Skip to content

Commit ab63580

Browse files
authored
Merge pull request #254 from Matyrobbrt/widen-access
One more round of API improvements
2 parents 0a46347 + b094049 commit ab63580

File tree

11 files changed

+128
-76
lines changed

11 files changed

+128
-76
lines changed

src/main/java/me/desht/modularrouters/block/tile/ModularRouterBlockEntity.java

+11
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
import net.minecraft.world.level.block.entity.BlockEntity;
6464
import net.minecraft.world.level.block.state.BlockState;
6565
import net.minecraft.world.phys.AABB;
66+
import net.neoforged.neoforge.capabilities.ItemCapability;
6667
import net.neoforged.neoforge.client.model.data.ModelData;
6768
import net.neoforged.neoforge.common.NeoForge;
6869
import net.neoforged.neoforge.energy.EnergyStorage;
@@ -989,6 +990,16 @@ public IFluidHandlerItem getFluidHandler() {
989990
return bufferHandler.getFluidHandler();
990991
}
991992

993+
/**
994+
* Returns the capability of the item in the router's buffer of the given type.
995+
* @param cap the capability
996+
* @param <T> the capability type
997+
*/
998+
@Nullable
999+
public <T> T getBufferCapability(ItemCapability<T, Void> cap) {
1000+
return bufferHandler.getCapability(cap);
1001+
}
1002+
9921003
public void sendBlockUpdateIfNeeded() {
9931004
if (!nonNullLevel().isClientSide && blockUpdateNeeded && !anyPlayerHasThisOpen()) {
9941005
nonNullLevel().sendBlockUpdated(worldPosition, getBlockState(), getBlockState(), Block.UPDATE_ALL);

src/main/java/me/desht/modularrouters/client/gui/module/ModuleScreen.java

+9-9
Original file line numberDiff line numberDiff line change
@@ -52,27 +52,27 @@
5252
import static me.desht.modularrouters.client.util.ClientUtil.xlate;
5353

5454
public class ModuleScreen extends AbstractContainerScreen<ModuleMenu> implements ContainerListener, IMouseOverHelpProvider, ISendToServer {
55-
static final ResourceLocation GUI_TEXTURE = MiscUtil.RL("textures/gui/module.png");
55+
protected static final ResourceLocation GUI_TEXTURE = MiscUtil.RL("textures/gui/module.png");
5656

5757
// locations of extra textures on the gui module texture sheet
58-
static final XYPoint SMALL_TEXTFIELD_XY = new XYPoint(0, 198);
59-
static final XYPoint LARGE_TEXTFIELD_XY = new XYPoint(0, 212);
60-
static final XYPoint BUTTON_XY = new XYPoint(0, 226);
58+
protected static final XYPoint SMALL_TEXTFIELD_XY = new XYPoint(0, 198);
59+
protected static final XYPoint LARGE_TEXTFIELD_XY = new XYPoint(0, 212);
60+
protected static final XYPoint BUTTON_XY = new XYPoint(0, 226);
6161

6262
private static final int GUI_HEIGHT = 198;
6363
private static final int GUI_WIDTH = 192;
6464
private static final int BUTTON_WIDTH = 16;
6565
private static final int BUTTON_HEIGHT = 16;
6666

67-
final ItemStack moduleItemStack;
67+
protected final ItemStack moduleItemStack;
6868
private final ModuleItem module;
6969
private final BlockPos routerPos;
7070
private final int moduleSlotIndex;
7171
private final InteractionHand hand;
7272
private final ModuleSettings settings;
7373
private int sendDelay;
7474
private final MouseOverHelp mouseOverHelp;
75-
final AugmentItem.AugmentCounter augmentCounter;
75+
protected final AugmentItem.AugmentCounter augmentCounter;
7676

7777
private int regulatorAmount;
7878
private RelativeDirection facing;
@@ -81,7 +81,7 @@ public class ModuleScreen extends AbstractContainerScreen<ModuleMenu> implements
8181
private final EnumMap<RelativeDirection,DirectionButton> directionButtons = new EnumMap<>(RelativeDirection.class);
8282
private MouseOverHelp.Button mouseOverHelpButton;
8383
private TexturedToggleButton matchAllButton;
84-
IntegerTextField regulatorTextField;
84+
protected IntegerTextField regulatorTextField;
8585
private TerminationButton terminationButton;
8686
private ModuleToggleButton whiteListButton;
8787
private ModuleToggleButton matchDamageButton;
@@ -214,7 +214,7 @@ public void containerTick() {
214214
*
215215
* @param delay delay in ticks
216216
*/
217-
void sendModuleSettingsDelayed(int delay) {
217+
protected void sendModuleSettingsDelayed(int delay) {
218218
sendDelay = delay;
219219
}
220220

@@ -335,7 +335,7 @@ public void removed() {
335335
}
336336
}
337337

338-
Optional<ModularRouterBlockEntity> getItemRouter() {
338+
protected Optional<ModularRouterBlockEntity> getItemRouter() {
339339
return routerPos != null ? Minecraft.getInstance().level.getBlockEntity(routerPos, ModBlockEntities.MODULAR_ROUTER.get()) : Optional.empty();
340340
}
341341

src/main/java/me/desht/modularrouters/container/handler/BufferHandler.java

+43-26
Original file line numberDiff line numberDiff line change
@@ -2,66 +2,83 @@
22

33
import me.desht.modularrouters.block.tile.ModularRouterBlockEntity;
44
import me.desht.modularrouters.core.ModBlocks;
5-
import net.minecraft.core.HolderLookup;
6-
import net.minecraft.nbt.CompoundTag;
75
import net.minecraft.world.item.ItemStack;
86
import net.neoforged.neoforge.capabilities.Capabilities;
7+
import net.neoforged.neoforge.capabilities.ItemCapability;
98
import net.neoforged.neoforge.energy.IEnergyStorage;
109
import net.neoforged.neoforge.fluids.capability.IFluidHandlerItem;
1110
import net.neoforged.neoforge.items.ItemStackHandler;
11+
import org.jetbrains.annotations.Nullable;
12+
13+
import java.util.IdentityHashMap;
14+
import java.util.concurrent.atomic.AtomicBoolean;
1215

1316
public class BufferHandler extends ItemStackHandler {
17+
// we mask null keys in the cap cache map with this object to avoid needing to check containsKey
18+
private static final Object NULL = new Object();
19+
1420
private final ModularRouterBlockEntity router;
1521

16-
private IEnergyStorage energyStorage;
17-
private IFluidHandlerItem fluidHandler;
22+
// default expected size of 2 is reasonable for most routers
23+
private final IdentityHashMap<ItemCapability<?, Void>, Object> capabilityCache = new IdentityHashMap<>(4);
1824

1925
public BufferHandler(ModularRouterBlockEntity router) {
2026
super(router.getBufferSlotCount());
2127
this.router = router;
22-
23-
setupFluidAndEnergyCaps();
2428
}
2529

2630
@Override
2731
public void onContentsChanged(int slot) {
28-
ItemStack stack = getStackInSlot(slot);
32+
// small optimisation in case we don't have any caps requested already
33+
if (!capabilityCache.isEmpty()) {
34+
ItemStack stack = getStackInSlot(slot);
2935

30-
IFluidHandlerItem newFluidHandler = stack.getCapability(Capabilities.FluidHandler.ITEM);
31-
IEnergyStorage newEnergyStorage = stack.getCapability(Capabilities.EnergyStorage.ITEM);
36+
var modified = new AtomicBoolean();
3237

33-
if (newFluidHandler != fluidHandler || newEnergyStorage != energyStorage) {
34-
fluidHandler = newFluidHandler;
35-
energyStorage = newEnergyStorage;
38+
// replace and invalidate if necessary the capabilities we previously returned
39+
//noinspection rawtypes,unchecked
40+
capabilityCache.replaceAll((cap, old) -> revalidate(stack, (ItemCapability) cap, old, modified));
3641

37-
router.invalidateCapabilities();
42+
if (modified.get()) {
43+
router.invalidateCapabilities();
3844

39-
// in case any pipes/cables need to connect/disconnect
40-
router.nonNullLevel().updateNeighborsAt(router.getBlockPos(), ModBlocks.MODULAR_ROUTER.get());
45+
// in case any pipes/cables need to connect/disconnect
46+
router.nonNullLevel().updateNeighborsAt(router.getBlockPos(), ModBlocks.MODULAR_ROUTER.get());
47+
}
4148
}
4249

4350
router.setChanged(); // will also update comparator output
4451
}
4552

46-
@Override
47-
public void deserializeNBT(HolderLookup.Provider provider, CompoundTag nbt) {
48-
super.deserializeNBT(provider, nbt);
49-
50-
setupFluidAndEnergyCaps();
53+
private <T> T revalidate(ItemStack stack, ItemCapability<T, Void> cap, T old, AtomicBoolean modified) {
54+
var newVal = maskNull(stack.getCapability(cap));
55+
if (newVal != old) {
56+
modified.compareAndSet(false, true);
57+
}
58+
return newVal;
5159
}
5260

5361
public IFluidHandlerItem getFluidHandler() {
54-
return fluidHandler;
62+
return getCapability(Capabilities.FluidHandler.ITEM);
5563
}
5664

5765
public IEnergyStorage getEnergyStorage() {
58-
return energyStorage;
66+
return getCapability(Capabilities.EnergyStorage.ITEM);
5967
}
6068

61-
private void setupFluidAndEnergyCaps() {
62-
ItemStack stack = getStackInSlot(0);
69+
@Nullable
70+
@SuppressWarnings("unchecked")
71+
public <T> T getCapability(ItemCapability<T, Void> cap) {
72+
var cached = capabilityCache.get(cap);
73+
if (cached == null) {
74+
cached = maskNull(getStackInSlot(0).getCapability(cap));
75+
capabilityCache.put(cap, cached);
76+
}
77+
return cached == NULL ? null : (T)cached;
78+
}
6379

64-
fluidHandler = stack.getCapability(Capabilities.FluidHandler.ITEM);
65-
energyStorage = stack.getCapability(Capabilities.EnergyStorage.ITEM);
80+
@SuppressWarnings("unchecked")
81+
private static <T> T maskNull(T value) {
82+
return value == null ? (T) NULL : value;
6683
}
6784
}

src/main/java/me/desht/modularrouters/integration/jei/BulkFilterScreenGhost.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public <I> List<Target<I>> getTargetsTyped(BulkItemFilterScreen gui, ITypedIngre
1616
for (int i = 0; i < gui.getMenu().slots.size(); i++) {
1717
Slot s = gui.getMenu().getSlot(i);
1818
if (s instanceof FilterSlot) {
19-
res.add(new GhostTarget<>(gui, s));
19+
res.add(new GhostTarget<>(ingredient.getType(), gui, s));
2020
}
2121
}
2222
return res;

src/main/java/me/desht/modularrouters/integration/jei/GhostTarget.java

+7-10
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,25 @@
22

33
import me.desht.modularrouters.network.messages.ModuleFilterMessage;
44
import mezz.jei.api.gui.handlers.IGhostIngredientHandler;
5+
import mezz.jei.api.ingredients.IIngredientType;
56
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
67
import net.minecraft.client.renderer.Rect2i;
78
import net.minecraft.world.inventory.Slot;
8-
import net.minecraft.world.item.ItemStack;
9-
import net.neoforged.neoforge.fluids.FluidStack;
10-
import net.neoforged.neoforge.fluids.FluidUtil;
119
import net.neoforged.neoforge.network.PacketDistributor;
1210

13-
record GhostTarget<I>(AbstractContainerScreen<?> gui, Slot slot) implements IGhostIngredientHandler.Target<I> {
11+
record GhostTarget<I>(IIngredientType<I> type, AbstractContainerScreen<?> gui, Slot slot) implements IGhostIngredientHandler.Target<I> {
1412
@Override
1513
public Rect2i getArea() {
1614
return new Rect2i(slot.x + gui.getGuiLeft(), slot.y + gui.getGuiTop(), 16, 16);
1715
}
1816

1917
@Override
2018
public void accept(I ingredient) {
21-
if (ingredient instanceof ItemStack stack) {
22-
PacketDistributor.sendToServer(new ModuleFilterMessage(slot.index, stack));
23-
} else if (ingredient instanceof FluidStack fluidStack) {
24-
ItemStack bucket = FluidUtil.getFilledBucket(fluidStack);
25-
if (!bucket.isEmpty()) {
26-
PacketDistributor.sendToServer(new ModuleFilterMessage(slot.index, bucket));
19+
var creator = JEIModularRoutersPlugin.STACK_CREATORS.get(type);
20+
if (creator != null) {
21+
var stack = creator.apply(ingredient);
22+
if (!stack.isEmpty()) {
23+
PacketDistributor.sendToServer(new ModuleFilterMessage(slot.index, stack));
2724
}
2825
}
2926
}

src/main/java/me/desht/modularrouters/integration/jei/JEIModularRoutersPlugin.java

+18
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,36 @@
1010
import mezz.jei.api.JeiPlugin;
1111
import mezz.jei.api.constants.VanillaTypes;
1212
import mezz.jei.api.gui.handlers.IGuiContainerHandler;
13+
import mezz.jei.api.ingredients.IIngredientType;
14+
import mezz.jei.api.neoforge.NeoForgeTypes;
1315
import mezz.jei.api.registration.IGuiHandlerRegistration;
1416
import mezz.jei.api.registration.IIngredientAliasRegistration;
1517
import net.minecraft.client.renderer.Rect2i;
1618
import net.minecraft.core.registries.BuiltInRegistries;
1719
import net.minecraft.resources.ResourceLocation;
20+
import net.minecraft.world.item.ItemStack;
21+
import net.neoforged.neoforge.fluids.FluidUtil;
1822

23+
import java.util.IdentityHashMap;
1924
import java.util.List;
25+
import java.util.Map;
26+
import java.util.function.Function;
2027

2128
import static me.desht.modularrouters.util.MiscUtil.RL;
2229

2330
@JeiPlugin
2431
public class JEIModularRoutersPlugin implements IModPlugin {
32+
static final Map<IIngredientType<?>, Function<Object, ItemStack>> STACK_CREATORS = new IdentityHashMap<>();
33+
34+
public static synchronized <T> void registerGhostStackCreator(IIngredientType<T> type, Function<T, ItemStack> creator) {
35+
STACK_CREATORS.put(type, object -> creator.apply((T) object));
36+
}
37+
38+
public JEIModularRoutersPlugin() {
39+
registerGhostStackCreator(VanillaTypes.ITEM_STACK, Function.identity());
40+
registerGhostStackCreator(NeoForgeTypes.FLUID_STACK, FluidUtil::getFilledBucket);
41+
}
42+
2543
@Override
2644
public ResourceLocation getPluginUid() {
2745
return RL("default");

src/main/java/me/desht/modularrouters/integration/jei/ModuleScreenGhost.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public <I> List<Target<I>> getTargetsTyped(ModuleScreen gui, ITypedIngredient<I>
1616
for (int i = 0; i < gui.getMenu().slots.size(); i++) {
1717
Slot s = gui.getMenu().getSlot(i);
1818
if (s instanceof FilterSlot) {
19-
res.add(new GhostTarget<>(gui, s));
19+
res.add(new GhostTarget<>(ingredient.getType(), gui, s));
2020
}
2121
}
2222
return res;

src/main/java/me/desht/modularrouters/item/MRBaseItem.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ public void appendHoverText(ItemStack stack, Item.TooltipContext context, List<C
4141
}
4242

4343
protected void addUsageInformation(ItemStack itemstack, List<Component> list) {
44-
list.add(xlate("modularrouters.itemText.usage.item." + BuiltInRegistries.ITEM.getKey(itemstack.getItem()).getPath(), getExtraUsageParams()));
44+
var key = BuiltInRegistries.ITEM.getKey(itemstack.getItem());
45+
list.add(xlate(key.getNamespace() + ".itemText.usage.item." + key.getPath(), getExtraUsageParams()));
4546
}
4647

4748
protected abstract void addExtraInformation(ItemStack stack, List<Component> list);

0 commit comments

Comments
 (0)