Skip to content

Commit

Permalink
feat: portable grid disk model sync
Browse files Browse the repository at this point in the history
  • Loading branch information
raoulvdberge committed Dec 30, 2023
1 parent ecbb220 commit 552910a
Show file tree
Hide file tree
Showing 11 changed files with 286 additions and 137 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ private Set<StorageChange> initializeStorage(final int index) {

if (provider != null) {
provider.resolve(index).ifPresentOrElse(resolved -> {
cache[index] = (TypedStorage) trackState(resolved);
cache[index] = (TypedStorage) StateTrackedStorage.of(resolved, listener);
final ExposedStorage<?> relevantComposite = exposedStorages.get(resolved.storageChannelType());
results.add(new StorageChange(false, relevantComposite, cache[index].storage()));
}, () -> cache[index] = null);
Expand All @@ -106,13 +106,6 @@ private Set<StorageChange> initializeStorage(final int index) {
return results;
}

private <T> TypedStorage<T, StateTrackedStorage<T>> trackState(final TypedStorage<T, Storage<T>> resolved) {
return new TypedStorage<>(
new StateTrackedStorage<>(resolved.storage(), listener),
resolved.storageChannelType()
);
}

@SuppressWarnings({"unchecked", "rawtypes"})
private void processStorageChange(final StorageChange change) {
if (!isActive()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,25 @@

import com.refinedmods.refinedstorage2.api.network.impl.node.multistorage.MultiStorageProvider;
import com.refinedmods.refinedstorage2.api.storage.Storage;
import com.refinedmods.refinedstorage2.api.storage.StorageState;
import com.refinedmods.refinedstorage2.api.storage.TypedStorage;
import com.refinedmods.refinedstorage2.platform.api.storage.StorageContainerItem;
import com.refinedmods.refinedstorage2.platform.api.storage.StorageRepository;

import java.util.Optional;
import java.util.function.IntFunction;
import javax.annotation.Nullable;

import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.item.ItemStack;

public class DiskInventory extends SimpleContainer implements MultiStorageProvider {
private static final String TAG_DISK_STATE = "s";
private static final String TAG_DISK_ITEM_ID = "i";

private final DiskListener listener;
@Nullable
private StorageRepository storageRepository;
Expand Down Expand Up @@ -64,6 +72,42 @@ private Optional<ItemStack> validateAndGetStack(final int slot) {
return Optional.of(stack);
}

@SuppressWarnings("deprecation") // Forge deprecates registry access this way
public ListTag toSyncTag(final IntFunction<StorageState> stateProvider) {
final ListTag list = new ListTag();
for (int i = 0; i < getContainerSize(); ++i) {
final CompoundTag disk = new CompoundTag();
disk.putByte(TAG_DISK_STATE, (byte) stateProvider.apply(i).ordinal());
final ItemStack diskItem = getItem(i);
if (!diskItem.isEmpty()) {
disk.putInt(TAG_DISK_ITEM_ID, BuiltInRegistries.ITEM.getId(diskItem.getItem()));
}
list.add(disk);
}
return list;
}

@SuppressWarnings("deprecation") // Forge deprecates registry access this way
public Disk[] fromSyncTag(final ListTag list) {
final Disk[] disks = new Disk[list.size()];
for (int i = 0; i < list.size(); ++i) {
final CompoundTag diskTag = list.getCompound(i);
disks[i] = BuiltInRegistries.ITEM.getHolder(diskTag.getInt(TAG_DISK_ITEM_ID))
.map(item -> new Disk(item.value(), getState(diskTag)))
.orElse(new Disk(null, StorageState.NONE));
}
return disks;
}

private StorageState getState(final CompoundTag tag) {
final int stateOrdinal = tag.getByte(TAG_DISK_STATE);
final StorageState[] values = StorageState.values();
if (stateOrdinal < 0 || stateOrdinal >= values.length) {
return StorageState.NONE;
}
return values[stateOrdinal];
}

@FunctionalInterface
public interface DiskListener {
void onDiskChanged(int slot);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.refinedmods.refinedstorage2.platform.common.storage;

import com.refinedmods.refinedstorage2.api.storage.StateTrackedStorage;

import com.google.common.util.concurrent.RateLimiter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DiskStateChangeListener implements StateTrackedStorage.Listener {
private static final Logger LOGGER = LoggerFactory.getLogger(DiskStateChangeListener.class);

private final BlockEntity blockEntity;
private final RateLimiter rateLimiter = RateLimiter.create(1);

private boolean syncRequested;

public DiskStateChangeListener(final BlockEntity blockEntity) {
this.blockEntity = blockEntity;
}

@Override
public void onStorageStateChanged() {
syncRequested = true;
}

public void updateIfNecessary() {
if (!syncRequested) {
return;
}
if (!rateLimiter.tryAcquire()) {
return;
}
LOGGER.debug("Disk state change for block at {}", blockEntity.getBlockPos());
syncRequested = false;
immediateUpdate();
}

public void immediateUpdate() {
final Level level = blockEntity.getLevel();
if (level == null) {
return;
}
level.sendBlockUpdated(
blockEntity.getBlockPos(),
blockEntity.getBlockState(),
blockEntity.getBlockState(),
Block.UPDATE_ALL
);
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
package com.refinedmods.refinedstorage2.platform.common.storage.diskdrive;

import com.refinedmods.refinedstorage2.api.network.impl.node.multistorage.MultiStorageNetworkNode;
import com.refinedmods.refinedstorage2.api.storage.StateTrackedStorage;
import com.refinedmods.refinedstorage2.api.storage.StorageState;
import com.refinedmods.refinedstorage2.platform.api.PlatformApi;
import com.refinedmods.refinedstorage2.platform.common.Platform;
import com.refinedmods.refinedstorage2.platform.common.content.BlockEntities;
import com.refinedmods.refinedstorage2.platform.common.content.ContentNames;
import com.refinedmods.refinedstorage2.platform.common.storage.Disk;
import com.refinedmods.refinedstorage2.platform.common.storage.DiskInventory;
import com.refinedmods.refinedstorage2.platform.common.storage.DiskStateChangeListener;
import com.refinedmods.refinedstorage2.platform.common.storage.StorageConfigurationContainerImpl;
import com.refinedmods.refinedstorage2.platform.common.support.AbstractDirectionalBlock;
import com.refinedmods.refinedstorage2.platform.common.support.BlockEntityWithDrops;
Expand All @@ -20,12 +19,9 @@

import javax.annotation.Nullable;

import com.google.common.util.concurrent.RateLimiter;
import net.minecraft.core.BlockPos;
import net.minecraft.core.NonNullList;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
Expand All @@ -40,32 +36,23 @@
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class AbstractDiskDriveBlockEntity
extends AbstractRedstoneModeNetworkNodeContainerBlockEntity<MultiStorageNetworkNode>
implements BlockEntityWithDrops, StateTrackedStorage.Listener, ExtendedMenuProvider {
implements BlockEntityWithDrops, ExtendedMenuProvider {
public static final int AMOUNT_OF_DISKS = 8;

private static final Logger LOGGER = LoggerFactory.getLogger(AbstractDiskDriveBlockEntity.class);

private static final String TAG_DISK_INVENTORY = "inv";
private static final String TAG_DISKS = "states";
private static final String TAG_DISK_STATE = "s";
private static final String TAG_DISK_ITEM_ID = "i";
private static final String TAG_DISKS = "disks";

@Nullable
protected Disk[] disks;

private final DiskInventory diskInventory;
private final FilterWithFuzzyMode filter;
private final StorageConfigurationContainerImpl configContainer;
private final RateLimiter diskStateChangeRateLimiter = RateLimiter.create(1);

private boolean syncRequested;
private final DiskStateChangeListener diskStateListener = new DiskStateChangeListener(this);

protected AbstractDiskDriveBlockEntity(final BlockPos pos, final BlockState state) {
super(BlockEntities.INSTANCE.getDiskDrive(), pos, state, new MultiStorageNetworkNode(
Expand All @@ -87,7 +74,7 @@ protected AbstractDiskDriveBlockEntity(final BlockPos pos, final BlockState stat
this::getRedstoneMode,
this::setRedstoneMode
);
getNode().setListener(this);
getNode().setListener(diskStateListener);
getNode().setNormalizer(filter.createNormalizer());
}

Expand All @@ -105,20 +92,7 @@ public static Item getDisk(final CompoundTag tag, final int slot) {
}

void updateDiskStateIfNecessaryInLevel() {
if (!syncRequested) {
return;
}
if (diskStateChangeRateLimiter.tryAcquire()) {
LOGGER.debug("Disk state change for block at {}", getBlockPos());
this.syncRequested = false;
sync();
}
}

private void sync() {
if (level != null) {
level.sendBlockUpdated(worldPosition, getBlockState(), getBlockState(), Block.UPDATE_ALL);
}
diskStateListener.updateIfNecessary();
}

@Override
Expand Down Expand Up @@ -156,7 +130,7 @@ private void initialize(final Level level) {
@Override
public void activenessChanged(final boolean newActive) {
super.activenessChanged(newActive);
updateBlock();
diskStateListener.immediateUpdate();
}

@Override
Expand Down Expand Up @@ -201,50 +175,28 @@ private void onDiskChanged(final int slot) {
return;
}
getNode().onStorageChanged(slot);
updateBlock();
diskStateListener.immediateUpdate();
setChanged();
}

@Override
public void onStorageStateChanged() {
this.syncRequested = true;
}

@Override
protected void onNetworkInNodeInitialized() {
super.onNetworkInNodeInitialized();
// It's important to sync here as the initial update packet might have failed as the network
// could possibly be not initialized yet.
updateBlock();
diskStateListener.immediateUpdate();
}

@SuppressWarnings("deprecation") // Forge deprecates registry access this way
private void fromClientTag(final CompoundTag tag) {
if (!tag.contains(TAG_DISKS)) {
return;
}
final ListTag disksList = tag.getList(TAG_DISKS, Tag.TAG_COMPOUND);
disks = new Disk[disksList.size()];
for (int i = 0; i < disksList.size(); ++i) {
final CompoundTag diskTag = disksList.getCompound(i);
disks[i] = BuiltInRegistries.ITEM.getHolder(diskTag.getInt(TAG_DISK_ITEM_ID))
.map(item -> new Disk(item.value(), getState(diskTag)))
.orElse(new Disk(null, StorageState.NONE));
}
disks = diskInventory.fromSyncTag(tag.getList(TAG_DISKS, Tag.TAG_COMPOUND));
onClientDriveStateUpdated();
}

protected void onClientDriveStateUpdated() {
updateBlock();
}

private StorageState getState(final CompoundTag tag) {
final int stateOrdinal = tag.getByte(TAG_DISK_STATE);
final StorageState[] values = StorageState.values();
if (stateOrdinal < 0 || stateOrdinal >= values.length) {
return StorageState.NONE;
}
return values[stateOrdinal];
diskStateListener.immediateUpdate();
}

@Override
Expand All @@ -253,24 +205,13 @@ public Packet<ClientGamePacketListener> getUpdatePacket() {
}

@Override
@SuppressWarnings("deprecation") // Forge deprecates registry access this way
public CompoundTag getUpdateTag() {
final CompoundTag tag = new CompoundTag();
// This null check is important. #getUpdateTag() can be called before the node's network is initialized!
if (getNode().getNetwork() == null) {
return tag;
}
final ListTag disksList = new ListTag();
for (int i = 0; i < getNode().getSize(); ++i) {
final CompoundTag disk = new CompoundTag();
disk.putByte(TAG_DISK_STATE, (byte) getNode().getState(i).ordinal());
final ItemStack diskItem = diskInventory.getItem(i);
if (!diskItem.isEmpty()) {
disk.putInt(TAG_DISK_ITEM_ID, BuiltInRegistries.ITEM.getId(diskItem.getItem()));
}
disksList.add(disk);
}
tag.put(TAG_DISKS, disksList);
tag.put(TAG_DISKS, diskInventory.toSyncTag(getNode()::getState));
return tag;
}

Expand Down
Loading

0 comments on commit 552910a

Please sign in to comment.