Skip to content

Commit

Permalink
change how emitted entities listen for block changes
Browse files Browse the repository at this point in the history
also bounding box is cached now
  • Loading branch information
TropheusJ committed Aug 20, 2023
1 parent 7682d92 commit f609366
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.fusionflux.portalcubed.accessor;

import com.fusionflux.portalcubed.entity.beams.EmittedEntity;
import com.fusionflux.portalcubed.mechanics.PortalCubedDamageSources;
import net.minecraft.world.entity.Entity;
import org.jetbrains.annotations.Nullable;
Expand All @@ -11,4 +12,8 @@ public interface LevelExt {

@Nullable
Entity getEntityByUuid(UUID uuid);

void pc$addBlockChangeListener(long sectionPos, EmittedEntity entity);

void pc$removeBlockChangeListener(long sectionPos, EmittedEntity entity);
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.fusionflux.portalcubed.entity.beams;

import com.fusionflux.portalcubed.accessor.LevelExt;
import com.fusionflux.portalcubed.entity.Portal;
import com.fusionflux.portalcubed.entity.PortalCubedEntities;
import com.fusionflux.portalcubed.entity.PortalListeningEntity;
import com.fusionflux.portalcubed.util.NbtHelper;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.core.SectionPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.FriendlyByteBuf;
Expand All @@ -17,7 +19,6 @@
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.entity.EntityTypeTest;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;
Expand All @@ -33,7 +34,6 @@

public abstract class EmittedEntity extends PortalListeningEntity implements QuiltExtendedSpawnDataEntity {
public static final int DEFAULT_MAX_LENGTH = 100;
public static final EntityTypeTest<Entity, EmittedEntity> TYPE_TEST = EntityTypeTest.forClass(EmittedEntity.class);
public static final EntityDataAccessor<Direction> FACING = SynchedEntityData.defineId(EmittedEntity.class, EntityDataSerializers.DIRECTION);
public static final EntityDataAccessor<Float> LENGTH = SynchedEntityData.defineId(EmittedEntity.class, EntityDataSerializers.FLOAT);

Expand All @@ -43,6 +43,7 @@ public abstract class EmittedEntity extends PortalListeningEntity implements Qui
private Vec3 center = Vec3.ZERO;
private AABB listeningArea = new AABB(BlockPos.ZERO);
private int reEmitTimer;
private AABB cachedBounds;

// UUID of next in line. resolving this will always work, since the first entity
// is the only one that can be unloaded (others are chunk loaded by portals)
Expand Down Expand Up @@ -89,14 +90,27 @@ public boolean listensTo(BlockPos pos) {
@Override
@NotNull
protected AABB makeBoundingBox() {
// updating bounds is expensive, minecraft calls this method constantly because of setPos
if (cachedBounds == null)
cachedBounds = actuallyMakeBoundingBox();
return cachedBounds;
}

protected AABB actuallyMakeBoundingBox() {
AABB base = makeBaseBoundingBox();
Vec3 pos = position();
Vec3 offset = pos.relative(getFacing(), getLength()).subtract(pos); // relative offset along facing by length
this.center = base.getCenter();
AABB bounds = base.expandTowards(offset);

Direction facing = getFacing();
Vec3 facingNormal = Vec3.ZERO.with(facing.getAxis(), facing.getAxisDirection().getStep());

if (listeningArea != null)
stopListeningToArea(listeningArea);
this.listeningArea = bounds.expandTowards(facingNormal);
startListeningToArea(listeningArea);

return bounds;
}

Expand Down Expand Up @@ -162,6 +176,7 @@ public void tick() {
@Override
public void remove(RemovalReason reason) {
super.remove(reason);
stopListeningToArea(listeningArea);
if (reason.shouldDestroy())
removeNextEntity();
}
Expand Down Expand Up @@ -227,6 +242,7 @@ protected void readAdditionalSaveData(CompoundTag tag) {
}

private void updateBounds() {
this.cachedBounds = actuallyMakeBoundingBox();
setBoundingBox(makeBoundingBox());
modelUpdater.accept(this);
}
Expand Down Expand Up @@ -254,4 +270,24 @@ public void onPortalRemove(Portal portal) {
public void onLinkedPortalCreate(Portal portal, Portal linked) {
reEmitTimer = 3;
}

public void startListeningToArea(AABB area) {
if (level() instanceof ServerLevel level) {
forEachSection(area, section -> ((LevelExt) level).pc$addBlockChangeListener(section.asLong(), this));
}
}

public void stopListeningToArea(AABB area) {
if (level() instanceof ServerLevel level) {
forEachSection(area, section -> ((LevelExt) level).pc$removeBlockChangeListener(section.asLong(), this));
}
}

public static void forEachSection(AABB bounds, Consumer<SectionPos> consumer) {
BlockPos minBlock = BlockPos.containing(bounds.minX, bounds.minY, bounds.minZ);
BlockPos maxBlock = BlockPos.containing(bounds.maxX, bounds.maxY, bounds.maxZ);
SectionPos min = SectionPos.of(minBlock);
SectionPos max = SectionPos.of(maxBlock);
SectionPos.betweenClosedStream(min.x(), min.y(), min.z(), max.x(), max.y(), max.z()).forEach(consumer);
}
}
52 changes: 44 additions & 8 deletions src/main/java/com/fusionflux/portalcubed/mixin/LevelMixin.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.SectionPos;
import net.minecraft.resources.ResourceKey;
import net.minecraft.util.AbortableIterationConsumer.Continuation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level;
Expand All @@ -18,6 +19,9 @@
import net.minecraft.world.level.entity.LevelEntityGetter;
import net.minecraft.world.level.storage.WritableLevelData;

import com.google.common.collect.AbstractIterator;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
Expand All @@ -26,13 +30,19 @@
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import java.util.function.Supplier;

@Mixin(Level.class)
public abstract class LevelMixin implements LevelAccessor, LevelExt {
@Unique
PortalCubedDamageSources pc$damageSources;
private PortalCubedDamageSources pc$damageSources;
@Unique
private Long2ObjectMap<List<EmittedEntity>> pc$blockChangeListeners = new Long2ObjectOpenHashMap<>();

@Shadow
protected abstract LevelEntityGetter<Entity> getEntities();
Expand All @@ -55,12 +65,38 @@ private void createDamageSources(

@Inject(method = "setBlocksDirty", at = @At("HEAD"))
private void updateEmittedEntities(BlockPos pos, BlockState old, BlockState updated, CallbackInfo ci) {
if (!isClientSide() && old.getCollisionShape(this, pos) != updated.getCollisionShape(this, pos)) {
getEntities().get(EmittedEntity.TYPE_TEST, emitted -> {
if (emitted.listensTo(pos))
emitted.reEmit();
return Continuation.CONTINUE;
});
if ((Object) this instanceof ServerLevel) {
getListeners(pos).forEachRemaining(EmittedEntity::reEmit);
}
}

@Unique
private Iterator<EmittedEntity> getListeners(BlockPos pos) {
long sectionPos = SectionPos.asLong(pos);
List<EmittedEntity> listeners = pc$blockChangeListeners.get(sectionPos);
return listeners == null || listeners.isEmpty() ? Collections.emptyIterator() : new AbstractIterator<>() {
private final Iterator<EmittedEntity> entities = List.copyOf(listeners).iterator(); // copy to avoid CMEs

@Override
protected EmittedEntity computeNext() {
if (!entities.hasNext())
return endOfData();
EmittedEntity next = entities.next();
return next.listensTo(pos) ? next : computeNext();
}
};
}

@Override
public void pc$addBlockChangeListener(long sectionPos, EmittedEntity entity) {
pc$blockChangeListeners.computeIfAbsent(sectionPos, $ -> new ArrayList<>()).add(entity);
}

@Override
public void pc$removeBlockChangeListener(long sectionPos, EmittedEntity entity) {
List<EmittedEntity> listeners = pc$blockChangeListeners.get(sectionPos);
if (listeners != null) {
listeners.remove(entity);
}
}

Expand Down

0 comments on commit f609366

Please sign in to comment.