diff --git a/src/main/java/li/cil/oc2/common/bus/BlockEntityDeviceBusController.java b/src/main/java/li/cil/oc2/common/bus/BlockEntityDeviceBusController.java index 484b477e..41658f8e 100644 --- a/src/main/java/li/cil/oc2/common/bus/BlockEntityDeviceBusController.java +++ b/src/main/java/li/cil/oc2/common/bus/BlockEntityDeviceBusController.java @@ -4,23 +4,21 @@ package li.cil.oc2.common.bus; import li.cil.oc2.api.bus.BlockDeviceBusElement; import li.cil.oc2.api.bus.DeviceBusElement; +import li.cil.oc2.common.util.ChunkLocation; import li.cil.oc2.common.util.ChunkUtils; import li.cil.oc2.common.util.ServerScheduler; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; -import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.block.entity.BlockEntity; -import java.lang.ref.WeakReference; import java.util.Collection; import java.util.HashSet; -import java.util.Optional; public final class BlockEntityDeviceBusController extends CommonDeviceBusController { private final Runnable onBusChunkLoadedStateChanged = this::scheduleBusScan; - private final HashSet trackedChunks = new HashSet<>(); + private final HashSet trackedChunks = new HashSet<>(); private final BlockEntity blockEntity; /////////////////////////////////////////////////////////////////// @@ -35,10 +33,9 @@ public final class BlockEntityDeviceBusController extends CommonDeviceBusControl @Override public void setDeviceContainersChanged() { super.setDeviceContainersChanged(); - for (final TrackedChunk trackedChunk : trackedChunks) { - trackedChunk.tryGetLevel().ifPresent(level -> { - ChunkUtils.setLazyUnsaved(level, trackedChunk.position()); - }); + for (final ChunkLocation trackedChunk : trackedChunks) { + trackedChunk.tryGetLevel().ifPresent(level -> + ChunkUtils.setLazyUnsaved(level, trackedChunk.position())); } } @@ -61,30 +58,30 @@ public final class BlockEntityDeviceBusController extends CommonDeviceBusControl return; } - final HashSet newTrackedChunks = new HashSet<>(); + final HashSet newTrackedChunks = new HashSet<>(); for (final DeviceBusElement element : getElements()) { if (element instanceof final BlockDeviceBusElement blockElement) { final LevelAccessor elementLevel = blockElement.getLevel(); final BlockPos elementPosition = blockElement.getPosition(); if (elementLevel != null) { - newTrackedChunks.add(TrackedChunk.of(elementLevel, elementPosition)); - newTrackedChunks.add(TrackedChunk.of(elementLevel, elementPosition.relative(Direction.NORTH))); - newTrackedChunks.add(TrackedChunk.of(elementLevel, elementPosition.relative(Direction.EAST))); - newTrackedChunks.add(TrackedChunk.of(elementLevel, elementPosition.relative(Direction.SOUTH))); - newTrackedChunks.add(TrackedChunk.of(elementLevel, elementPosition.relative(Direction.WEST))); + newTrackedChunks.add(ChunkLocation.of(elementLevel, elementPosition)); + newTrackedChunks.add(ChunkLocation.of(elementLevel, elementPosition.relative(Direction.NORTH))); + newTrackedChunks.add(ChunkLocation.of(elementLevel, elementPosition.relative(Direction.EAST))); + newTrackedChunks.add(ChunkLocation.of(elementLevel, elementPosition.relative(Direction.SOUTH))); + newTrackedChunks.add(ChunkLocation.of(elementLevel, elementPosition.relative(Direction.WEST))); } } } // Do not track the chunk the controller itself is in -- this is unneeded because // we expect the controller to be disposed if its chunk is unloaded. - newTrackedChunks.remove(TrackedChunk.of(level, blockEntity.getBlockPos())); + newTrackedChunks.remove(ChunkLocation.of(level, blockEntity.getBlockPos())); - final HashSet removedChunks = new HashSet<>(trackedChunks); + final HashSet removedChunks = new HashSet<>(trackedChunks); removedChunks.removeAll(newTrackedChunks); removeListeners(removedChunks); - final HashSet addedChunks = new HashSet<>(newTrackedChunks); + final HashSet addedChunks = new HashSet<>(newTrackedChunks); newTrackedChunks.removeAll(trackedChunks); addListeners(addedChunks); @@ -94,31 +91,21 @@ public final class BlockEntityDeviceBusController extends CommonDeviceBusControl /////////////////////////////////////////////////////////////////// - private void addListeners(final Collection trackedChunks) { - for (final TrackedChunk trackedChunk : trackedChunks) { + private void addListeners(final Collection trackedChunks) { + for (final ChunkLocation trackedChunk : trackedChunks) { trackedChunk.tryGetLevel().ifPresent(level -> { - ServerScheduler.scheduleOnLoad(level, trackedChunk.position, onBusChunkLoadedStateChanged); - ServerScheduler.scheduleOnUnload(level, trackedChunk.position, onBusChunkLoadedStateChanged); + ServerScheduler.scheduleOnLoad(level, trackedChunk.position(), onBusChunkLoadedStateChanged); + ServerScheduler.scheduleOnUnload(level, trackedChunk.position(), onBusChunkLoadedStateChanged); }); } } - private void removeListeners(final Collection trackedChunks) { - for (final TrackedChunk trackedChunk : trackedChunks) { + private void removeListeners(final Collection trackedChunks) { + for (final ChunkLocation trackedChunk : trackedChunks) { trackedChunk.tryGetLevel().ifPresent(level -> { - ServerScheduler.cancelOnLoad(level, trackedChunk.position, onBusChunkLoadedStateChanged); - ServerScheduler.cancelOnUnload(level, trackedChunk.position, onBusChunkLoadedStateChanged); + ServerScheduler.cancelOnLoad(level, trackedChunk.position(), onBusChunkLoadedStateChanged); + ServerScheduler.cancelOnUnload(level, trackedChunk.position(), onBusChunkLoadedStateChanged); }); } } - - private record TrackedChunk(WeakReference level, ChunkPos position) { - public static TrackedChunk of(final LevelAccessor level, final BlockPos position) { - return new TrackedChunk(new WeakReference<>(level), new ChunkPos(position)); - } - - public Optional tryGetLevel() { - return Optional.ofNullable(level.get()); - } - } } diff --git a/src/main/java/li/cil/oc2/common/bus/device/rpc/item/SoundCardItemDevice.java b/src/main/java/li/cil/oc2/common/bus/device/rpc/item/SoundCardItemDevice.java index d82aedf9..61846725 100644 --- a/src/main/java/li/cil/oc2/common/bus/device/rpc/item/SoundCardItemDevice.java +++ b/src/main/java/li/cil/oc2/common/bus/device/rpc/item/SoundCardItemDevice.java @@ -4,14 +4,13 @@ package li.cil.oc2.common.bus.device.rpc.item; import li.cil.oc2.api.bus.device.object.Callback; import li.cil.oc2.api.bus.device.object.Parameter; -import li.cil.oc2.common.util.Location; +import li.cil.oc2.common.util.BlockLocation; import li.cil.oc2.common.util.TickUtils; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundSource; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.LevelAccessor; import net.minecraftforge.registries.ForgeRegistries; import javax.annotation.Nullable; @@ -27,12 +26,12 @@ public final class SoundCardItemDevice extends AbstractItemRPCDevice { /////////////////////////////////////////////////////////////////// - private final Supplier> location; + private final Supplier> location; private long gameTimeCooldownExpiresAt; /////////////////////////////////////////////////////////////////// - public SoundCardItemDevice(final ItemStack identity, final Supplier> location) { + public SoundCardItemDevice(final ItemStack identity, final Supplier> location) { super(identity, "sound"); this.location = location; } @@ -43,8 +42,7 @@ public final class SoundCardItemDevice extends AbstractItemRPCDevice { public void playSound(@Nullable @Parameter("name") final String name) { if (name == null) throw new IllegalArgumentException(); - location.get().ifPresent(location -> { - final LevelAccessor level = location.level(); + location.get().ifPresent(location -> location.tryGetLevel().ifPresent(level -> { if (!(level instanceof final ServerLevel serverLevel)) { return; } @@ -58,8 +56,8 @@ public final class SoundCardItemDevice extends AbstractItemRPCDevice { final SoundEvent soundEvent = ForgeRegistries.SOUND_EVENTS.getValue(new ResourceLocation(name)); if (soundEvent == null) throw new IllegalArgumentException("Sound not found."); - level.playSound(null, location.pos(), soundEvent, SoundSource.BLOCKS, 1, 1); - }); + level.playSound(null, location.blockPos(), soundEvent, SoundSource.BLOCKS, 1, 1); + })); } @Callback diff --git a/src/main/java/li/cil/oc2/common/bus/device/vm/item/HardDriveDevice.java b/src/main/java/li/cil/oc2/common/bus/device/vm/item/HardDriveDevice.java index 7ab2d570..9fabae4f 100644 --- a/src/main/java/li/cil/oc2/common/bus/device/vm/item/HardDriveDevice.java +++ b/src/main/java/li/cil/oc2/common/bus/device/vm/item/HardDriveDevice.java @@ -3,7 +3,7 @@ package li.cil.oc2.common.bus.device.vm.item; import li.cil.oc2.common.serialization.BlobStorage; -import li.cil.oc2.common.util.Location; +import li.cil.oc2.common.util.BlockLocation; import li.cil.oc2.common.util.SoundEvents; import li.cil.oc2.common.util.ThrottledSoundEmitter; import li.cil.sedna.device.block.ByteBufferBlockDevice; @@ -23,7 +23,7 @@ public class HardDriveDevice extends AbstractBlockStorageDevice> location) { + public HardDriveDevice(final ItemStack identity, final int size, final boolean readonly, final Supplier> location) { super(identity, readonly); this.size = size; this.soundEmitter = new ThrottledSoundEmitter(location, SoundEvents.HDD_ACCESS.get()) diff --git a/src/main/java/li/cil/oc2/common/bus/device/vm/item/HardDriveDeviceWithInitialData.java b/src/main/java/li/cil/oc2/common/bus/device/vm/item/HardDriveDeviceWithInitialData.java index 204de23b..4c405b6b 100644 --- a/src/main/java/li/cil/oc2/common/bus/device/vm/item/HardDriveDeviceWithInitialData.java +++ b/src/main/java/li/cil/oc2/common/bus/device/vm/item/HardDriveDeviceWithInitialData.java @@ -3,7 +3,7 @@ package li.cil.oc2.common.bus.device.vm.item; import com.google.common.io.ByteStreams; -import li.cil.oc2.common.util.Location; +import li.cil.oc2.common.util.BlockLocation; import li.cil.sedna.api.device.BlockDevice; import li.cil.sedna.device.block.ByteBufferBlockDevice; import net.minecraft.world.item.ItemStack; @@ -20,7 +20,7 @@ public final class HardDriveDeviceWithInitialData extends HardDriveDevice { /////////////////////////////////////////////////////////////////// - public HardDriveDeviceWithInitialData(final ItemStack identity, final BlockDevice base, final boolean readonly, final Supplier> location) { + public HardDriveDeviceWithInitialData(final ItemStack identity, final BlockDevice base, final boolean readonly, final Supplier> location) { super(identity, (int) base.getCapacity(), readonly, location); this.base = base; } diff --git a/src/main/java/li/cil/oc2/common/util/BlockLocation.java b/src/main/java/li/cil/oc2/common/util/BlockLocation.java new file mode 100644 index 00000000..c57f5500 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/util/BlockLocation.java @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: MIT */ + +package li.cil.oc2.common.util; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.entity.BlockEntity; + +import java.lang.ref.WeakReference; +import java.util.Objects; +import java.util.Optional; + +public record BlockLocation(WeakReference level, BlockPos blockPos) { + public static Optional of(final Entity entity) { + if (entity.isAlive()) { + return Optional.of(new BlockLocation(new WeakReference<>(entity.level), entity.blockPosition())); + } else { + return Optional.empty(); + } + } + + public static Optional of(final BlockEntity blockEntity) { + if (!blockEntity.isRemoved()) { + return Optional.of(new BlockLocation(new WeakReference<>(blockEntity.getLevel()), blockEntity.getBlockPos())); + } else { + return Optional.empty(); + } + } + + public Optional tryGetLevel() { + return Optional.ofNullable(level.get()); + } + + @Override + public boolean equals(final Object obj) { + if (obj instanceof BlockLocation that) { + final LevelAccessor thisLevel = level.get(); + final LevelAccessor thatLevel = that.level.get(); + return Objects.equals(thisLevel, thatLevel) && Objects.equals(blockPos, that.blockPos); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(level.get(), blockPos); + } +} diff --git a/src/main/java/li/cil/oc2/common/util/ChunkLocation.java b/src/main/java/li/cil/oc2/common/util/ChunkLocation.java new file mode 100644 index 00000000..78ed25a7 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/util/ChunkLocation.java @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: MIT */ + +package li.cil.oc2.common.util; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelAccessor; + +import java.lang.ref.WeakReference; +import java.util.Objects; +import java.util.Optional; + +public record ChunkLocation(WeakReference level, ChunkPos position) { + public static ChunkLocation of(final LevelAccessor level, final BlockPos position) { + return new ChunkLocation(new WeakReference<>(level), new ChunkPos(position)); + } + + public static ChunkLocation of(final LevelAccessor level, final ChunkPos position) { + return new ChunkLocation(new WeakReference<>(level), position); + } + + public Optional tryGetLevel() { + return Optional.ofNullable(level.get()); + } + + @Override + public boolean equals(final Object obj) { + if (obj instanceof ChunkLocation that) { + final LevelAccessor thisLevel = level.get(); + final LevelAccessor thatLevel = that.level.get(); + return Objects.equals(thisLevel, thatLevel) && Objects.equals(position, that.position); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(level.get(), position); + } +} diff --git a/src/main/java/li/cil/oc2/common/util/Location.java b/src/main/java/li/cil/oc2/common/util/Location.java deleted file mode 100644 index 7d9768e4..00000000 --- a/src/main/java/li/cil/oc2/common/util/Location.java +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: MIT */ - -package li.cil.oc2.common.util; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.block.entity.BlockEntity; - -import java.util.Objects; -import java.util.Optional; - -public record Location(LevelAccessor level, BlockPos pos) { - public static Optional of(final Entity entity) { - if (entity.isAlive()) { - return Optional.of(new Location(entity.level, entity.blockPosition())); - } else { - return Optional.empty(); - } - } - - public static Optional of(final BlockEntity blockEntity) { - if (!blockEntity.isRemoved()) { - return Optional.of(new Location(Objects.requireNonNull(blockEntity.getLevel()), blockEntity.getBlockPos())); - } else { - return Optional.empty(); - } - } -} diff --git a/src/main/java/li/cil/oc2/common/util/LocationSupplierUtils.java b/src/main/java/li/cil/oc2/common/util/LocationSupplierUtils.java index 19a97d0b..246a5218 100644 --- a/src/main/java/li/cil/oc2/common/util/LocationSupplierUtils.java +++ b/src/main/java/li/cil/oc2/common/util/LocationSupplierUtils.java @@ -7,32 +7,33 @@ import li.cil.oc2.api.bus.device.provider.ItemDeviceQuery; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.block.entity.BlockEntity; +import java.lang.ref.WeakReference; import java.util.Optional; import java.util.function.Supplier; public final class LocationSupplierUtils { - public static Supplier> of(final BlockEntity blockEntity) { - return () -> Location.of(blockEntity); + public static Supplier> of(final BlockEntity blockEntity) { + return () -> BlockLocation.of(blockEntity); } - public static Supplier> of(final Entity entity) { - return () -> Location.of(entity); + public static Supplier> of(final Entity entity) { + return () -> BlockLocation.of(entity); } - public static Supplier> of(final BlockDeviceQuery query) { - final Optional location = Optional.of(new Location(query.getLevel(), query.getQueryPosition())); + public static Supplier> of(final BlockDeviceQuery query) { + final Optional location = Optional.of(new BlockLocation(new WeakReference<>(query.getLevel()), query.getQueryPosition())); return () -> location; } - public static Supplier> of(final ItemDeviceQuery query) { + public static Supplier> of(final ItemDeviceQuery query) { final Optional blockEntity = query.getContainerBlockEntity(); if (blockEntity.isPresent()) { - return () -> Location.of(blockEntity.get()); + return () -> BlockLocation.of(blockEntity.get()); } final Optional entity = query.getContainerEntity(); if (entity.isPresent()) { - return () -> Location.of(entity.get()); + return () -> BlockLocation.of(entity.get()); } return Optional::empty; diff --git a/src/main/java/li/cil/oc2/common/util/ServerScheduler.java b/src/main/java/li/cil/oc2/common/util/ServerScheduler.java index 4215f1b5..d0272e8a 100644 --- a/src/main/java/li/cil/oc2/common/util/ServerScheduler.java +++ b/src/main/java/li/cil/oc2/common/util/ServerScheduler.java @@ -45,7 +45,9 @@ public final class ServerScheduler { } public static void scheduleOnUnload(final LevelAccessor level, final Runnable listener) { - levelUnloadSchedulers.computeIfAbsent(level, unused -> new SimpleScheduler()).add(listener); + levelUnloadSchedulers + .computeIfAbsent(level, unused -> new SimpleScheduler()) + .add(listener); } public static void cancelOnUnload(@Nullable final LevelAccessor level, final Runnable listener) { diff --git a/src/main/java/li/cil/oc2/common/util/ThrottledSoundEmitter.java b/src/main/java/li/cil/oc2/common/util/ThrottledSoundEmitter.java index 5458c3e7..c9702c08 100644 --- a/src/main/java/li/cil/oc2/common/util/ThrottledSoundEmitter.java +++ b/src/main/java/li/cil/oc2/common/util/ThrottledSoundEmitter.java @@ -5,7 +5,6 @@ package li.cil.oc2.common.util; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundSource; import net.minecraft.util.Mth; -import net.minecraft.world.level.LevelAccessor; import java.time.Duration; import java.util.Optional; @@ -13,7 +12,7 @@ import java.util.Random; import java.util.function.Supplier; public final class ThrottledSoundEmitter { - private final Supplier> location; + private final Supplier> location; private final SoundEvent sound; private long minInterval; private SoundSource category; @@ -26,7 +25,7 @@ public final class ThrottledSoundEmitter { /////////////////////////////////////////////////////////////////// - public ThrottledSoundEmitter(final Supplier> location, final SoundEvent sound) { + public ThrottledSoundEmitter(final Supplier> location, final SoundEvent sound) { this.location = location; this.sound = sound; this.category = SoundSource.BLOCKS; @@ -39,12 +38,11 @@ public final class ThrottledSoundEmitter { final long now = System.currentTimeMillis(); if (now - lastEmittedTime > minInterval) { lastEmittedTime = now; - this.location.get().ifPresent(location -> { - final LevelAccessor level = location.level(); + this.location.get().ifPresent(location -> location.tryGetLevel().ifPresent(level -> { final float volume = sampleVolume(level.getRandom()); final float pitch = samplePitch(level.getRandom()); - LevelUtils.playSound(level, location.pos(), sound, category, volume, pitch); - }); + LevelUtils.playSound(level, location.blockPos(), sound, category, volume, pitch); + })); } }