Skip to content

Commit

Permalink
Add NeoForge support
Browse files Browse the repository at this point in the history
Co-authored-by: 秋雨落 <[email protected]>
  • Loading branch information
IzzelAliz and qyl27 committed Feb 14, 2024
1 parent c524379 commit 0a711ca
Show file tree
Hide file tree
Showing 49 changed files with 1,173 additions and 201 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.izzel.arclight.common.bridge.core.util;

import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;

public interface DamageSourceBridge {

Expand All @@ -11,4 +12,16 @@ public interface DamageSourceBridge {
DamageSource bridge$poison();

DamageSource bridge$melting();

Entity bridge$getCausingEntity();

DamageSource bridge$customCausingEntity(Entity entity);

DamageSource bridge$setCustomCausingEntity(Entity entity);

org.bukkit.block.Block bridge$directBlock();

DamageSource bridge$directBlock(org.bukkit.block.Block block);

DamageSource bridge$setDirectBlock(org.bukkit.block.Block block);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
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.bridge.core.util.DamageSourceBridge;
import io.izzel.arclight.common.mod.util.ArclightCaptures;
import io.izzel.arclight.common.mod.util.DistValidate;
import net.minecraft.core.BlockPos;
Expand All @@ -19,17 +18,11 @@
import org.bukkit.craftbukkit.v.block.CraftBlockState;
import org.bukkit.craftbukkit.v.block.CraftBlockStates;
import org.bukkit.craftbukkit.v.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v.damage.CraftDamageSource;
import org.bukkit.craftbukkit.v.event.CraftEventFactory;
import org.bukkit.craftbukkit.v.util.CraftMagicNumbers;
import org.bukkit.entity.Item;
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.block.*;
import org.bukkit.event.entity.EntityChangeBlockEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
Expand All @@ -39,51 +32,43 @@
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.ModifyVariable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import javax.annotation.Nullable;
import java.util.Map;

@Mixin(value = CraftEventFactory.class, remap = false)
public class CraftEventFactoryMixin {
public abstract class CraftEventFactoryMixin {

@Shadow public static Entity entityDamage;
@Shadow public static Block blockDamage;
// @formatter:off
@Shadow private static EntityDamageEvent callEntityDamageEvent(Entity damager, Entity damagee, EntityDamageEvent.DamageCause cause, org.bukkit.damage.DamageSource bukkitDamageSource, Map<EntityDamageEvent.DamageModifier, Double> modifiers, Map<EntityDamageEvent.DamageModifier, Function<? super Double, Double>> modifierFunctions, boolean cancelled) { return null; }
// @formatter:on

@Inject(method = "handleEntityDamageEvent(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/damagesource/DamageSource;Ljava/util/Map;Ljava/util/Map;Z)Lorg/bukkit/event/entity/EntityDamageEvent;", at = @At("HEAD"))
private static void arclight$captureSource(Entity entity, DamageSource source, Map<EntityDamageEvent.DamageModifier, Double> modifiers, Map<EntityDamageEvent.DamageModifier, Function<? super Double, Double>> modifierFunctions, boolean cancelled, CallbackInfoReturnable<EntityDamageEvent> cir) {
@ModifyVariable(method = "handleEntityDamageEvent(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/damagesource/DamageSource;Ljava/util/Map;Ljava/util/Map;Z)Lorg/bukkit/event/entity/EntityDamageEvent;", at = @At("HEAD"), index = 1, argsOnly = true)
private static DamageSource arclight$captureSource(DamageSource source, Entity entity) {
Entity damageEventEntity = ArclightCaptures.getDamageEventEntity();
BlockPos damageEventBlock = ArclightCaptures.getDamageEventBlock();
if (damageEventEntity != null && entityDamage == null) {
if (damageEventEntity != null && ((DamageSourceBridge) source).bridge$getCausingEntity() == null) {
if (source.is(DamageTypes.LIGHTNING_BOLT)) {
entityDamage = damageEventEntity;
source = ((DamageSourceBridge) source).bridge$customCausingEntity(damageEventEntity);
}
}
if (damageEventBlock != null && blockDamage == null) {
if (damageEventBlock != null && ((DamageSourceBridge) source).bridge$directBlock() == null) {
if (source.is(DamageTypes.CACTUS)
|| source.is(DamageTypes.SWEET_BERRY_BUSH)
|| source.is(DamageTypes.HOT_FLOOR)) {
blockDamage = CraftBlock.at(entity.getCommandSenderWorld(), damageEventBlock);
|| source.is(DamageTypes.SWEET_BERRY_BUSH)
|| source.is(DamageTypes.HOT_FLOOR)) {
source = ((DamageSourceBridge) source).bridge$directBlock(CraftBlock.at(entity.getCommandSenderWorld(), damageEventBlock));
}
}
return source;
}

@Inject(method = "handleEntityDamageEvent(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/damagesource/DamageSource;Ljava/util/Map;Ljava/util/Map;Z)Lorg/bukkit/event/entity/EntityDamageEvent;", cancellable = true, at = @At(value = "NEW", target = "java/lang/IllegalStateException"))
private static void arclight$unhandledDamage(Entity entity, DamageSource source, Map<EntityDamageEvent.DamageModifier, Double> modifiers, Map<EntityDamageEvent.DamageModifier, Function<? super Double, Double>> modifierFunctions, boolean cancelled, CallbackInfoReturnable<EntityDamageEvent> cir) {
// todo blockDamage is lost
EntityDamageEvent event;
if (source.getEntity() != null) {
// ArclightMod.LOGGER.debug("Unhandled damage of {} by {} from {}", entity, source.getEntity(), source.msgId);
event = new EntityDamageByEntityEvent(((EntityBridge) source.getEntity()).bridge$getBukkitEntity(), ((EntityBridge) entity).bridge$getBukkitEntity(), EntityDamageEvent.DamageCause.CUSTOM, modifiers, modifierFunctions);
} else {
// ArclightMod.LOGGER.debug("Unhandled damage of {} from {}", entity, source.msgId);
event = new EntityDamageEvent(((EntityBridge) entity).bridge$getBukkitEntity(), EntityDamageEvent.DamageCause.CUSTOM, modifiers, modifierFunctions);
}
event.setCancelled(cancelled);
Bukkit.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
((EntityBridge) entity).bridge$getBukkitEntity().setLastDamageCause(event);
}
CraftDamageSource bukkitDamageSource = new CraftDamageSource(source);
EntityDamageEvent event = callEntityDamageEvent(((DamageSourceBridge) source).bridge$getCausingEntity(), entity, EntityDamageEvent.DamageCause.CUSTOM, bukkitDamageSource, modifiers, modifierFunctions, cancelled);
cir.setReturnValue(event);
}

Expand Down Expand Up @@ -122,7 +107,7 @@ public static boolean handleBlockGrowEvent(Level world, BlockPos pos, net.minecr
world.setBlock(pos, newData, flag);
return true;
}
Block block = ((WorldBridge) world).bridge$getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ());
Block block = world.bridge$getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ());
CraftBlockState state = (CraftBlockState) block.getState();
state.setData(newData);

Expand Down Expand Up @@ -150,7 +135,7 @@ public static boolean handleBlockFormEvent(Level world, BlockPos pos, net.minecr
CraftBlockState blockState = CraftBlockStates.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);
BlockFormEvent event = (entity == null) ? new BlockFormEvent(blockState.getBlock(), blockState) : new EntityBlockFormEvent(entity.bridge$getBukkitEntity(), blockState.getBlock(), blockState);
Bukkit.getPluginManager().callEvent(event);

if (!event.isCancelled()) {
Expand Down Expand Up @@ -200,7 +185,7 @@ public static BlockPhysicsEvent callBlockPhysicsEvent(LevelAccessor world, Block
@Overwrite
public static boolean 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));
EntityChangeBlockEvent event = new EntityChangeBlockEvent(entity.bridge$getBukkitEntity(), block, CraftBlockData.fromData(newBlock));
event.setCancelled(cancelled);
// Suppress during worldgen
if (DistValidate.isValid(entity.level())) {
Expand Down Expand Up @@ -240,7 +225,7 @@ public static NotePlayEvent callNotePlayEvent(Level world, BlockPos pos, NoteBlo
@Inject(method = "callItemSpawnEvent", cancellable = true, at = @At("HEAD"))
private static void arclight$noAirDrops(ItemEntity itemEntity, CallbackInfoReturnable<ItemSpawnEvent> cir) {
if (itemEntity.getItem().isEmpty()) {
Item entity = (Item) ((EntityBridge) itemEntity).bridge$getBukkitEntity();
Item entity = (Item) itemEntity.bridge$getBukkitEntity();
ItemSpawnEvent event = new ItemSpawnEvent(entity);
event.setCancelled(true);
cir.setReturnValue(event);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package io.izzel.arclight.common.mixin.core.world.damagesource;

import io.izzel.arclight.common.bridge.core.util.DamageSourceBridge;
import net.minecraft.core.Holder;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.damagesource.DamageType;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.Vec3;
import org.bukkit.block.Block;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;

Expand All @@ -13,14 +18,20 @@ public abstract class DamageSourceMixin implements DamageSourceBridge {

// @formatter:off
@Shadow @Nullable public Entity getEntity() { return null; }
@Shadow @Final @org.jetbrains.annotations.Nullable private Entity causingEntity;
@Shadow @Final private Holder<DamageType> type;
@Shadow @Final @org.jetbrains.annotations.Nullable private Entity directEntity;
@Shadow @Final @org.jetbrains.annotations.Nullable private Vec3 damageSourcePosition;
// @formatter:on

private boolean sweep;
private org.bukkit.block.Block directBlock;
private boolean withSweep;
private boolean melting;
private boolean poison;
private Entity customCausingEntity = null;

public boolean isSweep() {
return sweep;
return withSweep;
}

@Override
Expand All @@ -29,7 +40,7 @@ public boolean isSweep() {
}

public DamageSource sweep() {
sweep = true;
withSweep = true;
return (DamageSource) (Object) this;
}

Expand Down Expand Up @@ -65,4 +76,61 @@ public DamageSource poison() {
public DamageSource bridge$poison() {
return poison();
}

public Entity getCausingEntity() {
return this.customCausingEntity == null ? this.causingEntity : this.customCausingEntity;
}

@Override
public Entity bridge$getCausingEntity() {
return this.getCausingEntity();
}

@Override
public DamageSource bridge$customCausingEntity(Entity entity) {
var src = cloneInstance();
return ((DamageSourceBridge) src).bridge$setCustomCausingEntity(entity);
}

@Override
public DamageSource bridge$setCustomCausingEntity(Entity entity) {
this.customCausingEntity = entity;
return (DamageSource) (Object) this;
}

public Block getDirectBlock() {
return this.directBlock;
}

@Override
public Block bridge$directBlock() {
return this.getDirectBlock();
}

@Override
public DamageSource bridge$directBlock(Block block) {
return ((DamageSourceBridge) cloneInstance()).bridge$setDirectBlock(block);
}

@Override
public DamageSource bridge$setDirectBlock(Block block) {
this.directBlock = block;
return (DamageSource) (Object) this;
}

private DamageSource cloneInstance() {
var damageSource = new DamageSource(this.type, this.directEntity, this.causingEntity, this.damageSourcePosition);
var br = (DamageSourceBridge) damageSource;
br.bridge$directBlock(this.bridge$directBlock());
if (this.withSweep) {
br.bridge$sweep();
}
if (this.poison) {
br.bridge$poison();
}
if (this.melting) {
br.bridge$melting();
}
return damageSource;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,21 @@ public abstract class DamageSourcesMixin implements DamageSourcesBridge {
this.poison = ((DamageSourceBridge) this.source(DamageTypes.MAGIC)).bridge$poison();
}

public DamageSource poison() {
return poison;
}

public DamageSource melting() {
return melting;
}

@Override
public DamageSource bridge$poison() {
return poison;
return poison();
}

@Override
public DamageSource bridge$melting() {
return melting;
return melting();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import io.izzel.arclight.common.bridge.core.entity.LivingEntityBridge;
import io.izzel.arclight.common.bridge.core.entity.player.ServerPlayerEntityBridge;
import io.izzel.arclight.common.bridge.core.network.datasync.SynchedEntityDataBridge;
import io.izzel.arclight.common.bridge.core.util.DamageSourceBridge;
import io.izzel.arclight.common.bridge.core.world.TeleporterBridge;
import io.izzel.arclight.common.bridge.core.world.WorldBridge;
import io.izzel.arclight.common.bridge.core.world.level.block.PortalInfoBridge;
Expand Down Expand Up @@ -459,9 +460,8 @@ public void postTick() {

@Redirect(method = "lavaHurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;setSecondsOnFire(I)V"))
public void arclight$setOnFireFromLava$bukkitEvent(Entity entity, int seconds) {
var damager = (lastLavaContact == null) ? null : CraftBlock.at(level(), lastLavaContact);
CraftEventFactory.blockDamage = damager;
if ((Object) this instanceof LivingEntity && remainingFireTicks <= 0) {
var damager = (lastLavaContact == null) ? null : CraftBlock.at(level(), lastLavaContact);
var damagee = this.getBukkitEntity();
EntityCombustEvent combustEvent = new EntityCombustByBlockEvent(damager, damagee, 15);
Bukkit.getPluginManager().callEvent(combustEvent);
Expand All @@ -475,9 +475,10 @@ public void postTick() {
}
}

@Inject(method = "lavaHurt", at = @At("RETURN"))
private void arclight$resetBlockDamage(CallbackInfo ci) {
CraftEventFactory.blockDamage = null;
@Redirect(method = "lavaHurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/damagesource/DamageSources;lava()Lnet/minecraft/world/damagesource/DamageSource;"))
private DamageSource arclight$resetBlockDamage(DamageSources instance) {
var damager = (lastLavaContact == null) ? null : CraftBlock.at(level(), lastLavaContact);
return ((DamageSourceBridge) instance.lava()).bridge$directBlock(damager);
}

public void setSecondsOnFire(int seconds, boolean callEvent) {
Expand Down Expand Up @@ -889,9 +890,7 @@ public boolean removePassenger(Entity entity) { // CraftBukkit
if (this.fireImmune()) {
return false;
}
CraftEventFactory.entityDamage = entity;
if (!this.hurt(this.damageSources().lightningBolt(), amount)) {
CraftEventFactory.entityDamage = null;
if (!this.hurt(((DamageSourceBridge) this.damageSources().lightningBolt()).bridge$customCausingEntity(entity), amount)) {
return false;
}
return true;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package io.izzel.arclight.common.mixin.core.world.entity.animal;

import io.izzel.arclight.common.bridge.core.entity.passive.TurtleEntityBridge;
import io.izzel.arclight.common.bridge.core.util.DamageSourceBridge;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.damagesource.DamageSources;
import net.minecraft.world.entity.LightningBolt;
import net.minecraft.world.entity.animal.Turtle;
import org.bukkit.craftbukkit.v.event.CraftEventFactory;
Expand All @@ -10,6 +13,7 @@
import org.spongepowered.asm.mixin.gen.Invoker;
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;

@Mixin(Turtle.class)
Expand All @@ -32,13 +36,8 @@ public abstract class TurtleMixin extends AnimalMixin implements TurtleEntityBri
forceDrops = false;
}

@Inject(method = "thunderHit", at = @At("HEAD"))
private void arclight$lightning(ServerLevel world, LightningBolt lightningBolt, CallbackInfo ci) {
CraftEventFactory.entityDamage = lightningBolt;
}

@Inject(method = "thunderHit", at = @At("RETURN"))
private void arclight$lightningReset(ServerLevel world, LightningBolt lightningBolt, CallbackInfo ci) {
CraftEventFactory.entityDamage = null;
@Redirect(method = "thunderHit", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/damagesource/DamageSources;lightningBolt()Lnet/minecraft/world/damagesource/DamageSource;"))
private DamageSource arclight$lightning(DamageSources instance, ServerLevel serverLevel, LightningBolt lightningBolt) {
return ((DamageSourceBridge) instance.lightningBolt()).bridge$customCausingEntity(lightningBolt);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,6 @@ public abstract class FallingBlockEntityMixin extends EntityMixin {
}
}

@Inject(method = "causeFallDamage", at = @At(value = "INVOKE", remap = false, target = "Ljava/util/List;forEach(Ljava/util/function/Consumer;)V"))
private void arclight$damageSource(float distance, float damageMultiplier, DamageSource source, CallbackInfoReturnable<Boolean> cir) {
CraftEventFactory.entityDamage = (FallingBlockEntity) (Object) this;
}

@Inject(method = "causeFallDamage", at = @At(value = "INVOKE", remap = false, shift = At.Shift.AFTER, target = "Ljava/util/List;forEach(Ljava/util/function/Consumer;)V"))
private void arclight$damageSourceReset(float distance, float damageMultiplier, DamageSource source, CallbackInfoReturnable<Boolean> cir) {
CraftEventFactory.entityDamage = null;
}

@Inject(method = "fall", cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD, 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 static void arclight$entityFall(Level level, BlockPos pos, BlockState state, CallbackInfoReturnable<FallingBlockEntity> cir, FallingBlockEntity entity) {
if (!CraftEventFactory.callEntityChangeBlockEvent(entity, pos, state.getFluidState().createLegacyBlock())) {
Expand Down
Loading

0 comments on commit 0a711ca

Please sign in to comment.