Extra logic worlds (#378)

This commit is contained in:
IzzelAliz 2021-10-22 11:58:54 +08:00
parent 58740de7a5
commit 8c102f1eeb
No known key found for this signature in database
GPG Key ID: EE50E123A11D8338
24 changed files with 300 additions and 38 deletions

View File

@ -2,24 +2,43 @@ package io.izzel.arclight.common.mixin.bukkit;
import com.google.common.base.Function;
import io.izzel.arclight.common.bridge.core.entity.EntityBridge;
import io.izzel.arclight.common.bridge.core.world.WorldBridge;
import io.izzel.arclight.common.mod.ArclightMod;
import io.izzel.arclight.common.mod.util.ArclightCaptures;
import io.izzel.arclight.common.mod.util.DistValidate;
import net.minecraft.core.BlockPos;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.state.properties.NoteBlockInstrument;
import org.bukkit.Bukkit;
import org.bukkit.block.Block;
import org.bukkit.craftbukkit.v.block.CraftBlock;
import org.bukkit.craftbukkit.v.block.CraftBlockState;
import org.bukkit.craftbukkit.v.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v.event.CraftEventFactory;
import org.bukkit.craftbukkit.v.util.CraftMagicNumbers;
import org.bukkit.event.block.BlockFadeEvent;
import org.bukkit.event.block.BlockFormEvent;
import org.bukkit.event.block.BlockGrowEvent;
import org.bukkit.event.block.BlockPhysicsEvent;
import org.bukkit.event.block.BlockRedstoneEvent;
import org.bukkit.event.block.BlockSpreadEvent;
import org.bukkit.event.block.EntityBlockFormEvent;
import org.bukkit.event.block.NotePlayEvent;
import org.bukkit.event.entity.EntityChangeBlockEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
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.callback.CallbackInfoReturnable;
import javax.annotation.Nullable;
import java.util.Map;
import net.minecraft.core.BlockPos;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;
@Mixin(value = CraftEventFactory.class, remap = false)
public class CraftEventFactoryMixin {
@ -63,4 +82,154 @@ public class CraftEventFactoryMixin {
}
cir.setReturnValue(event);
}
/**
* @author IzzelAliz
* @reason
*/
@Overwrite
public static boolean handleBlockSpreadEvent(LevelAccessor world, BlockPos source, BlockPos target, net.minecraft.world.level.block.state.BlockState block, int flag) {
// Suppress during worldgen
if (!(world instanceof Level) || !DistValidate.isValid(world)) {
world.setBlock(target, block, flag);
return true;
}
CraftBlockState state = CraftBlockState.getBlockState(world, target, flag);
state.setData(block);
BlockSpreadEvent event = new BlockSpreadEvent(state.getBlock(), CraftBlock.at(world, source), state);
Bukkit.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
state.update(true);
}
return !event.isCancelled();
}
/**
* @author IzzelAliz
* @reason
*/
@Overwrite
public static boolean handleBlockGrowEvent(Level world, BlockPos pos, net.minecraft.world.level.block.state.BlockState newData, int flag) {
// Suppress during worldgen
if (!DistValidate.isValid(world)) {
world.setBlock(pos, newData, flag);
return true;
}
Block block = ((WorldBridge) world).bridge$getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ());
CraftBlockState state = (CraftBlockState) block.getState();
state.setData(newData);
BlockGrowEvent event = new BlockGrowEvent(block, state);
Bukkit.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
state.update(true);
}
return !event.isCancelled();
}
/**
* @author IzzelAliz
* @reason
*/
@Overwrite
public static boolean handleBlockFormEvent(Level world, BlockPos pos, net.minecraft.world.level.block.state.BlockState block, int flag, @Nullable Entity entity) {
// Suppress during worldgen
if (!DistValidate.isValid(world)) {
world.setBlock(pos, block, flag);
return true;
}
CraftBlockState blockState = CraftBlockState.getBlockState(world, pos, flag);
blockState.setData(block);
BlockFormEvent event = (entity == null) ? new BlockFormEvent(blockState.getBlock(), blockState) : new EntityBlockFormEvent(((EntityBridge) entity).bridge$getBukkitEntity(), blockState.getBlock(), blockState);
Bukkit.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
blockState.update(true);
}
return !event.isCancelled();
}
/**
* @author IzzelAliz
* @reason
*/
@Overwrite
public static BlockFadeEvent callBlockFadeEvent(LevelAccessor world, BlockPos pos, net.minecraft.world.level.block.state.BlockState newBlock) {
// Suppress during worldgen
if (!(world instanceof Level) || !DistValidate.isValid(world)) {
return new BlockFadeEvent(CraftBlock.at(world, pos), new CraftBlockState(CraftMagicNumbers.getMaterial(newBlock.getBlock())));
}
CraftBlockState state = CraftBlockState.getBlockState(world, pos);
state.setData(newBlock);
BlockFadeEvent event = new BlockFadeEvent(state.getBlock(), state);
Bukkit.getPluginManager().callEvent(event);
return event;
}
/**
* @author IzzelAliz
* @reason
*/
@Overwrite
public static BlockPhysicsEvent callBlockPhysicsEvent(LevelAccessor world, BlockPos blockposition) {
org.bukkit.block.Block block = CraftBlock.at(world, blockposition);
BlockPhysicsEvent event = new BlockPhysicsEvent(block, block.getBlockData());
// Suppress during worldgen
if (world instanceof Level && DistValidate.isValid(world)) {
Bukkit.getPluginManager().callEvent(event);
}
return event;
}
/**
* @author IzzelAliz
* @reason
*/
@Overwrite
public static EntityChangeBlockEvent callEntityChangeBlockEvent(Entity entity, BlockPos position, net.minecraft.world.level.block.state.BlockState newBlock, boolean cancelled) {
Block block = CraftBlock.at(entity.level, position);
EntityChangeBlockEvent event = new EntityChangeBlockEvent(((EntityBridge) entity).bridge$getBukkitEntity(), block, CraftBlockData.fromData(newBlock));
event.setCancelled(cancelled);
// Suppress during worldgen
if (DistValidate.isValid(entity.level)) {
Bukkit.getPluginManager().callEvent(event);
}
return event;
}
/**
* @author IzzelAliz
* @reason
*/
@Overwrite
public static BlockRedstoneEvent callRedstoneChange(Level world, BlockPos pos, int oldCurrent, int newCurrent) {
BlockRedstoneEvent event = new BlockRedstoneEvent(CraftBlock.at(world, pos), oldCurrent, newCurrent);
// Suppress during worldgen
if (DistValidate.isValid(world)) {
Bukkit.getPluginManager().callEvent(event);
}
return event;
}
/**
* @author IzzelAliz
* @reason
*/
@Overwrite
public static NotePlayEvent callNotePlayEvent(Level world, BlockPos pos, NoteBlockInstrument instrument, int note) {
NotePlayEvent event = new NotePlayEvent(CraftBlock.at(world, pos), org.bukkit.Instrument.getByType((byte) instrument.ordinal()), new org.bukkit.Note(note));
// Suppress during worldgen
if (DistValidate.isValid(world)) {
Bukkit.getPluginManager().callEvent(event);
}
return event;
}
}

