diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 7b41592ff..8b49085c9 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -13,6 +13,9 @@ minecraft { dependencies { compileOnly("org.spongepowered:mixin:0.8.5") + // This is just the eventbus implementation from neoforge, it does not require + // the rest of neoforge. + api("net.neoforged:bus:8.0.5") } configurations { diff --git a/common/src/main/java/com/jaquadro/minecraft/storagedrawers/api/event/INetworkedLoadedEvent.java b/common/src/main/java/com/jaquadro/minecraft/storagedrawers/api/event/INetworkedLoadedEvent.java new file mode 100644 index 000000000..c8706bf3a --- /dev/null +++ b/common/src/main/java/com/jaquadro/minecraft/storagedrawers/api/event/INetworkedLoadedEvent.java @@ -0,0 +1,25 @@ +package com.jaquadro.minecraft.storagedrawers.api.event; + +import com.jaquadro.minecraft.storagedrawers.block.tile.BaseBlockEntity; +import net.minecraft.core.BlockPos; +import net.neoforged.bus.api.Event; + +public class INetworkedLoadedEvent extends Event { + private final BlockPos pos; + private final BaseBlockEntity entity; + + public INetworkedLoadedEvent(BaseBlockEntity entity, BlockPos pos) { + this.pos = pos; + this.entity = entity; + } + + public BlockPos getPos() { + return pos; + } + + public BaseBlockEntity getEntity() { + return entity; + } + + +} diff --git a/common/src/main/java/com/jaquadro/minecraft/storagedrawers/api/event/INetworkedUnloadedEvent.java b/common/src/main/java/com/jaquadro/minecraft/storagedrawers/api/event/INetworkedUnloadedEvent.java new file mode 100644 index 000000000..ba3c9d6e6 --- /dev/null +++ b/common/src/main/java/com/jaquadro/minecraft/storagedrawers/api/event/INetworkedUnloadedEvent.java @@ -0,0 +1,25 @@ +package com.jaquadro.minecraft.storagedrawers.api.event; + +import com.jaquadro.minecraft.storagedrawers.block.tile.BaseBlockEntity; +import net.minecraft.core.BlockPos; +import net.neoforged.bus.api.Event; + +public class INetworkedUnloadedEvent extends Event { + private final BlockPos pos; + private final BaseBlockEntity entity; + + public INetworkedUnloadedEvent(BaseBlockEntity entity, BlockPos pos) { + this.entity = entity; + this.pos = pos; + } + + public BlockPos getPos() { + return pos; + } + + public BaseBlockEntity getEntity() { + return entity; + } + + +} diff --git a/common/src/main/java/com/jaquadro/minecraft/storagedrawers/block/tile/BaseBlockEntity.java b/common/src/main/java/com/jaquadro/minecraft/storagedrawers/block/tile/BaseBlockEntity.java index 530fbde2e..a7c271067 100644 --- a/common/src/main/java/com/jaquadro/minecraft/storagedrawers/block/tile/BaseBlockEntity.java +++ b/common/src/main/java/com/jaquadro/minecraft/storagedrawers/block/tile/BaseBlockEntity.java @@ -1,6 +1,10 @@ package com.jaquadro.minecraft.storagedrawers.block.tile; +import com.jaquadro.minecraft.storagedrawers.api.event.INetworkedLoadedEvent; +import com.jaquadro.minecraft.storagedrawers.api.event.INetworkedUnloadedEvent; +import com.jaquadro.minecraft.storagedrawers.api.storage.INetworked; import com.jaquadro.minecraft.storagedrawers.block.tile.tiledata.BlockEntityDataShim; +import com.jaquadro.minecraft.storagedrawers.core.ModINetworkedLocations; import net.minecraft.core.BlockPos; import net.minecraft.core.HolderLookup; import net.minecraft.nbt.CompoundTag; @@ -29,6 +33,22 @@ public BaseBlockEntity (BlockEntityType blockEntityType, BlockPos pos, BlockS super(blockEntityType, pos, state); } + @Override + public void setRemoved () { + BlockPos pos = getBlockPos(); + super.setRemoved(); + if (this instanceof INetworked && getLevel() != null && !getLevel().isClientSide()) { + ModINetworkedLocations.EVENT_BUS.post(new INetworkedUnloadedEvent(this, pos)); + } + } + + public void onEntityLoad() { + if (this instanceof INetworked && getLevel() != null && !getLevel().isClientSide()) { + BlockPos ourPos = getBlockPos(); + ModINetworkedLocations.EVENT_BUS.post(new INetworkedLoadedEvent(this, ourPos)); + } + } + public boolean hasDataPacket () { return true; } diff --git a/common/src/main/java/com/jaquadro/minecraft/storagedrawers/block/tile/BlockEntityController.java b/common/src/main/java/com/jaquadro/minecraft/storagedrawers/block/tile/BlockEntityController.java index a57952843..f118b8536 100644 --- a/common/src/main/java/com/jaquadro/minecraft/storagedrawers/block/tile/BlockEntityController.java +++ b/common/src/main/java/com/jaquadro/minecraft/storagedrawers/block/tile/BlockEntityController.java @@ -2,6 +2,7 @@ import com.jaquadro.minecraft.storagedrawers.ModServices; import com.jaquadro.minecraft.storagedrawers.api.capabilities.IItemRepository; +import com.jaquadro.minecraft.storagedrawers.api.event.INetworkedUnloadedEvent; import com.jaquadro.minecraft.storagedrawers.api.framing.IFramedBlockEntity; import com.jaquadro.minecraft.storagedrawers.api.security.ISecurityProvider; import com.jaquadro.minecraft.storagedrawers.api.storage.*; @@ -17,7 +18,7 @@ import com.jaquadro.minecraft.storagedrawers.capabilities.DrawerItemRepository; import com.jaquadro.minecraft.storagedrawers.config.ModCommonConfig; import com.jaquadro.minecraft.storagedrawers.core.ModBlockEntities; -import com.jaquadro.minecraft.storagedrawers.core.ModBlocks; +import com.jaquadro.minecraft.storagedrawers.core.ModINetworkedLocations; import com.jaquadro.minecraft.storagedrawers.security.SecurityManager; import com.jaquadro.minecraft.storagedrawers.storage.StorageUtil; import com.jaquadro.minecraft.storagedrawers.util.ItemCollectionRegistry; @@ -25,8 +26,6 @@ import com.mojang.authlib.GameProfile; import com.texelsaurus.minecraft.chameleon.capabilities.ChameleonCapability; import net.minecraft.core.BlockPos; -import net.minecraft.core.HolderLookup; -import net.minecraft.nbt.CompoundTag; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; @@ -117,8 +116,6 @@ public int compareTo (SlotRecord other) { } } - private final Queue searchQueue = new LinkedList<>(); - private final Set searchDiscovered = new HashSet<>(); private final Comparator slotRecordComparator = (o1, o2) -> { if (o1.priorityGroup != o2.priorityGroup) return o2.priorityGroup - o1.priorityGroup; @@ -298,10 +295,12 @@ public boolean isSoftBindingValid (BlockPos pos, IDrawerGroup node) { return record.storage == node; } + @Override public void onEntityLoad () { if (ModCommonConfig.INSTANCE.GENERAL.debugTrace.get()) ModServices.log.info("controller [{}] onEntityLoad", worldPosition); + super.onEntityLoad(); if (getLevel() == null || getLevel().isClientSide()) return; @@ -753,9 +752,6 @@ private void populateNodes () { if (getLevel() == null) return; - searchQueue.clear(); - searchDiscovered.clear(); - if (!getLevel().isClientSide()) controllerHostData.validateRemoteNodes(this, level); @@ -766,33 +762,33 @@ private void populateNodes () { int remoteRange = confRemoteRange > 0 ? Math.min(globalRange, confRemoteRange) : globalRange; int remoteGroupRange = confRemoteGroupRange > 0 ? Math.min(globalRange, confRemoteGroupRange) : globalRange; - populateRoot(getBlockPos(), globalRange, true); + populateRoot(getBlockPos(), globalRange); getBoundRemoteNodes().forEach(n -> { if (n.getBoundControlGroup() == this && n instanceof BlockEntity blockEntity) { boolean recurse = n.canRecurseSearch(); int range = recurse ? remoteGroupRange : remoteRange; - populateRoot(blockEntity.getBlockPos(), range, recurse); + populateRoot(blockEntity.getBlockPos(), range); } }); } - private void populateRoot (BlockPos root, int range, boolean recursiveSearch) { - searchQueue.add(root); - searchDiscovered.add(root); + private void populateRoot (BlockPos root, int range) { BlockPos origin = getBlockPos(); - while (!searchQueue.isEmpty()) { - BlockPos coord = searchQueue.remove(); - int depth = Math.max(Math.max(Math.abs(coord.getX() - origin.getX()), Math.abs(coord.getY() - origin.getY())), Math.abs(coord.getZ() - origin.getZ())); - if (depth > range) - continue; + // Ask for the drawer locations that are in range + if (ModCommonConfig.INSTANCE.GENERAL.debugTrace.get()) + ModServices.log.info("Controller [{}] searching for drawers in range {}", origin, range); - if (!getLevel().isLoaded(coord)) + var networkedThingsInRange = ModINetworkedLocations.getINetworkedLocationsInRange(origin, range); + if (ModCommonConfig.INSTANCE.GENERAL.debugTrace.get()) + ModServices.log.info("Controller [{}] found {} drawers in range", origin, networkedThingsInRange.size()); + for (var pos: networkedThingsInRange) { + if (!getLevel().isLoaded(pos)) continue; - Block block = getLevel().getBlockState(coord).getBlock(); + Block block = getLevel().getBlockState(pos).getBlock(); if (block instanceof INetworked networked) { IControlGroup group = networked.getBoundControlGroup(); if (group != null && group != this) @@ -800,32 +796,19 @@ private void populateRoot (BlockPos root, int range, boolean recursiveSearch) { } else continue; - StorageRecord record = storage.get(coord); + StorageRecord record = storage.get(pos); if (record == null) { record = new StorageRecord(); - storage.put(coord, record); + storage.put(pos, record); } if (block instanceof BlockControllerIO) { - WorldUtils.getBlockEntity(getLevel(), coord, BlockEntityControllerIO.class); + WorldUtils.getBlockEntity(getLevel(), pos, BlockEntityControllerIO.class); } - updateRecordInfo(coord, record, getLevel().getBlockEntity(coord)); + updateRecordInfo(pos, record, getLevel().getBlockEntity(pos)); record.mark = true; - record.distance = depth; - - if (recursiveSearch) { - BlockPos[] neighbors = new BlockPos[]{ - coord.west(), coord.east(), coord.south(), coord.north(), coord.above(), coord.below() - }; - - for (BlockPos n : neighbors) { - if (!searchDiscovered.contains(n)) { - searchQueue.add(n); - searchDiscovered.add(n); - } - } - } + record.distance = Math.max(Math.max(Math.abs(pos.getX() - origin.getX()), Math.abs(pos.getY() - origin.getY())), Math.abs(pos.getZ() - origin.getZ())); } } diff --git a/common/src/main/java/com/jaquadro/minecraft/storagedrawers/block/tile/BlockEntityDrawers.java b/common/src/main/java/com/jaquadro/minecraft/storagedrawers/block/tile/BlockEntityDrawers.java index c4e7a154a..f716b1a29 100644 --- a/common/src/main/java/com/jaquadro/minecraft/storagedrawers/block/tile/BlockEntityDrawers.java +++ b/common/src/main/java/com/jaquadro/minecraft/storagedrawers/block/tile/BlockEntityDrawers.java @@ -1,6 +1,7 @@ package com.jaquadro.minecraft.storagedrawers.block.tile; import com.jaquadro.minecraft.storagedrawers.ModServices; +import com.jaquadro.minecraft.storagedrawers.api.event.*; import com.jaquadro.minecraft.storagedrawers.api.framing.IFramedBlockEntity; import com.jaquadro.minecraft.storagedrawers.api.security.ISecurityProvider; import com.jaquadro.minecraft.storagedrawers.api.storage.*; @@ -11,7 +12,6 @@ import com.jaquadro.minecraft.storagedrawers.block.tile.modelprops.DrawerModelProperties; import com.jaquadro.minecraft.storagedrawers.block.tile.modelprops.RenderDataProvider; import com.jaquadro.minecraft.storagedrawers.block.tile.tiledata.ControllerData; -import com.jaquadro.minecraft.storagedrawers.block.tile.tiledata.DetachedDrawerData; import com.jaquadro.minecraft.storagedrawers.block.tile.tiledata.MaterialData; import com.jaquadro.minecraft.storagedrawers.block.tile.tiledata.UpgradeData; import com.jaquadro.minecraft.storagedrawers.capabilities.BasicDrawerAttributes; @@ -19,6 +19,7 @@ import com.jaquadro.minecraft.storagedrawers.components.item.DetachedDrawerContents; import com.jaquadro.minecraft.storagedrawers.config.ModCommonConfig; import com.jaquadro.minecraft.storagedrawers.core.ModDataComponents; +import com.jaquadro.minecraft.storagedrawers.core.ModINetworkedLocations; import com.jaquadro.minecraft.storagedrawers.core.ModItems; import com.jaquadro.minecraft.storagedrawers.core.ModSecurity; import com.jaquadro.minecraft.storagedrawers.inventory.*; @@ -33,18 +34,15 @@ import com.texelsaurus.minecraft.chameleon.inventory.content.PositionContent; import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; -import net.minecraft.core.HolderLookup; import net.minecraft.core.Vec3i; import net.minecraft.core.component.DataComponentGetter; import net.minecraft.core.component.DataComponentMap; import net.minecraft.core.component.DataComponents; -import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.ComponentSerialization; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.tags.BlockTags; -import net.minecraft.util.ProblemReporter; import net.minecraft.world.Nameable; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntitySelector; @@ -53,14 +51,12 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.component.CustomData; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.levelgen.structure.BoundingBox; -import net.minecraft.world.level.storage.TagValueInput; import net.minecraft.world.level.storage.ValueInput; import net.minecraft.world.level.storage.ValueOutput; import net.minecraft.world.phys.AABB; @@ -71,8 +67,6 @@ import java.util.*; -import static com.ibm.icu.impl.CurrencyData.provider; - public abstract class BlockEntityDrawers extends BaseBlockEntity implements IDrawerGroup, IProtectable, INetworked, IFramedBlockEntity, Nameable, RenderDataProvider { private MaterialData materialData = new MaterialData(); @@ -266,6 +260,7 @@ public void validateBoundController() { } public void onEntityLoad () { + super.onEntityLoad(); try { if (getLevel() == null || getLevel().isClientSide()) return; diff --git a/common/src/main/java/com/jaquadro/minecraft/storagedrawers/config/ModCommonConfig.java b/common/src/main/java/com/jaquadro/minecraft/storagedrawers/config/ModCommonConfig.java index 86006740d..8b16b68c4 100644 --- a/common/src/main/java/com/jaquadro/minecraft/storagedrawers/config/ModCommonConfig.java +++ b/common/src/main/java/com/jaquadro/minecraft/storagedrawers/config/ModCommonConfig.java @@ -12,7 +12,6 @@ public final class ModCommonConfig extends ConfigSpec { public static ModCommonConfig INSTANCE = new ModCommonConfig(); - private final ChameleonConfig commonConfig; public General GENERAL; public Drawers DRAWERS; diff --git a/common/src/main/java/com/jaquadro/minecraft/storagedrawers/core/ModINetworkedLocations.java b/common/src/main/java/com/jaquadro/minecraft/storagedrawers/core/ModINetworkedLocations.java new file mode 100644 index 000000000..4261b5d45 --- /dev/null +++ b/common/src/main/java/com/jaquadro/minecraft/storagedrawers/core/ModINetworkedLocations.java @@ -0,0 +1,87 @@ +package com.jaquadro.minecraft.storagedrawers.core; + +import com.jaquadro.minecraft.storagedrawers.ModServices; +import com.jaquadro.minecraft.storagedrawers.api.event.INetworkedLoadedEvent; +import com.jaquadro.minecraft.storagedrawers.api.event.INetworkedUnloadedEvent; +import com.jaquadro.minecraft.storagedrawers.config.ModCommonConfig; +import com.jaquadro.minecraft.storagedrawers.util.GridIndex3D; +import com.texelsaurus.minecraft.chameleon.api.ChameleonInit; +import net.minecraft.core.BlockPos; +import net.neoforged.bus.api.BusBuilder; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.bus.api.SubscribeEvent; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.function.LongConsumer; + +public class ModINetworkedLocations { + public static final IEventBus EVENT_BUS = BusBuilder.builder().build(); + + // While server is technically single threaded, these days there are fewer and fewer guarantees + // about threading. As it's totally conceivable that the event bus or other things will not be on the same + // thread querying the locations, and the locking is very inexpensive, we just do read/write locking. + private static final ReadWriteLock lock = new ReentrantReadWriteLock(); + private static final Lock writeLock = lock.writeLock(); + private static final Lock readLock = lock.readLock(); + + private static final GridIndex3D INetworkedLocationsGrid = new GridIndex3D(); + + public static void init(ChameleonInit.InitContext ignoredContext) { + if (ModCommonConfig.INSTANCE.GENERAL.debugTrace.get()) + ModServices.log.info("Registering INetworked location events"); + EVENT_BUS.register(ModINetworkedLocations.class); + } + + // Unloads happen either from block removal or chunk unloading. + // We don't actually care which because we don't transfer or count items in unloaded drawers + @SubscribeEvent + private static void drawerUnloadHandler(INetworkedUnloadedEvent event) { + if (ModCommonConfig.INSTANCE.GENERAL.debugTrace.get()) + ModServices.log.info("INetworked of kind {} unloaded at position: {}", event.getEntity().getClass().toString(), event.getPos()); + BlockPos pos = event.getPos(); + writeLock.lock(); + try { + if (!INetworkedLocationsGrid.remove(pos)) + ModServices.log.error("Failed to remove INetworked at position: {}", pos); + if (ModCommonConfig.INSTANCE.GENERAL.debugTrace.get()) + ModServices.log.info("Removed INetworked at position: {}", pos); + } finally { + writeLock.unlock(); + } + } + + // Loads happen from either placement or chunk loading. + // + @SubscribeEvent + private static void drawerLoadHandler(INetworkedLoadedEvent event) { + if (ModCommonConfig.INSTANCE.GENERAL.debugTrace.get()) + ModServices.log.info("INetworked of kind {} loaded at position: {}", event.getEntity().getClass().toString(), event.getPos()); + BlockPos pos = event.getPos(); + writeLock.lock(); + try { + INetworkedLocationsGrid.add(pos); + ModServices.log.info("Inserted INetworked at position: {}", pos); + } finally { + writeLock.unlock(); + } + } + + public static List getINetworkedLocationsInRange(BlockPos center, int range) { + readLock.lock(); + try { + // We use a sphere to match how the search was done before. + if (ModCommonConfig.INSTANCE.GENERAL.debugTrace.get()) + ModServices.log.info("Querying for INetworked locations within range {} at position {}", range, center); + var gridResults = new ArrayList(); + LongConsumer c = v -> gridResults.add(BlockPos.of(v)); + INetworkedLocationsGrid.querySphere(center, range, c); + return gridResults; + } finally { + readLock.unlock(); + } + } +} diff --git a/common/src/main/java/com/jaquadro/minecraft/storagedrawers/util/GridIndex3D.java b/common/src/main/java/com/jaquadro/minecraft/storagedrawers/util/GridIndex3D.java new file mode 100644 index 000000000..b404dfccd --- /dev/null +++ b/common/src/main/java/com/jaquadro/minecraft/storagedrawers/util/GridIndex3D.java @@ -0,0 +1,141 @@ +package com.jaquadro.minecraft.storagedrawers.util; + +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.longs.LongArrayList; +import net.minecraft.core.BlockPos; +import net.minecraft.core.SectionPos; + +import java.util.function.LongConsumer; + +public final class GridIndex3D { + // Map cellKey -> bucket of packed BlockPos longs + private final Long2ObjectOpenHashMap buckets = new Long2ObjectOpenHashMap<>(); + + private static boolean sphereIntersectsAabb(BlockPos center, long r2, int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { + + // This is the standard branchless sphere intersection test. + // If we wanted to know if the sphere is contained within the box, we only would have to check if the + // center + radius is inside the box in each axis. + // For intersection, we need to test overlap, and it's possible for the center to be outside the box, + // but the sphere to still overlap the box. + // So we compute how far it is from the sphere center to the nearest point on the boundary. + // If the center is in the box, it will end up contributing nothing to the distance (dx,dy,dz) because the + // clamped point will be the center. + // If it isn't, it will contribute how far away from the box boundary it is, and we know they still overlap + // if the distance is less than the radius squared + int qx = Math.clamp(center.getX(), minX, maxX); + int qy = Math.clamp(center.getY(), minY, maxY); + int qz = Math.clamp(center.getZ(), minZ, maxZ); + + int dx = center.getX() - qx; + int dy = center.getY() - qy; + int dz = center.getZ() - qz; + + // The + long d2 = (long) dx * dx + (long) dy * dy + (long) dz * dz; + return d2 <= r2; + } + + public void add(BlockPos pos) { + var sectionPos = SectionPos.of(pos); + + long key = sectionPos.asLong(); + LongArrayList list = buckets.get(key); + if (list == null) { + list = new LongArrayList(); + buckets.put(key, list); + } + list.add(pos.asLong()); + } + + public boolean remove(BlockPos pos) { + var packedBlockPos = pos.asLong(); + var sectionPos = SectionPos.of(pos); + + long key = sectionPos.asLong(); + LongArrayList list = buckets.get(key); + if (list == null) return false; + + // Remove can be made O(1) with a side-index, but we aren't loading/unloading chunks + // fast enough to be a big deal here. Queries are much more common. + for (int i = 0; i < list.size(); i++) { + if (list.getLong(i) == packedBlockPos) { + int last = list.size() - 1; + list.set(i, list.getLong(last)); + list.removeLong(last); + if (list.isEmpty()) buckets.remove(key); + return true; + } + } + return false; + } + + public void querySphere(BlockPos center, int radius, LongConsumer found) { + long r2 = (long) radius * (long) radius; + + // Compute block-space bounds, then section-space bounds + int minX = center.getX() - radius; + int maxX = center.getX() + radius; + int minY = center.getY() - radius; + int maxY = center.getY() + radius; + int minZ = center.getZ() - radius; + int maxZ = center.getZ() + radius; + + int cellCoordMinX = SectionPos.blockToSectionCoord(minX); + int cellCoordMaxX = SectionPos.blockToSectionCoord(maxX); + int cellCoordMinY = SectionPos.blockToSectionCoord(minY); + int cellCoordMaxY = SectionPos.blockToSectionCoord(maxY); + int cellCoordMinZ = SectionPos.blockToSectionCoord(minZ); + int cellCoordMaxZ = SectionPos.blockToSectionCoord(maxZ); + + // This triple-nested loop is only iterating over cells. Most cells will be eliminated. + // It seems expensive but is not, as it will only look at chunks that are in range + // and will eliminate almost all chunks very quickly without looking at any points + // inside them. + // The expensive tests are actually the per-point tests, which we minimize. + // If we wanted to maximize speed but make it less general, + // we could simply only scan the chunks that are loaded only, etc. + + for (int cx = cellCoordMinX; cx <= cellCoordMaxX; cx++) { + int cellMinX = SectionPos.sectionToBlockCoord(cx); + int cellMaxX = cellMinX + SectionPos.SECTION_MAX_INDEX; + + for (int cy = cellCoordMinY; cy <= cellCoordMaxY; cy++) { + int cellMinY = SectionPos.sectionToBlockCoord(cy); + int cellMaxY = cellMinY + SectionPos.SECTION_MAX_INDEX; + + for (int cz = cellCoordMinZ; cz <= cellCoordMaxZ; cz++) { + long key = SectionPos.of(cx, cy, cz).asLong(); + LongArrayList list = buckets.get(key); + if (list == null) continue; + + int cellMinZ = SectionPos.sectionToBlockCoord(cz); + int cellMaxZ = cellMinZ + SectionPos.SECTION_MAX_INDEX; + + // Sphere-AABB prune against the cell bounds + if (!sphereIntersectsAabb(center, r2, cellMinX, cellMinY, cellMinZ, cellMaxX, cellMaxY, cellMaxZ)) { + continue; + } + + // Scan bucket points, check if within radius + for (int i = 0; i < list.size(); i++) { + long p = list.getLong(i); + int x = BlockPos.getX(p); + int y = BlockPos.getY(p); + int z = BlockPos.getZ(p); + + int dx = x - center.getX(); + int dy = y - center.getY(); + int dz = z - center.getZ(); + + long d2 = (long) dx * dx + (long) dy * dy + (long) dz * dz; + if (d2 <= r2) { + found.accept(p); + } + } + } + } + } + } + +} diff --git a/fabric/build.gradle.kts b/fabric/build.gradle.kts index b1ce624af..9677419ec 100644 --- a/fabric/build.gradle.kts +++ b/fabric/build.gradle.kts @@ -5,7 +5,7 @@ import net.darkhax.curseforgegradle.Constants as CFG_Constants plugins { id("modloader-conv") - id("fabric-loom") version "1.11.7" + id("fabric-loom") version "1.13.6" id("com.modrinth.minotaur") } @@ -16,6 +16,7 @@ dependencies { modImplementation("net.fabricmc.fabric-api:fabric-api:${Versions.fabric}") modCompileOnly("fuzs.forgeconfigapiport:forgeconfigapiport-fabric:21.9.6") + include("net.neoforged:bus:8.0.5") //modCompileOnlyApi("mezz.jei:jei-${Versions.minecraft}-fabric-api:19.8.2.99") //modRuntimeOnly("mezz.jei:jei-${Versions.minecraft}-fabric:19.8.2.99") @@ -69,4 +70,4 @@ modrinth { optional.project("forge-config-api-port") } } -tasks.modrinth.get().dependsOn(tasks.remapJar) \ No newline at end of file +tasks.modrinth.get().dependsOn(tasks.remapJar) diff --git a/fabric/src/main/java/com/jaquadro/minecraft/storagedrawers/StorageDrawers.java b/fabric/src/main/java/com/jaquadro/minecraft/storagedrawers/StorageDrawers.java index c22e751fd..5a82f175c 100644 --- a/fabric/src/main/java/com/jaquadro/minecraft/storagedrawers/StorageDrawers.java +++ b/fabric/src/main/java/com/jaquadro/minecraft/storagedrawers/StorageDrawers.java @@ -28,6 +28,7 @@ public void onInitialize () { ModContainers.init(context); ModDataComponents.init(context); ModRecipes.init(context); + ModINetworkedLocations.init(context); ModNetworking.INSTANCE.init(context); CommonEvents.init(); diff --git a/fabric/src/main/java/com/jaquadro/minecraft/storagedrawers/core/CommonEvents.java b/fabric/src/main/java/com/jaquadro/minecraft/storagedrawers/core/CommonEvents.java index 8d2f205a6..5c7786fb8 100644 --- a/fabric/src/main/java/com/jaquadro/minecraft/storagedrawers/core/CommonEvents.java +++ b/fabric/src/main/java/com/jaquadro/minecraft/storagedrawers/core/CommonEvents.java @@ -1,6 +1,8 @@ package com.jaquadro.minecraft.storagedrawers.core; +import com.jaquadro.minecraft.storagedrawers.api.storage.INetworked; import com.jaquadro.minecraft.storagedrawers.block.BlockDrawers; +import com.jaquadro.minecraft.storagedrawers.block.tile.BaseBlockEntity; import com.jaquadro.minecraft.storagedrawers.block.tile.BlockEntityController; import com.jaquadro.minecraft.storagedrawers.block.tile.BlockEntityDrawers; import com.texelsaurus.minecraft.chameleon.util.WorldUtils; @@ -39,10 +41,9 @@ public static void init () { }); ServerBlockEntityEvents.BLOCK_ENTITY_LOAD.register((blockEntity, world) -> { - if (blockEntity instanceof BlockEntityController controller) - controller.onEntityLoad(); - else if (blockEntity instanceof BlockEntityDrawers drawers) - drawers.onEntityLoad(); + if (blockEntity instanceof BaseBlockEntity bbe) { + bbe.onEntityLoad(); + } }); /*UseBlockCallback.EVENT.register((player, world, hand, hitResult) -> { diff --git a/forge/build.gradle.kts b/forge/build.gradle.kts index c07291386..e73411755 100644 --- a/forge/build.gradle.kts +++ b/forge/build.gradle.kts @@ -53,6 +53,7 @@ dependencies { annotationProcessor("org.spongepowered:mixin:0.8.5-SNAPSHOT:processor") // annotationProcessor("net.minecraftforge:eventbus-validator:7.0-beta.7") implementation("net.sf.jopt-simple:jopt-simple:5.0.4") { version { strictly("5.0.4") } } + implementation("net.neoforged:bus:8.0.5") // JEI //runtimeOnly("mezz.jei:jei-1.21-forge:19.8.2.99") @@ -92,4 +93,4 @@ modrinth { uploadFile.set(tasks.jar.get()) loaders.add("forge") } -tasks.modrinth.get().dependsOn(tasks.jar) \ No newline at end of file +tasks.modrinth.get().dependsOn(tasks.jar) diff --git a/neoforge/src/main/java/com/jaquadro/minecraft/storagedrawers/StorageDrawers.java b/neoforge/src/main/java/com/jaquadro/minecraft/storagedrawers/StorageDrawers.java index af94cddf2..369da768e 100644 --- a/neoforge/src/main/java/com/jaquadro/minecraft/storagedrawers/StorageDrawers.java +++ b/neoforge/src/main/java/com/jaquadro/minecraft/storagedrawers/StorageDrawers.java @@ -59,6 +59,7 @@ public StorageDrawers (ModContainer modContainer, IEventBus modEventBus) { ModContainers.init(regContext); ModDataComponents.init(regContext); ModRecipes.init(regContext); + ModINetworkedLocations.init(regContext); modEventBus.addListener(this::setup); //modEventBus.addListener(MessageHandler::register);