Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize anti beacon to not deadlock worldgen or lag entities #2334

Merged
merged 2 commits into from
Dec 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package com.lothrazar.cyclic.block.antipotion;

import java.util.ArrayList;
import java.util.List;
import com.lothrazar.cyclic.ModCyclic;
import com.lothrazar.cyclic.block.BlockCyclic;
import com.lothrazar.cyclic.capabilities.livingentity.LivingEntityCapProvider;
import com.lothrazar.cyclic.capabilities.livingentity.LivingEntityCapabilityStorage;
import com.lothrazar.cyclic.registry.BlockRegistry;
import com.lothrazar.cyclic.registry.TileRegistry;
import com.lothrazar.library.util.BlockstatesUtil;
import com.lothrazar.library.util.EntityUtil;
import com.lothrazar.library.util.StringParseUtil;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.effect.MobEffectCategory;
import net.minecraft.world.entity.LivingEntity;
Expand All @@ -26,6 +27,9 @@
import net.minecraftforge.eventbus.api.Event.Result;
import net.minecraftforge.registries.ForgeRegistries;

import java.util.ArrayList;
import java.util.List;

public class BlockAntiBeacon extends BlockCyclic {

private static final float[] COLOR = new float[] { 1, 1, 1 };
Expand Down Expand Up @@ -74,6 +78,29 @@ public static void absorbPotions(Level world, BlockPos pos) {
}
}

public static void markNearbyEntitiesWithAntiBeaconPosition(Level world, BlockPos pos) {
List<LivingEntity> all = world.getEntitiesOfClass(LivingEntity.class, EntityUtil.makeBoundingBox(pos, TileAntiBeacon.RADIUS.get(), TileAntiBeacon.RADIUS.get()));
for (LivingEntity e : all) {
LivingEntityCapabilityStorage livingEntityData = e.getCapability(LivingEntityCapProvider.CYCLIC_LIVING_ENTITY).orElse(null);
if (livingEntityData == null) {
continue;
}

BlockPos oldPosition = livingEntityData.getClosestAntiBeaconPosition();
if (oldPosition != null && world.getBlockState(oldPosition).is(BlockRegistry.ANTI_BEACON.get())) {
int oldDistance = e.blockPosition().distManhattan(oldPosition);
int newDistance = e.blockPosition().distManhattan(pos);

if (newDistance < oldDistance) {
livingEntityData.setClosestAntiBeaconPosition(pos);
}
}
else {
livingEntityData.setClosestAntiBeaconPosition(pos);
}
}
}

