Skip to content
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
Expand Up @@ -19,6 +19,7 @@
import com.rae.creatingspace.content.rocket.CustomTeleporter;
import com.rae.creatingspace.init.ingameobject.BlockInit;
import com.rae.creatingspace.init.ingameobject.ItemInit;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
Expand All @@ -42,6 +43,7 @@
import net.neoforged.neoforge.event.tick.EntityTickEvent;
import net.neoforged.neoforge.registries.IdMappingEvent;

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

Expand Down Expand Up @@ -194,38 +196,56 @@ public static void registerCommands(RegisterCommandsEvent event) {

@SubscribeEvent
public static void onBlockPlaced(BlockEvent.NeighborNotifyEvent event) {
boolean blockPlaced = false;
Level level = (Level) event.getLevel();
AABB colBoxInside = new AABB(event.getPos());
// rooms only exist (and only matter) on the logical server
if (!(event.getLevel() instanceof ServerLevel level)) {
return;
}
BlockPos pos = event.getPos();
AABB colBoxInside = new AABB(pos);

// one query covering the block and its 6 neighbours, instead of up to 7 separate queries
// for every single block update in every dimension
List<RoomAtmosphere> nearby = level.getEntitiesOfClass(RoomAtmosphere.class, colBoxInside.inflate(1.0));
if (nearby.isEmpty()) {
return;
}

List<RoomAtmosphere> entityStream = level.getEntitiesOfClass(RoomAtmosphere.class, colBoxInside);
for (RoomAtmosphere atmosphere : entityStream) {
boolean smarter = CSConfigs.SERVER.smarterSearch.get();
List<RoomAtmosphere> insideRooms = new ArrayList<>();
for (RoomAtmosphere atmosphere : nearby) {
if (atmosphere.getBoundingBox().intersects(colBoxInside)) {
insideRooms.add(atmosphere);
}
}

boolean blockPlaced = false;
for (RoomAtmosphere atmosphere : insideRooms) {
if (atmosphere.getShape().inside(colBoxInside)) {
blockPlaced = true;
}
}

// rebuilds are queued on the room and processed on its next tick, so a burst of block
// updates (piston, door, machine) results in one rebuild instead of one per update
if (blockPlaced) {
for (RoomAtmosphere atmosphere : entityStream) {
if (CSConfigs.SERVER.smarterSearch.get()){
atmosphere.regenerateRoom(event.getPos());
for (RoomAtmosphere atmosphere : insideRooms) {
if (smarter) {
atmosphere.requestRegenerate(pos);
} else {
atmosphere.resetShape();
atmosphere.regenerateRoom(atmosphere.getOnPos());
atmosphere.requestFullRebuild();
}
}
}
else {
for (Direction direction :
event.getNotifiedSides()) {
AABB colBoxOutside = new AABB(event.getPos().relative(direction));
entityStream = level.getEntitiesOfClass(RoomAtmosphere.class, colBoxOutside);

for (RoomAtmosphere atmosphere : entityStream) {
if (CSConfigs.SERVER.smarterSearch.get()) {
atmosphere.regenerateRoom(event.getPos().relative(direction));
} else {
atmosphere.resetShape();
atmosphere.regenerateRoom(atmosphere.getOnPos());
} else {
for (Direction direction : event.getNotifiedSides()) {
BlockPos neighbour = pos.relative(direction);
AABB colBoxOutside = new AABB(neighbour);
for (RoomAtmosphere atmosphere : nearby) {
if (atmosphere.getBoundingBox().intersects(colBoxOutside)) {
if (smarter) {
atmosphere.requestRegenerate(neighbour);
} else {
atmosphere.requestFullRebuild();
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,48 @@ public RoomAtmosphere(EntityType<?> entityType, Level level) {
ArrayList<BlockPos> roomSealers = new ArrayList<>();
HashMap<ResourceLocation, AtmosphereFilterData> passiveFilters = new HashMap<>();
Queue<BlockPos> toVist = new ArrayDeque<>();
// minimum ticks between two rebuilds triggered by block changes
private static final int REGEN_COOLDOWN = 5;
private final LinkedHashSet<BlockPos> pendingRegen = new LinkedHashSet<>();
private boolean pendingFullRebuild = false;
private int lastRegenTick = -REGEN_COOLDOWN;

/**
* Ask for a full rebuild (reset + new search). Many requests in a short time collapse into one.
*/
public void requestFullRebuild() {
pendingFullRebuild = true;
}

/**
* Ask for an incremental rebuild around a changed block (smarterSearch mode).
*/
public void requestRegenerate(BlockPos pos) {
pendingRegen.add(pos.immutable());
}

private void processPendingRegeneration() {
if (!pendingFullRebuild && pendingRegen.isEmpty()) {
return;
}
if (tickCount - lastRegenTick < REGEN_COOLDOWN) {
return;
}
lastRegenTick = tickCount;
if (pendingFullRebuild) {
pendingFullRebuild = false;
pendingRegen.clear();
toVist = new ArrayDeque<>();
resetShape();
regenerateRoom(getOnPos());
} else {
List<BlockPos> positions = new ArrayList<>(pendingRegen);
pendingRegen.clear();
for (BlockPos pos : positions) {
regenerateRoom(pos);
}
}
}
//TODO make a regenerateRoom and a searchFrontier methode (regenerateRoom will only initiate the call, searchFrontier will be private)
public void regenerateRoom(BlockPos firstPos) {
passiveFilters = new HashMap<>();
Expand Down Expand Up @@ -208,6 +250,10 @@ else if (toVist.isEmpty()){
}

private void applyOnBlock(BlockPos pos) {
// never touch unloaded chunks: getBlockState/getBlockEntity would load or generate them on the server thread
if (!level().hasChunkAt(pos)) {
return;
}
BlockState state = level().getBlockState(pos);
if (level().getBlockEntity(pos) instanceof RoomPressuriserBlockEntity rp && !roomSealers.contains(pos)) {
roomSealers.add(pos);
Expand All @@ -223,6 +269,10 @@ private void applyOnBlock(BlockPos pos) {
}

private boolean canGoThrough(Level world, BlockPos currentPos, Direction dir) {
// unloaded chunks count as solid, so the search can never force a synchronous chunk load
if (!world.hasChunkAt(currentPos)) {
return false;
}
//copied from AirCurrent
BlockState state = world.getBlockState(currentPos);
BlockState copycatState = CopycatBlock.getMaterial(world, currentPos);
Expand Down Expand Up @@ -326,6 +376,7 @@ public void tick() {
super.tick();

if (!level().isClientSide()) {
processPendingRegeneration();
if (!toVist.isEmpty()){
entityData.set(SHAPE_DATA_ACCESSOR,searchTopology(toVist.poll()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

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

public class RoomShape {
ArrayList<AABB> listOfBox;
Expand Down Expand Up @@ -197,4 +198,17 @@ private List<AABB> carve(AABB carver, AABB carved) {

return aabbs.stream().filter(aabb -> aabb.getSize() != 0).toList();
}
}

// Value equality lets SynchedEntityData skip re-sending an unchanged shape to every tracking player.
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof RoomShape other)) return false;
return volume == other.volume && closed == other.closed && listOfBox.equals(other.listOfBox);
}

@Override
public int hashCode() {
return Objects.hash(listOfBox, volume, closed);
}
}