Implement entity activation range

This commit is contained in:
IzzelAliz 2021-02-04 20:55:45 +08:00
parent 24db9e1cc0
commit 5605db762f
15 changed files with 313 additions and 29 deletions

View File

@ -0,0 +1,6 @@
package io.izzel.arclight.common.bridge.entity;
public interface AgeableEntityBridge extends LivingEntityBridge {
boolean bridge$isAgeLocked();
}

View File

@ -54,6 +54,4 @@ public interface EntityBridge extends ICommandSourceBridge {
int bridge$getRideCooldown();
boolean bridge$canCollideWith(Entity entity);
void bridge$inactiveTick();
}

View File

@ -1,5 +1,6 @@
package io.izzel.arclight.common.mixin.core.entity;
import io.izzel.arclight.common.bridge.entity.AgeableEntityBridge;
import net.minecraft.entity.AgeableEntity;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.world.World;
@ -14,7 +15,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import javax.annotation.Nullable;
@Mixin(AgeableEntity.class)
public abstract class AgeableEntityMixin extends CreatureEntityMixin {
public abstract class AgeableEntityMixin extends CreatureEntityMixin implements AgeableEntityBridge {
// @formatter:off
@Shadow public abstract boolean isChild();
@ -38,4 +39,9 @@ public abstract class AgeableEntityMixin extends CreatureEntityMixin {
private boolean arclight$tickIfNotLocked(World world) {
return world.isRemote || ageLocked;
}
@Override
public boolean bridge$isAgeLocked() {
return this.ageLocked;
}
}

View File

@ -73,7 +73,6 @@ import org.bukkit.event.vehicle.VehicleEnterEvent;
import org.bukkit.event.vehicle.VehicleExitEvent;
import org.bukkit.plugin.PluginManager;
import org.bukkit.projectiles.ProjectileSource;
import org.spigotmc.ActivationRange;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
@ -201,41 +200,18 @@ public abstract class EntityMixin implements InternalEntityBridge, EntityBridge,
// @formatter:on
private static final int CURRENT_LEVEL = 2;
public boolean persist;
public boolean persist = true;
public boolean valid;
public org.bukkit.projectiles.ProjectileSource projectileSource; // For projectiles only
public boolean forceExplosionKnockback; // SPIGOT-949
public org.spigotmc.ActivationRange.ActivationType activationType;
public boolean defaultActivationState;
public long activatedTick = Integer.MIN_VALUE;
public boolean persistentInvisibility = false;
@Inject(method = "<init>", at = @At("RETURN"))
private void arclight$init(EntityType<?> entityTypeIn, World worldIn, CallbackInfo ci) {
this.persist = true;
activationType = ActivationRange.initializeEntityActivationType((Entity) (Object) this);
if (worldIn != null) {
this.defaultActivationState = ActivationRange.initializeEntityActivationState((Entity) (Object) this, ((WorldBridge) worldIn).bridge$spigotConfig());
} else {
this.defaultActivationState = false;
}
}
private CraftEntity bukkitEntity;
public CraftEntity getBukkitEntity() {
return internal$getBukkitEntity();
}
public void inactiveTick() {
this.tick();
}
@Override
public void bridge$inactiveTick() {
this.inactiveTick();
}
@Override
public CommandSender bridge$getBukkitSender(CommandSource wrapper) {
return internal$getBukkitEntity();

View File

@ -0,0 +1,6 @@
package io.izzel.arclight.impl.bridge;
public interface EntityBridge_ActivationRange {
void bridge$inactiveTick();
}

View File

@ -0,0 +1,46 @@
package io.izzel.arclight.impl.mixin.optimization.general.activationrange;
import io.izzel.arclight.common.bridge.world.WorldBridge;
import io.izzel.arclight.impl.bridge.EntityBridge_ActivationRange;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.world.World;
import org.spigotmc.ActivationRange;
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.callback.CallbackInfo;
@Mixin(Entity.class)
public abstract class EntityMixin_ActivationRange implements EntityBridge_ActivationRange {
// @formatter:off
@Shadow public abstract void recalculateSize();
@Shadow public int ticksExisted;
@Shadow public abstract void remove();
@Shadow public World world;
// @formatter:on
public ActivationRange.ActivationType activationType;
public boolean defaultActivationState;
public long activatedTick = Integer.MIN_VALUE;
@Inject(method = "<init>", at = @At("RETURN"))
private void arclight$init(EntityType<?> entityTypeIn, World worldIn, CallbackInfo ci) {
activationType = ActivationRange.initializeEntityActivationType((Entity) (Object) this);
if (worldIn != null) {
this.defaultActivationState = ActivationRange.initializeEntityActivationState((Entity) (Object) this, ((WorldBridge) worldIn).bridge$spigotConfig());
} else {
this.defaultActivationState = false;
}
}
public void inactiveTick() {
}
@Override
public void bridge$inactiveTick() {
this.inactiveTick();
}
}

View File

@ -0,0 +1,34 @@
package io.izzel.arclight.impl.mixin.optimization.general.activationrange;
import io.izzel.arclight.impl.bridge.EntityBridge_ActivationRange;
import net.minecraft.entity.Entity;
import net.minecraft.world.server.ServerWorld;
import org.spigotmc.ActivationRange;
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.callback.CallbackInfo;
import java.util.function.BooleanSupplier;
@Mixin(ServerWorld.class)
public class ServerWorldMixin_ActivationRange {
@Inject(method = "tick", at = @At(value = "INVOKE", remap = false, target = "Lit/unimi/dsi/fastutil/ints/Int2ObjectMap;int2ObjectEntrySet()Lit/unimi/dsi/fastutil/objects/ObjectSet;"))
private void activationRange$activateEntity(BooleanSupplier hasTimeLeft, CallbackInfo ci) {
ActivationRange.activateEntities((ServerWorld) (Object) this);
}
@Inject(method = "updateEntity", cancellable = true, at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/Entity;forceSetPosition(DDD)V"))
private void activationRange$inactiveTick(Entity entityIn, CallbackInfo ci) {
if (!ActivationRange.checkIfActive(entityIn)) {
if (entityIn.addedToChunk) {
++entityIn.ticksExisted;
if (entityIn.canUpdate()) {
((EntityBridge_ActivationRange) entityIn).bridge$inactiveTick();
}
}
ci.cancel();
}
}
}

View File

@ -0,0 +1,23 @@
package io.izzel.arclight.impl.mixin.optimization.general.activationrange.entity;
import io.izzel.arclight.impl.mixin.optimization.general.activationrange.EntityMixin_ActivationRange;
import net.minecraft.entity.projectile.AbstractArrowEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(AbstractArrowEntity.class)
public abstract class AbstractArrowEntityMixin_ActivationRange extends EntityMixin_ActivationRange {
// @formatter:off
@Shadow public boolean inGround;
@Shadow protected int timeInGround;
// @formatter:on
@Override
public void inactiveTick() {
super.inactiveTick();
if (this.inGround) {
this.timeInGround++;
}
}
}

View File

@ -0,0 +1,33 @@
package io.izzel.arclight.impl.mixin.optimization.general.activationrange.entity;
import io.izzel.arclight.common.bridge.entity.AgeableEntityBridge;
import io.izzel.arclight.impl.mixin.optimization.general.activationrange.EntityMixin_ActivationRange;
import net.minecraft.entity.AgeableEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(AgeableEntity.class)
public abstract class AgeableEntityMixin_ActivationRange extends EntityMixin_ActivationRange {
// @formatter:off
@Shadow public abstract int getGrowingAge();
@Shadow public abstract void setGrowingAge(int age);
// @formatter:on
@Override
public void inactiveTick() {
super.inactiveTick();
if (((AgeableEntityBridge) this).bridge$isAgeLocked()) {
this.recalculateSize();
} else {
int i = this.getGrowingAge();
if (i < 0) {
++i;
this.setGrowingAge(i);
} else if (i > 0) {
--i;
this.setGrowingAge(i);
}
}
}
}

View File

@ -0,0 +1,23 @@
package io.izzel.arclight.impl.mixin.optimization.general.activationrange.entity;
import io.izzel.arclight.impl.mixin.optimization.general.activationrange.EntityMixin_ActivationRange;
import net.minecraft.entity.AreaEffectCloudEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(AreaEffectCloudEntity.class)
public abstract class AreaEffectCloudEntityMixin_ActivationRange extends EntityMixin_ActivationRange {
// @formatter:off
@Shadow public int waitTime;
@Shadow private int duration;
// @formatter:on
@Override
public void inactiveTick() {
super.inactiveTick();
if (this.ticksExisted >= this.waitTime + this.duration) {
this.remove();
}
}
}

View File

@ -0,0 +1,25 @@
package io.izzel.arclight.impl.mixin.optimization.general.activationrange.entity;
import io.izzel.arclight.impl.mixin.optimization.general.activationrange.EntityMixin_ActivationRange;
import net.minecraft.entity.projectile.FireworkRocketEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(FireworkRocketEntity.class)
public abstract class FireworkRocketEntityMixin_ActivationRange extends EntityMixin_ActivationRange {
// @formatter:off
@Shadow private int fireworkAge;
@Shadow public int lifetime;
@Shadow protected abstract void func_213893_k();
// @formatter:on
@Override
public void inactiveTick() {
super.inactiveTick();
++this.fireworkAge;
if (!this.world.isRemote && this.fireworkAge > this.lifetime) {
this.func_213893_k();
}
}
}

View File

@ -0,0 +1,55 @@
package io.izzel.arclight.impl.mixin.optimization.general.activationrange.entity;
import io.izzel.arclight.common.bridge.world.WorldBridge;
import io.izzel.arclight.common.mod.ArclightConstants;
import io.izzel.arclight.impl.mixin.optimization.general.activationrange.EntityMixin_ActivationRange;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import net.minecraftforge.event.ForgeEventFactory;
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.callback.CallbackInfo;
@Mixin(ItemEntity.class)
public abstract class ItemEntityMixin_ActivationRange extends EntityMixin_ActivationRange {
// @formatter:off
@Shadow public int pickupDelay;
@Shadow public int age;
@Shadow(remap = false) public int lifespan;
@Shadow public abstract ItemStack getItem();
// @formatter:on
@Inject(method = "<init>(Lnet/minecraft/entity/EntityType;Lnet/minecraft/world/World;)V", at = @At("RETURN"))
private void activationRange$init(EntityType<? extends ItemEntity> entityType, World world, CallbackInfo ci) {
this.lifespan = ((WorldBridge) this.world).bridge$spigotConfig().itemDespawnRate;
}
@Inject(method = "<init>(Lnet/minecraft/world/World;DDDLnet/minecraft/item/ItemStack;)V", at = @At("RETURN"))
private void activationRange$init(World worldIn, double x, double y, double z, ItemStack stack, CallbackInfo ci) {
if (this.lifespan == 6000) {
this.lifespan = ((WorldBridge) this.world).bridge$spigotConfig().itemDespawnRate;
}
}
private int lastTick = ArclightConstants.currentTick - 1;
@Override
public void inactiveTick() {
super.inactiveTick();
int elapsedTicks = ArclightConstants.currentTick - this.lastTick;
if (this.pickupDelay != 32767) this.pickupDelay -= elapsedTicks;
if (this.age != -32768) this.age += elapsedTicks;
this.lastTick = ArclightConstants.currentTick;
if (!this.world.isRemote && this.age >= this.lifespan) {
int hook = ForgeEventFactory.onItemExpire((ItemEntity) (Object) this, this.getItem());
if (hook < 0) this.remove();
else this.lifespan += hook;
}
}
}

View File

@ -0,0 +1,20 @@
package io.izzel.arclight.impl.mixin.optimization.general.activationrange.entity;
import io.izzel.arclight.impl.mixin.optimization.general.activationrange.EntityMixin_ActivationRange;
import net.minecraft.entity.LivingEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(LivingEntity.class)
public abstract class LivingEntityMixin_ActivationRange extends EntityMixin_ActivationRange {
// @formatter:off
@Shadow protected int idleTime;
// @formatter:on
@Override
public void inactiveTick() {
super.inactiveTick();
this.idleTime++;
}
}

View File

@ -0,0 +1,24 @@
package io.izzel.arclight.impl.mixin.optimization.general.activationrange.entity;
import io.izzel.arclight.common.bridge.world.WorldBridge;
import io.izzel.arclight.impl.mixin.optimization.general.activationrange.EntityMixin_ActivationRange;
import net.minecraft.entity.merchant.villager.VillagerEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(VillagerEntity.class)
public abstract class VillagerEntityMixin_ActivationRange extends EntityMixin_ActivationRange {
// @formatter:off
@Shadow protected abstract void updateAITasks();
// @formatter:on
@Override
public void inactiveTick() {
super.inactiveTick();
if (((WorldBridge) this.world).bridge$spigotConfig().tickInactiveVillagers
&& ((VillagerEntity) (Object) this).isServerWorld()) {
this.updateAITasks();
}
}
}

View File

@ -5,6 +5,15 @@
"refmap": "mixins.arclight.impl.refmap.1_16.json",
"mixins": [
"ClassInheritanceMultiMapMixin",
"VoxelShapesMixin"
"VoxelShapesMixin",
"activationrange.EntityMixin_ActivationRange",
"activationrange.ServerWorldMixin_ActivationRange",
"activationrange.entity.AbstractArrowEntityMixin_ActivationRange",
"activationrange.entity.AgeableEntityMixin_ActivationRange",
"activationrange.entity.AreaEffectCloudEntityMixin_ActivationRange",
"activationrange.entity.FireworkRocketEntityMixin_ActivationRange",
"activationrange.entity.ItemEntityMixin_ActivationRange",
"activationrange.entity.LivingEntityMixin_ActivationRange",
"activationrange.entity.VillagerEntityMixin_ActivationRange"
]
}