private static void cureAllRelevant(LivingEntity e) {
List<MobEffect> cureMe = new ArrayList<>();
for (MobEffect mobEffect : e.getActiveEffectsMap().keySet()) {
Expand Down Expand Up @@ -101,16 +128,41 @@ public void isPotionApplicable(MobEffectEvent.Applicable event) {
if (event.getEffectInstance() == null) {
return;
}

//this will cancel it
if (BlockAntiBeacon.doesConfigBlockEffect(event.getEffectInstance().getEffect())) {
LivingEntity livingEntity = event.getEntity();
if (BlockAntiBeacon.doesConfigBlockEffect(event.getEffectInstance().getEffect()) &&
livingEntity.getCommandSenderWorld() instanceof ServerLevel serverLevel &&
serverLevel.isLoaded(livingEntity.blockPosition())) {

LivingEntityCapabilityStorage livingEntityData = livingEntity.getCapability(LivingEntityCapProvider.CYCLIC_LIVING_ENTITY).orElse(null);
if (livingEntityData == null) {
return;
}

BlockPos closestAntiBeacon = livingEntityData.getClosestAntiBeaconPosition();
if (closestAntiBeacon == null) {
return;
}

if (livingEntity.blockPosition().distManhattan(closestAntiBeacon) > TileAntiBeacon.RADIUS.get()) {
livingEntityData.setClosestAntiBeaconPosition(null);
return;
}

if (!serverLevel.getBlockState(closestAntiBeacon).getBlock().equals(this)) {
livingEntityData.setClosestAntiBeaconPosition(null);
return;
}

final boolean isPowered = false; // if im NOT powered, im running
List<BlockPos> blocks = BlockstatesUtil.findBlocks(event.getEntity().getCommandSenderWorld(),
event.getEntity().blockPosition(), this, TileAntiBeacon.RADIUS.get(), isPowered);
//can
if (blocks != null && blocks.size() > 0) {
ModCyclic.LOGGER.info("[potion blocked] " + event.getEffectInstance());
event.setResult(Result.DENY);
if (serverLevel.hasNeighborSignal(closestAntiBeacon) != isPowered) {
return;
}

//can
ModCyclic.LOGGER.info("[potion blocked] " + event.getEffectInstance());
event.setResult(Result.DENY);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,13 @@ public static void serverTick(Level level, BlockPos blockPos, BlockState blockSt
//ok go
tile.tick(level, blockPos);
if (tile.timer <= 0) {
BlockAntiBeacon.markNearbyEntitiesWithAntiBeaconPosition(level, blockPos);
BlockAntiBeacon.absorbPotions(level, blockPos);
tile.timer = TICKS.get();
}
else {
tile.timer--;
}
}

public static <E extends BlockEntity> void clientTick(Level level, BlockPos blockPos, BlockState blockState, TileAntiBeacon e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.lothrazar.cyclic.capabilities.livingentity;

import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.common.capabilities.CapabilityToken;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.INBTSerializable;
import net.minecraftforge.common.util.LazyOptional;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

public class LivingEntityCapProvider implements ICapabilityProvider, INBTSerializable<CompoundTag> {

public static Capability<LivingEntityCapabilityStorage> CYCLIC_LIVING_ENTITY = CapabilityManager.get(new CapabilityToken<>() {});
private LivingEntityCapabilityStorage livingEntityAntiBeaconPosition = null;
private final LazyOptional<LivingEntityCapabilityStorage> opt = LazyOptional.of(this::createMe);

@Nonnull
private LivingEntityCapabilityStorage createMe() {
if (livingEntityAntiBeaconPosition == null) {
livingEntityAntiBeaconPosition = new LivingEntityCapabilityStorage();
}
return livingEntityAntiBeaconPosition;
}

@Nonnull
@Override
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap) {
if (cap == CYCLIC_LIVING_ENTITY) {
return opt.cast();
}
return LazyOptional.empty();
}

@Nonnull
@Override
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
return getCapability(cap);
}

@Override
public CompoundTag serializeNBT() {
CompoundTag nbt = new CompoundTag();
createMe().saveNBTData(nbt);
return nbt;
}

@Override
public void deserializeNBT(CompoundTag nbt) {
createMe().loadNBTData(nbt);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.lothrazar.cyclic.capabilities.livingentity;

import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtUtils;

public class LivingEntityCapabilityStorage {

BlockPos closestAntiBeaconPosition = null;

public LivingEntityCapabilityStorage() {}

public BlockPos getClosestAntiBeaconPosition() {
return closestAntiBeaconPosition;
}

public void setClosestAntiBeaconPosition(BlockPos closestAntiBeaconPosition) {
this.closestAntiBeaconPosition = closestAntiBeaconPosition;
}

public void saveNBTData(CompoundTag compound) {
if (closestAntiBeaconPosition != null) {
compound.put("closestAntiBeaconPosition", NbtUtils.writeBlockPos(closestAntiBeaconPosition));
}
}

public void loadNBTData(CompoundTag compound) {
if (compound.contains("closestAntiBeaconPosition")) {
closestAntiBeaconPosition = NbtUtils.readBlockPos(compound.getCompound("closestAntiBeaconPosition"));
}
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package com.lothrazar.cyclic.registry;

import com.lothrazar.cyclic.ModCyclic;
import com.lothrazar.cyclic.capabilities.livingentity.LivingEntityCapProvider;
import com.lothrazar.cyclic.capabilities.livingentity.LivingEntityCapabilityStorage;
import com.lothrazar.cyclic.capabilities.player.PlayerCapProvider;
import com.lothrazar.cyclic.capabilities.player.PlayerCapabilityStorage;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent;
import net.minecraftforge.event.AttachCapabilitiesEvent;
Expand All @@ -22,11 +25,18 @@ public static void onAttachCapabilitiesPlayer(AttachCapabilitiesEvent<Entity> ev
event.addCapability(new ResourceLocation(ModCyclic.MODID, "data"), new PlayerCapProvider());
}
}
if (event.getObject() instanceof LivingEntity) {
if (!event.getObject().getCapability(LivingEntityCapProvider.CYCLIC_LIVING_ENTITY).isPresent()) {
// The living entity does not already have this capability so we need to add the capability provider here
event.addCapability(new ResourceLocation(ModCyclic.MODID, "living_entity_data"), new LivingEntityCapProvider());
}
}
}

@SubscribeEvent
public void onRegisterCapabilities(RegisterCapabilitiesEvent event) {
event.register(PlayerCapabilityStorage.class);
event.register(LivingEntityCapabilityStorage.class);
}
// Finally we need to register our capability in a RegisterCapabilitiesEvent
}