View File

@ -1,5 +1,6 @@
package io.izzel.arclight.common.mixin.core.fluid;
import io.izzel.arclight.common.mod.util.DistValidate;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.BlockGetter;
@ -33,6 +34,7 @@ public abstract class FlowingFluidMixin {
@Inject(method = "spread", cancellable = true, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/material/FlowingFluid;spreadTo(Lnet/minecraft/world/level/LevelAccessor;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/Direction;Lnet/minecraft/world/level/material/FluidState;)V"))
public void arclight$flowInto(LevelAccessor worldIn, BlockPos pos, FluidState stateIn, CallbackInfo ci) {
if (!DistValidate.isValid(worldIn)) return;
Block source = CraftBlock.at(worldIn, pos);
BlockFromToEvent event = new BlockFromToEvent(source, BlockFace.DOWN);
Bukkit.getPluginManager().callEvent(event);
@ -44,6 +46,7 @@ public abstract class FlowingFluidMixin {
@Redirect(method = "spreadToSides", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/material/FlowingFluid;canSpreadTo(Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/Direction;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/material/FluidState;Lnet/minecraft/world/level/material/Fluid;)Z"))
public boolean arclight$flowInto(FlowingFluid flowingFluid, BlockGetter worldIn, BlockPos fromPos, BlockState fromBlockState, Direction direction, BlockPos toPos, BlockState toBlockState, FluidState toFluidState, Fluid fluidIn) {
if (this.canSpreadTo(worldIn, fromPos, fromBlockState, direction, toPos, toBlockState, toFluidState, fluidIn)) {
if (!DistValidate.isValid(worldIn)) return true;
Block source = CraftBlock.at(((Level) worldIn), fromPos);
BlockFromToEvent event = new BlockFromToEvent(source, CraftBlock.notchToBlockFace(direction));
Bukkit.getPluginManager().callEvent(event);
@ -55,6 +58,7 @@ public abstract class FlowingFluidMixin {
@Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;setBlock(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;I)Z"))
private boolean arclight$fluidLevelChange(Level world, BlockPos pos, BlockState newState, int flags) {
if (!DistValidate.isValid(world)) return world.setBlock(pos, newState, flags);
FluidLevelChangeEvent event = CraftEventFactory.callFluidLevelChangeEvent(world, pos, newState);
if (event.isCancelled()) {
return false;

View File

@ -1,6 +1,7 @@
package io.izzel.arclight.common.mixin.core.fluid;
import io.izzel.arclight.common.bridge.core.world.IWorldBridge;
import io.izzel.arclight.common.mod.util.DistValidate;
import io.izzel.arclight.mixin.Eject;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
@ -51,7 +52,7 @@ public abstract class LavaFluidMixin {
if (blockstate.isAir()) {
if (this.hasFlammableNeighbours(world, blockpos)) {
if (world.getBlockState(blockpos).getBlock() != Blocks.FIRE) {
if (CraftEventFactory.callBlockIgniteEvent(world, blockpos, pos).isCancelled()) {
if (DistValidate.isValid(world) && CraftEventFactory.callBlockIgniteEvent(world, blockpos, pos).isCancelled()) {
continue;
}
}
@ -72,7 +73,7 @@ public abstract class LavaFluidMixin {
if (world.isEmptyBlock(blockpos1.above()) && this.isFlammable(world, blockpos1, Direction.UP)) {
BlockPos up = blockpos1.above();
if (world.getBlockState(up).getBlock() != Blocks.FIRE) {
if (CraftEventFactory.callBlockIgniteEvent(world, up, pos).isCancelled()) {
if (DistValidate.isValid(world) && CraftEventFactory.callBlockIgniteEvent(world, up, pos).isCancelled()) {
continue;
}
}
@ -86,6 +87,7 @@ public abstract class LavaFluidMixin {
@Eject(method = "spreadTo", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/LevelAccessor;setBlock(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;I)Z"))
private boolean arclight$blockFromTo(LevelAccessor world, BlockPos pos, BlockState newState, int flags, CallbackInfo ci) {
if (!DistValidate.isValid(world)) return world.setBlock(pos, newState, flags);
if (!CraftEventFactory.handleBlockFormEvent(((IWorldBridge) world).bridge$getMinecraftWorld(), pos, newState, flags)) {
ci.cancel();
return false;

View File

@ -15,6 +15,7 @@ import io.izzel.arclight.common.mixin.core.world.level.LevelMixin;
import io.izzel.arclight.common.mod.server.world.WorldSymlink;
import io.izzel.arclight.common.mod.util.ArclightCaptures;
import io.izzel.arclight.common.mod.util.DelegateWorldInfo;
import io.izzel.arclight.common.mod.util.DistValidate;
import io.izzel.arclight.i18n.ArclightConfig;
import net.minecraft.core.BlockPos;
import net.minecraft.core.particles.ParticleOptions;
@ -34,6 +35,7 @@ import net.minecraft.world.entity.LightningBolt;
import net.minecraft.world.level.CustomSpawner;
import net.minecraft.world.level.Explosion;
import net.minecraft.world.level.ExplosionDamageCalculator;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity;
@ -113,7 +115,7 @@ public abstract class ServerLevelMixin extends LevelMixin implements ServerWorld
this.generator = gen;
this.environment = env;
this.biomeProvider = biomeProvider;
if (gen != null) {
if (gen != null && this.chunkSource != null) {
CustomChunkGenerator generator = new CustomChunkGenerator((ServerLevel) (Object) this, this.chunkSource.getGenerator(), gen);
((ServerChunkProviderBridge) this.chunkSource).bridge$setChunkGenerator(generator);
}
@ -122,21 +124,25 @@ public abstract class ServerLevelMixin extends LevelMixin implements ServerWorld
@Inject(method = "<init>(Lnet/minecraft/server/MinecraftServer;Ljava/util/concurrent/Executor;Lnet/minecraft/world/level/storage/LevelStorageSource$LevelStorageAccess;Lnet/minecraft/world/level/storage/ServerLevelData;Lnet/minecraft/resources/ResourceKey;Lnet/minecraft/world/level/dimension/DimensionType;Lnet/minecraft/server/level/progress/ChunkProgressListener;Lnet/minecraft/world/level/chunk/ChunkGenerator;ZJLjava/util/List;Z)V", at = @At("RETURN"))
private void arclight$init(MinecraftServer minecraftServer, Executor backgroundExecutor, LevelStorageSource.LevelStorageAccess levelSave, ServerLevelData worldInfo, ResourceKey<net.minecraft.world.level.Level> dimension, DimensionType dimensionType, ChunkProgressListener statusListener, ChunkGenerator chunkGenerator, boolean isDebug, long seed, List<CustomSpawner> specialSpawners, boolean shouldBeTicking, CallbackInfo ci) {
this.pvpMode = minecraftServer.isPvpAllowed();
this.pvpMode = minecraftServer != null && minecraftServer.isPvpAllowed();
this.convertable = levelSave;
this.uuid = WorldUUID.getUUID(levelSave.getDimensionPath(this.dimension()));
this.uuid = levelSave != null ? WorldUUID.getUUID(levelSave.getDimensionPath(this.dimension())) : UUID.randomUUID();
if (worldInfo instanceof PrimaryLevelData) {
this.$$worldDataServer = (PrimaryLevelData) worldInfo;
} else if (worldInfo instanceof DerivedLevelData) {
// damn spigot again
this.$$worldDataServer = DelegateWorldInfo.wrap(((DerivedLevelData) worldInfo));
((DerivedWorldInfoBridge) worldInfo).bridge$setDimType(this.getTypeKey());
if (ArclightConfig.spec().getCompat().isSymlinkWorld()) {
if (levelSave != null && ArclightConfig.spec().getCompat().isSymlinkWorld()) {
WorldSymlink.create((DerivedLevelData) worldInfo, levelSave.getDimensionPath(this.dimension()));
}
}
((ServerChunkProviderBridge) this.chunkSource).bridge$setViewDistance(spigotConfig.viewDistance);
((WorldInfoBridge) this.$$worldDataServer).bridge$setWorld((ServerLevel) (Object) this);
if (this.chunkSource != null) {
((ServerChunkProviderBridge) this.chunkSource).bridge$setViewDistance(spigotConfig.viewDistance);
}
if (this.$$worldDataServer != null) {
((WorldInfoBridge) this.$$worldDataServer).bridge$setWorld((ServerLevel) (Object) this);
}
}
public LevelChunk getChunkIfLoaded(int x, int z) {
@ -190,9 +196,11 @@ public abstract class ServerLevelMixin extends LevelMixin implements ServerWorld
cause = arclight$cause;
arclight$cause = null;
}
LightningStrikeEvent lightning = CraftEventFactory.callLightningStrikeEvent((LightningStrike) ((EntityBridge) entity).bridge$getBukkitEntity(), cause);
if (lightning.isCancelled()) {
return false;
if (DistValidate.isValid((LevelAccessor) this)) {
LightningStrikeEvent lightning = CraftEventFactory.callLightningStrikeEvent((LightningStrike) ((EntityBridge) entity).bridge$getBukkitEntity(), cause);
if (lightning.isCancelled()) {
return false;
}
}
return this.addFreshEntity(entity);
}
@ -204,7 +212,9 @@ public abstract class ServerLevelMixin extends LevelMixin implements ServerWorld
@Inject(method = "save", at = @At(value = "JUMP", ordinal = 0, opcode = Opcodes.IFNULL))
private void arclight$worldSaveEvent(ProgressListener progress, boolean flush, boolean skipSave, CallbackInfo ci) {
Bukkit.getPluginManager().callEvent(new WorldSaveEvent(bridge$getWorld()));
if (DistValidate.isValid((LevelAccessor) this)) {
Bukkit.getPluginManager().callEvent(new WorldSaveEvent(bridge$getWorld()));
}
}
@Inject(method = "save", at = @At("RETURN"))
@ -264,7 +274,7 @@ public abstract class ServerLevelMixin extends LevelMixin implements ServerWorld
private void arclight$addEntityEvent(Entity entityIn, CallbackInfoReturnable<Boolean> cir) {
CreatureSpawnEvent.SpawnReason reason = arclight$reason == null ? CreatureSpawnEvent.SpawnReason.DEFAULT : arclight$reason;
arclight$reason = null;
if (!CraftEventFactory.doEntityAddEventCalling((ServerLevel) (Object) this, entityIn, reason)) {
if (DistValidate.isValid((LevelAccessor) this) && !CraftEventFactory.doEntityAddEventCalling((ServerLevel) (Object) this, entityIn, reason)) {
cir.setReturnValue(false);
}
}
@ -406,6 +416,11 @@ public abstract class ServerLevelMixin extends LevelMixin implements ServerWorld
BlockPos.betweenClosed(i - 2, j, k - 2, i + 2, j, k + 2).forEach((pos) -> {
blockList.setBlock(pos, Blocks.OBSIDIAN.defaultBlockState(), 3);
});
if (!DistValidate.isValid(world)) {
blockList.updateList();
ArclightCaptures.getEndPortalEntity();
return;
}
CraftWorld bworld = ((WorldBridge) world).bridge$getWorld();
boolean spawnPortal = ArclightCaptures.getEndPortalSpawn();
Entity entity = ArclightCaptures.getEndPortalEntity();

View File

@ -1,5 +1,6 @@
package io.izzel.arclight.common.mixin.core.world.item;
import io.izzel.arclight.common.mod.util.DistValidate;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.decoration.ArmorStand;
import net.minecraft.world.item.ArmorStandItem;
@ -24,7 +25,7 @@ public class ArmorStandItemMixin {
@Inject(method = "useOn", cancellable = true, at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerLevel;addFreshEntityWithPassengers(Lnet/minecraft/world/entity/Entity;)V"))
public void arclight$entityPlace(UseOnContext context, CallbackInfoReturnable<InteractionResult> cir) {
if (CraftEventFactory.callEntityPlaceEvent(context, arclight$entity).isCancelled()) {
if (DistValidate.isValid(context) && CraftEventFactory.callEntityPlaceEvent(context, arclight$entity).isCancelled()) {
cir.setReturnValue(InteractionResult.FAIL);
}
arclight$entity = null;

View File

@ -1,6 +1,7 @@
package io.izzel.arclight.common.mixin.core.world.item;
import io.izzel.arclight.common.bridge.core.entity.player.ServerPlayerEntityBridge;
import io.izzel.arclight.common.mod.util.DistValidate;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerLevel;
@ -52,7 +53,7 @@ public abstract class BlockItemMixin {
org.bukkit.block.BlockState state = arclight$state;
arclight$state = null;
BlockPos pos = context1.getClickedPos();
if (state != null) {
if (state != null && DistValidate.isValid(context)) {
org.bukkit.event.block.BlockPlaceEvent placeEvent = CraftEventFactory.callBlockPlaceEvent((ServerLevel) context1.getLevel(), context1.getPlayer(), context1.getHand(), state, pos.getX(), pos.getY(), pos.getZ());
if (placeEvent != null && (placeEvent.isCancelled() || !placeEvent.canBuild())) {
state.update(true, false);
@ -90,7 +91,7 @@ public abstract class BlockItemMixin {
Player player = (context.getPlayer() instanceof ServerPlayerEntityBridge) ? ((ServerPlayerEntityBridge) context.getPlayer()).bridge$getBukkitEntity() : null;
BlockCanBuildEvent event = new BlockCanBuildEvent(CraftBlock.at(context.getLevel(), context.getClickedPos()), player, CraftBlockData.fromData(state), original);
Bukkit.getPluginManager().callEvent(event);
if (DistValidate.isValid(context)) Bukkit.getPluginManager().callEvent(event);
return event.isBuildable();
}
}

View File

@ -1,5 +1,6 @@
package io.izzel.arclight.common.mixin.core.world.item;
import io.izzel.arclight.common.mod.util.DistValidate;
import net.minecraft.stats.Stats;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
@ -66,10 +67,12 @@ public class BoatItemMixin extends Item {
}
if (result.getType() == HitResult.Type.BLOCK) {
PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(playerIn, Action.RIGHT_CLICK_BLOCK, result.getBlockPos(), result.getDirection(), itemstack, handIn);
if (DistValidate.isValid(worldIn)) {
PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(playerIn, Action.RIGHT_CLICK_BLOCK, result.getBlockPos(), result.getDirection(), itemstack, handIn);
if (event.isCancelled()) {
return new InteractionResultHolder<>(InteractionResult.PASS, itemstack);
if (event.isCancelled()) {
return new InteractionResultHolder<>(InteractionResult.PASS, itemstack);
}
}
Boat boatentity = new Boat(worldIn, result.getLocation().x, result.getLocation().y, result.getLocation().z);
@ -79,7 +82,7 @@ public class BoatItemMixin extends Item {
return new InteractionResultHolder<>(InteractionResult.FAIL, itemstack);
} else {
if (!worldIn.isClientSide) {
if (CraftEventFactory.callEntityPlaceEvent(worldIn, result.getBlockPos(), result.getDirection(), playerIn, boatentity).isCancelled()) {
if (DistValidate.isValid(worldIn) && CraftEventFactory.callEntityPlaceEvent(worldIn, result.getBlockPos(), result.getDirection(), playerIn, boatentity).isCancelled()) {
return new InteractionResultHolder<>(InteractionResult.FAIL, itemstack);
}
if (!worldIn.addFreshEntity(boatentity)) {

View File

@ -1,6 +1,7 @@
package io.izzel.arclight.common.mixin.core.world.item;
import io.izzel.arclight.common.bridge.core.entity.player.ServerPlayerEntityBridge;
import io.izzel.arclight.common.mod.util.DistValidate;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket;
@ -39,7 +40,8 @@ public abstract class BucketItemMixin {
@Inject(method = "use", cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/BucketPickup;pickupBlock(Lnet/minecraft/world/level/LevelAccessor;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;)Lnet/minecraft/world/item/ItemStack;"))
private void arclight$bucketFill(Level worldIn, Player playerIn, InteractionHand handIn, CallbackInfoReturnable<InteractionResultHolder<ItemStack>> cir, ItemStack stack, BlockHitResult result) {
BlockPos pos = ((BlockHitResult) result).getBlockPos();
if (!DistValidate.isValid(worldIn)) return;
BlockPos pos = result.getBlockPos();
BlockState state = worldIn.getBlockState(pos);
ItemStack dummyFluid = ((BucketPickup) state.getBlock()).pickupBlock(DummyGeneratorAccess.INSTANCE, pos, state);
PlayerBucketFillEvent event = CraftEventFactory.callPlayerBucketFillEvent((ServerLevel) worldIn, playerIn, pos, pos, result.getDirection(), stack, dummyFluid.getItem());
@ -93,6 +95,7 @@ public abstract class BucketItemMixin {
@Inject(method = "emptyContents", cancellable = true, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/dimension/DimensionType;ultraWarm()Z"))
private void arclight$bucketEmpty(Player player, Level worldIn, BlockPos posIn, BlockHitResult rayTrace, CallbackInfoReturnable<Boolean> cir) {
if (!DistValidate.isValid(worldIn)) return;
if (player != null) {
PlayerBucketEmptyEvent event = CraftEventFactory.callPlayerBucketEmptyEvent((ServerLevel) worldIn, player, posIn, arclight$click, arclight$direction, arclight$stack);
if (event.isCancelled()) {

View File

@ -1,6 +1,7 @@
package io.izzel.arclight.common.mixin.core.world.item;
import io.izzel.arclight.common.bridge.core.entity.player.ServerPlayerEntityBridge;
import io.izzel.arclight.common.mod.util.DistValidate;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
@ -44,7 +45,7 @@ public class ChorusFruitItemMixin extends Item {
double d4 = Mth.clamp(entityLiving.getY() + (double) (entityLiving.getRandom().nextInt(16) - 8), 0.0D, worldIn.getHeight() - 1);
double d5 = entityLiving.getZ() + (entityLiving.getRandom().nextDouble() - 0.5D) * 16.0D;
if (entityLiving instanceof ServerPlayer) {
if (entityLiving instanceof ServerPlayer && DistValidate.isValid(worldIn)) {
Player player = ((ServerPlayerEntityBridge) entityLiving).bridge$getBukkitEntity();
PlayerTeleportEvent event = new PlayerTeleportEvent(player, player.getLocation(), new Location(player.getWorld(), d3, d4, d5), PlayerTeleportEvent.TeleportCause.CHORUS_FRUIT);
Bukkit.getPluginManager().callEvent(event);

View File

@ -2,6 +2,7 @@ package io.izzel.arclight.common.mixin.core.world.item;
import io.izzel.arclight.common.bridge.core.entity.EntityBridge;
import io.izzel.arclight.common.bridge.core.entity.player.ServerPlayerEntityBridge;
import io.izzel.arclight.common.mod.util.DistValidate;
import io.izzel.arclight.mixin.Eject;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
@ -25,6 +26,10 @@ public class CrossbowItemMixin {
@Inject(method = "shootProjectile", cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;hurtAndBreak(ILnet/minecraft/world/entity/LivingEntity;Ljava/util/function/Consumer;)V"))
private static void arclight$entityShoot(Level worldIn, LivingEntity shooter, InteractionHand handIn, ItemStack crossbow, ItemStack projectile, float soundPitch, boolean isCreativeMode, float velocity, float inaccuracy, float projectileAngle, CallbackInfo ci,
boolean flag, Projectile proj) {
if (!DistValidate.isValid(worldIn)) {
arclight$capturedBoolean = true;
return;
}
EntityShootBowEvent event = CraftEventFactory.callEntityShootBowEvent(shooter, crossbow, projectile, proj, shooter.getUsedItemHand(), soundPitch, true);
if (event.isCancelled()) {
event.getProjectile().remove();

View File

@ -1,5 +1,6 @@
package io.izzel.arclight.common.mixin.core.world.item;
import io.izzel.arclight.common.mod.util.DistValidate;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.boss.enderdragon.EndCrystal;
import net.minecraft.world.item.EndCrystalItem;
@ -24,7 +25,7 @@ public class EnderCrystalItemMixin {
@Inject(method = "useOn", cancellable = true, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;addFreshEntity(Lnet/minecraft/world/entity/Entity;)Z"))
public void arclight$entityPlace(UseOnContext context, CallbackInfoReturnable<InteractionResult> cir) {
if (CraftEventFactory.callEntityPlaceEvent(context, arclight$enderCrystalEntity).isCancelled()) {
if (DistValidate.isValid(context) && CraftEventFactory.callEntityPlaceEvent(context, arclight$enderCrystalEntity).isCancelled()) {
cir.setReturnValue(InteractionResult.FAIL);
}
arclight$enderCrystalEntity = null;

View File

@ -1,5 +1,6 @@
package io.izzel.arclight.common.mixin.core.world.item;
import io.izzel.arclight.common.mod.util.DistValidate;
import net.minecraft.core.BlockPos;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.item.FireChargeItem;
@ -19,7 +20,7 @@ public class FireChargeItemMixin {
@Inject(method = "useOn", cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD,
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/FireChargeItem;playSound(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;)V"))
public void arclight$blockIgnite(UseOnContext context, CallbackInfoReturnable<InteractionResult> cir, Level world, BlockPos blockPos) {
if (CraftEventFactory.callBlockIgniteEvent(world, blockPos, BlockIgniteEvent.IgniteCause.FIREBALL, context.getPlayer()).isCancelled()) {
if (DistValidate.isValid(context) && CraftEventFactory.callBlockIgniteEvent(world, blockPos, BlockIgniteEvent.IgniteCause.FIREBALL, context.getPlayer()).isCancelled()) {
if (!context.getPlayer().getAbilities().instabuild) {
context.getItemInHand().shrink(1);
}

View File

@ -2,6 +2,7 @@ package io.izzel.arclight.common.mixin.core.world.item;
import io.izzel.arclight.common.bridge.core.entity.EntityBridge;
import io.izzel.arclight.common.bridge.core.entity.player.ServerPlayerEntityBridge;
import io.izzel.arclight.common.mod.util.DistValidate;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.stats.Stats;
@ -51,12 +52,14 @@ public class FishingRodItemMixin extends Item {
int j = EnchantmentHelper.getFishingLuckBonus(itemstack);
FishingHook hook = new FishingHook(playerIn, worldIn, j, k);
PlayerFishEvent playerFishEvent = new PlayerFishEvent(((ServerPlayerEntityBridge) playerIn).bridge$getBukkitEntity(), null, (FishHook) ((EntityBridge) hook).bridge$getBukkitEntity(), PlayerFishEvent.State.FISHING);
Bukkit.getPluginManager().callEvent(playerFishEvent);
if (DistValidate.isValid(worldIn)) {
PlayerFishEvent playerFishEvent = new PlayerFishEvent(((ServerPlayerEntityBridge) playerIn).bridge$getBukkitEntity(), null, (FishHook) ((EntityBridge) hook).bridge$getBukkitEntity(), PlayerFishEvent.State.FISHING);
Bukkit.getPluginManager().callEvent(playerFishEvent);
if (playerFishEvent.isCancelled()) {
playerIn.fishing = null;
return new InteractionResultHolder<>(InteractionResult.PASS, itemstack);
if (playerFishEvent.isCancelled()) {
playerIn.fishing = null;
return new InteractionResultHolder<>(InteractionResult.PASS, itemstack);
}
}
worldIn.playSound(null, playerIn.getX(), playerIn.getY(), playerIn.getZ(), SoundEvents.FISHING_BOBBER_THROW, SoundSource.NEUTRAL, 0.5F, 0.4F / (worldIn.getRandom().nextFloat() * 0.4F + 0.8F));
worldIn.addFreshEntity(new FishingHook(playerIn, worldIn, j, k));

View File

@ -1,5 +1,6 @@
package io.izzel.arclight.common.mixin.core.world.item;
import io.izzel.arclight.common.mod.util.DistValidate;
import net.minecraft.core.BlockPos;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
@ -18,6 +19,7 @@ public class FlintAndSteelItemMixin {
@Inject(method = "useOn", cancellable = true, at = @At(value = "INVOKE", ordinal = 0, target = "Lnet/minecraft/world/level/Level;playSound(Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/core/BlockPos;Lnet/minecraft/sounds/SoundEvent;Lnet/minecraft/sounds/SoundSource;FF)V"))
public void arclight$blockIgnite(UseOnContext context, CallbackInfoReturnable<InteractionResult> cir) {
if (!DistValidate.isValid(context)) return;
Player playerentity = context.getPlayer();
Level world = context.getLevel();
BlockPos blockpos = context.getClickedPos();

View File

@ -2,6 +2,7 @@ package io.izzel.arclight.common.mixin.core.world.item;
import io.izzel.arclight.common.bridge.core.entity.EntityBridge;
import io.izzel.arclight.common.bridge.core.entity.player.PlayerEntityBridge;
import io.izzel.arclight.common.mod.util.DistValidate;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.InteractionResult;
@ -30,6 +31,7 @@ public class HangingEntityItemMixin {
@Inject(method = "useOn", cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD,
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/decoration/HangingEntity;playPlacementSound()V"))
public void arclight$hangingPlace(UseOnContext context, CallbackInfoReturnable<InteractionResult> cir, BlockPos blockPos, Direction direction, BlockPos blockPos1, net.minecraft.world.entity.player.Player playerEntity, ItemStack itemStack, Level world, HangingEntity hangingEntity) {
if (!DistValidate.isValid(context)) return;
Player who = (context.getPlayer() == null) ? null : (Player) ((PlayerEntityBridge) context.getPlayer()).bridge$getBukkitEntity();
Block blockClicked = CraftBlock.at(world, blockPos);
BlockFace blockFace = CraftBlock.notchToBlockFace(direction);

View File

@ -1,5 +1,6 @@
package io.izzel.arclight.common.mixin.core.world.item;
import io.izzel.arclight.common.mod.util.DistValidate;
import io.izzel.arclight.mixin.Eject;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.Entity;
@ -16,7 +17,7 @@ public class MinecartItemMixin {
@Eject(method = "useOn", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;addFreshEntity(Lnet/minecraft/world/entity/Entity;)Z"))
private boolean arclight$entityPlace(Level world, Entity entityIn, CallbackInfoReturnable<InteractionResult> cir, UseOnContext context) {
if (CraftEventFactory.callEntityPlaceEvent(context, entityIn).isCancelled()) {
if (DistValidate.isValid(world) && CraftEventFactory.callEntityPlaceEvent(context, entityIn).isCancelled()) {
cir.setReturnValue(InteractionResult.FAIL);
return false;
} else if (!world.addFreshEntity(entityIn)) {

View File

@ -2,6 +2,7 @@ package io.izzel.arclight.common.mixin.core.world.item;
import io.izzel.arclight.common.bridge.core.entity.player.ServerPlayerEntityBridge;
import io.izzel.arclight.common.bridge.core.entity.projectile.TridentEntityBridge;
import io.izzel.arclight.common.mod.util.DistValidate;
import io.izzel.arclight.mixin.Eject;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
@ -47,6 +48,7 @@ public class TridentItemMixin {
@Inject(method = "releaseUsing", at = @At(value = "INVOKE", ordinal = 1, target = "Lnet/minecraft/world/entity/player/Player;getYRot()F"))
public void arclight$riptide(ItemStack stack, Level worldIn, LivingEntity entityLiving, int timeLeft, CallbackInfo ci) {
if (!DistValidate.isValid(worldIn)) return;
PlayerRiptideEvent event = new PlayerRiptideEvent(((ServerPlayerEntityBridge) entityLiving).bridge$getBukkitEntity(), CraftItemStack.asCraftMirror(stack));
Bukkit.getPluginManager().callEvent(event);
}

View File

@ -1,5 +1,6 @@
package io.izzel.arclight.common.mixin.core.world.level.block;
import io.izzel.arclight.common.mod.util.DistValidate;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level;
@ -29,7 +30,7 @@ public abstract class BasePressurePlateBlockMixin {
boolean flag = oldRedstoneStrength > 0;
boolean flag1 = newStrength > 0;
if (flag != flag1) {
if (flag != flag1 && DistValidate.isValid(world)) {
BlockRedstoneEvent event = new BlockRedstoneEvent(CraftBlock.at(worldIn, blockPos), oldRedstoneStrength, newStrength);
Bukkit.getPluginManager().callEvent(event);
newStrength = event.getNewCurrent();

View File

@ -3,6 +3,7 @@ package io.izzel.arclight.common.mixin.core.world.level.block;
import io.izzel.arclight.common.bridge.core.block.BlockBridge;
import io.izzel.arclight.common.mixin.core.world.level.block.state.BlockBehaviourMixin;
import io.izzel.arclight.common.mod.util.ArclightCaptures;
import io.izzel.arclight.common.mod.util.DistValidate;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
@ -78,7 +79,8 @@ public abstract class BlockMixin extends BlockBehaviourMixin implements BlockBri
List<ItemEntity> blockDrops = ArclightCaptures.getBlockDrops();
org.bukkit.block.BlockState state = ArclightCaptures.getBlockBreakPlayerState();
BlockBreakEvent breakEvent = ArclightCaptures.resetBlockBreakPlayer();
if (player instanceof ServerPlayer && blockDrops != null && (breakEvent == null || breakEvent.isDropItems())) {
if (player instanceof ServerPlayer && blockDrops != null && (breakEvent == null || breakEvent.isDropItems())
&& DistValidate.isValid(worldIn)) {
CraftBlock craftBlock = CraftBlock.at(((CraftWorld) state.getWorld()).getHandle(), pos);
CraftEventFactory.handleBlockDropItemEvent(craftBlock, state, ((ServerPlayer) player), blockDrops);
}

View File

@ -2,6 +2,7 @@ package io.izzel.arclight.common.mod.server.event;
import io.izzel.arclight.common.bridge.core.entity.EntityBridge;
import io.izzel.arclight.common.bridge.core.entity.player.ServerPlayerEntityBridge;
import io.izzel.arclight.common.mod.util.DistValidate;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.block.Blocks;
@ -20,7 +21,7 @@ public class BlockBreakEventDispatcher {
@SubscribeEvent(receiveCanceled = true)
public void onBreakBlock(BlockEvent.BreakEvent event) {
if (!event.getWorld().isClientSide()) {
if (DistValidate.isValid(event.getWorld())) {
CraftBlock craftBlock = CraftBlock.at(event.getWorld(), event.getPos());
BlockBreakEvent breakEvent = new BlockBreakEvent(craftBlock, ((ServerPlayerEntityBridge) event.getPlayer()).bridge$getBukkitEntity());
ArclightCaptures.captureBlockBreakPlayer(breakEvent);
@ -34,6 +35,7 @@ public class BlockBreakEventDispatcher {
@SubscribeEvent
public void onFarmlandBreak(BlockEvent.FarmlandTrampleEvent event) {
if (!DistValidate.isValid(event.getWorld())) return;
Entity entity = event.getEntity();
Cancellable cancellable;
if (entity instanceof Player) {

View File

@ -3,6 +3,7 @@ package io.izzel.arclight.common.mod.server.event;
import io.izzel.arclight.common.bridge.core.entity.player.ServerPlayerEntityBridge;
import io.izzel.arclight.common.mod.util.ArclightBlockSnapshot;
import io.izzel.arclight.common.mod.util.ArclightCaptures;
import io.izzel.arclight.common.mod.util.DistValidate;
import net.minecraft.core.Direction;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.Entity;
@ -29,7 +30,7 @@ public class BlockPlaceEventDispatcher {
if (entity instanceof ServerPlayerEntityBridge playerEntity) {
Player player = playerEntity.bridge$getBukkitEntity();
Direction direction = ArclightCaptures.getPlaceEventDirection();
if (direction != null) {
if (direction != null && DistValidate.isValid(event.getWorld())) {
InteractionHand hand = ArclightCaptures.getPlaceEventHand(InteractionHand.MAIN_HAND);
CraftBlock placedBlock = ArclightBlockSnapshot.fromBlockSnapshot(event.getBlockSnapshot(), true);
CraftBlock againstBlock = CraftBlock.at(event.getWorld(), event.getPos().relative(direction.getOpposite()));
@ -64,7 +65,7 @@ public class BlockPlaceEventDispatcher {
if (entity instanceof ServerPlayerEntityBridge playerEntity) {
Player player = playerEntity.bridge$getBukkitEntity();
Direction direction = ArclightCaptures.getPlaceEventDirection();
if (direction != null) {
if (direction != null && DistValidate.isValid(event.getWorld())) {
InteractionHand hand = ArclightCaptures.getPlaceEventHand(InteractionHand.MAIN_HAND);
List<BlockState> placedBlocks = new ArrayList<>(event.getReplacedBlockSnapshots().size());
for (BlockSnapshot snapshot : event.getReplacedBlockSnapshots()) {

View File

@ -0,0 +1,31 @@
package io.izzel.arclight.common.mod.util;
import io.izzel.arclight.i18n.ArclightConfig;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.LevelAccessor;
public class DistValidate {
public static boolean isValid(UseOnContext context) {
return context != null && isValid(context.getLevel());
}
public static boolean isValid(LevelAccessor level) {
return level != null
&& !level.isClientSide()
&& isLogicWorld(level);
}
public static boolean isValid(BlockGetter getter) {
return getter instanceof LevelAccessor level && isValid(level);
}
private static boolean isLogicWorld(LevelAccessor level) {
var cl = level.getClass();
return cl == ServerLevel.class || cl == WorldGenRegion.class
|| ArclightConfig.spec().getCompat().getExtraLogicWorlds().contains(cl.getName());
}
}

View File

@ -5,6 +5,7 @@ import ninja.leaping.configurate.objectmapping.serialize.ConfigSerializable;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
@ConfigSerializable
public class CompatSpec {
@ -19,6 +20,9 @@ public class CompatSpec {
@Setting("symlink-world")
private boolean symlinkWorld;
@Setting("extra-logic-worlds")
private Set<String> extraLogicWorlds;
public Map<String, MaterialPropertySpec> getMaterials() {
return materials;
}
@ -38,4 +42,8 @@ public class CompatSpec {
public boolean isSymlinkWorld() {
return symlinkWorld;
}
public Set<String> getExtraLogicWorlds() {
return extraLogicWorlds;
}
}

View File

@ -14,6 +14,7 @@ compatibility {
entity-property-overrides {
}
symlink-world = false
extra-logic-worlds = []
}
async-catcher {
dump = true