Skip to content

Commit d63aeb9

Browse files
committed
feat: ✨ Added linked storage support
1 parent bb3bbde commit d63aeb9

68 files changed

Lines changed: 3866 additions & 22 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ loader_version_range=[4,)
1313
mod_id=sophisticatedcore
1414
mod_name=Sophisticated Core
1515
mod_license=All Rights Reserved
16-
mod_version=1.4.104
16+
mod_version=1.5.0
1717
mod_group_id=net.p3pp3rf1y
1818
mod_authors=P3pp3rF1y
1919
mod_description=A library / shared functionality mod for Sophisticated Storage and Backpacks
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
{
2+
"neoforge:conditions": [
3+
{
4+
"type": "sophisticatedcore:item_enabled",
5+
"itemRegistryName": "sophisticatedcore:ender_linker"
6+
},
7+
{
8+
"type": "neoforge:or",
9+
"values": [
10+
{
11+
"type": "neoforge:mod_loaded",
12+
"modid": "sophisticatedbackpacks"
13+
},
14+
{
15+
"type": "neoforge:mod_loaded",
16+
"modid": "sophisticatedstorage"
17+
}
18+
]
19+
}
20+
],
21+
"parent": "minecraft:recipes/root",
22+
"criteria": {
23+
"has_ender_pearl": {
24+
"conditions": {
25+
"items": [
26+
{
27+
"items": "minecraft:ender_pearl"
28+
}
29+
]
30+
},
31+
"trigger": "minecraft:inventory_changed"
32+
},
33+
"has_the_recipe": {
34+
"conditions": {
35+
"recipe": "sophisticatedcore:ender_linker"
36+
},
37+
"trigger": "minecraft:recipe_unlocked"
38+
}
39+
},
40+
"requirements": [
41+
[
42+
"has_the_recipe",
43+
"has_ender_pearl"
44+
]
45+
],
46+
"rewards": {
47+
"recipes": [
48+
"sophisticatedcore:ender_linker"
49+
]
50+
}
51+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"neoforge:conditions": [
3+
{
4+
"type": "sophisticatedcore:item_enabled",
5+
"itemRegistryName": "sophisticatedcore:ender_linker"
6+
},
7+
{
8+
"type": "neoforge:or",
9+
"values": [
10+
{
11+
"type": "neoforge:mod_loaded",
12+
"modid": "sophisticatedbackpacks"
13+
},
14+
{
15+
"type": "neoforge:mod_loaded",
16+
"modid": "sophisticatedstorage"
17+
}
18+
]
19+
}
20+
],
21+
"type": "minecraft:crafting_shaped",
22+
"category": "misc",
23+
"key": {
24+
"B": "minecraft:blaze_rod",
25+
"E": "minecraft:ender_pearl",
26+
"O": "minecraft:obsidian"
27+
},
28+
"pattern": [
29+
"OEO",
30+
"BOB",
31+
"OEO"
32+
],
33+
"result": {
34+
"count": 1,
35+
"id": "sophisticatedcore:ender_linker"
36+
}
37+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"neoforge:conditions": [
3+
{
4+
"type": "neoforge:or",
5+
"values": [
6+
{
7+
"type": "neoforge:mod_loaded",
8+
"modid": "sophisticatedbackpacks"
9+
},
10+
{
11+
"type": "neoforge:mod_loaded",
12+
"modid": "sophisticatedstorage"
13+
}
14+
]
15+
}
16+
],
17+
"type": "sophisticatedcore:ender_linker_clear",
18+
"category": "misc"
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"neoforge:conditions": [
3+
{
4+
"type": "neoforge:or",
5+
"values": [
6+
{
7+
"type": "neoforge:mod_loaded",
8+
"modid": "sophisticatedbackpacks"
9+
},
10+
{
11+
"type": "neoforge:mod_loaded",
12+
"modid": "sophisticatedstorage"
13+
}
14+
]
15+
}
16+
],
17+
"type": "sophisticatedcore:ender_linker_endpoint",
18+
"category": "misc"
19+
}

src/main/java/net/p3pp3rf1y/sophisticatedcore/SophisticatedCore.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import net.p3pp3rf1y.sophisticatedcore.data.DataGenerators;
2525
import net.p3pp3rf1y.sophisticatedcore.init.ModCompat;
2626
import net.p3pp3rf1y.sophisticatedcore.init.ModCoreDataComponents;
27+
import net.p3pp3rf1y.sophisticatedcore.init.ModItems;
2728
import net.p3pp3rf1y.sophisticatedcore.inventory.StorageWrapperRepository;
2829
import net.p3pp3rf1y.sophisticatedcore.settings.DatapackSettingsTemplateManager;
2930
import net.p3pp3rf1y.sophisticatedcore.util.RecipeHelper;
@@ -52,6 +53,7 @@ public SophisticatedCore(IEventBus modBus, Dist dist, ModContainer container) {
5253
}
5354
Config.COMMON.initListeners(modBus);
5455
ModCoreDataComponents.register(modBus);
56+
ModItems.register(modBus);
5557
modBus.addListener((FMLConstructModEvent event) -> construct(event, modBus));
5658
modBus.addListener(SophisticatedCore::setup);
5759
modBus.addListener(DataGenerators::gatherData);

src/main/java/net/p3pp3rf1y/sophisticatedcore/client/ClientEventHandler.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package net.p3pp3rf1y.sophisticatedcore.client;
22

33
import com.mojang.blaze3d.platform.InputConstants;
4+
import net.minecraft.ChatFormatting;
45
import net.minecraft.client.KeyMapping;
56
import net.minecraft.client.Minecraft;
67
import net.minecraft.client.MouseHandler;
@@ -24,6 +25,7 @@
2425
import net.neoforged.neoforge.client.settings.IKeyConflictContext;
2526
import net.neoforged.neoforge.client.settings.KeyModifier;
2627
import net.neoforged.neoforge.common.NeoForge;
28+
import net.neoforged.neoforge.event.entity.player.ItemTooltipEvent;
2729
import net.p3pp3rf1y.sophisticatedcore.SophisticatedCore;
2830
import net.p3pp3rf1y.sophisticatedcore.api.IStashStorageItem;
2931
import net.p3pp3rf1y.sophisticatedcore.client.gui.StorageScreenBase;
@@ -62,6 +64,7 @@ private ClientEventHandler() {
6264

6365
public static void registerHandlers(IEventBus modBus) {
6466
modBus.addListener(ModParticles::registerFactories);
67+
modBus.addListener(ClientEventHandler::registerConditionalItemModelProperties);
6568
modBus.addListener(ClientEventHandler::registerFluidClientExtension);
6669
modBus.addListener(ClientEventHandler::registerFluidModels);
6770
modBus.addListener(ClientEventHandler::registerKeyMappings);
@@ -73,12 +76,17 @@ public static void registerHandlers(IEventBus modBus) {
7376
eventBus.addListener(ClientEventHandler::onDrawScreen);
7477
eventBus.addListener(ClientEventHandler::onScreenForeground);
7578
eventBus.addListener(ClientEventHandler::recipesReceived);
79+
eventBus.addListener(ClientEventHandler::onItemTooltip);
7680
eventBus.addListener(ClientEventHandler::handleGuiKeyPress);
7781
eventBus.addListener(ClientEventHandler::handleGuiMouseKeyPress);
7882
eventBus.addListener(ClientEventHandler::submitCustomGeometry);
7983
eventBus.addListener(ClientEventHandler::onTickEnd);
8084
}
8185

86+
private static void registerConditionalItemModelProperties(RegisterConditionalItemModelPropertyEvent event) {
87+
event.register(SophisticatedCore.getIdentifier("ender_linker_bound"), EnderLinkerBound.MAP_CODEC);
88+
}
89+
8290
private static void onTickEnd(ClientTickEvent.Post event) {
8391
ItemStackKey.clearCache();
8492
}
@@ -197,6 +205,8 @@ private static void onScreenForeground(ScreenEvent.Render.Foreground event) {
197205
return;
198206
}
199207
AbstractContainerMenu menu = containerGui.getMenu();
208+
LinkerCraftingDiagnostics.requestIfChanged(menu);
209+
renderLinkerCraftingDiagnostics(event.getGuiGraphics(), menu);
200210
ItemStack held = menu.getCarried();
201211
if (held.isEmpty()) {
202212
return;
@@ -213,6 +223,35 @@ private static void onScreenForeground(ScreenEvent.Render.Foreground event) {
213223
}
214224
}
215225

226+
private static void renderLinkerCraftingDiagnostics(GuiGraphicsExtractor guiGraphics, AbstractContainerMenu menu) {
227+
for (Slot slot : menu.slots) {
228+
renderLinkerCraftingDiagnostic(guiGraphics, slot);
229+
}
230+
if (menu instanceof StorageContainerMenuBase<?> storageContainer) {
231+
storageContainer.upgradeSlots.forEach(slot -> renderLinkerCraftingDiagnostic(guiGraphics, slot));
232+
}
233+
}
234+
235+
private static void renderLinkerCraftingDiagnostic(GuiGraphicsExtractor guiGraphics, Slot slot) {
236+
if (LinkerCraftingDiagnostics.getStatusMessage(slot.index) != null) {
237+
guiGraphics.fill(slot.x, slot.y, slot.x + 16, slot.y + 16, 0x80FF0000);
238+
}
239+
}
240+
241+
private static void onItemTooltip(ItemTooltipEvent event) {
242+
if (!(Minecraft.getInstance().gui.screen() instanceof AbstractContainerScreen<?> screen)) {
243+
return;
244+
}
245+
Slot slot = screen.getSlotUnderMouse();
246+
if (slot == null || slot.getItem() != event.getItemStack()) {
247+
return;
248+
}
249+
String statusMessage = LinkerCraftingDiagnostics.getStatusMessage(slot.index);
250+
if (statusMessage != null) {
251+
event.getToolTip().add(TranslationHelper.INSTANCE.translStatusMessage(statusMessage).withStyle(ChatFormatting.RED));
252+
}
253+
}
254+
216255
private static void renderStashTooltip(ScreenEvent.Render.Post event, AbstractContainerScreen<?> containerGui, ItemStack held) {
217256
Slot under = containerGui.getSlotUnderMouse();
218257
if (under != null) {
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package net.p3pp3rf1y.sophisticatedcore.client;
2+
3+
import com.mojang.serialization.MapCodec;
4+
import net.minecraft.client.multiplayer.ClientLevel;
5+
import net.minecraft.client.renderer.item.properties.conditional.ConditionalItemModelProperty;
6+
import net.minecraft.world.entity.LivingEntity;
7+
import net.minecraft.world.item.ItemDisplayContext;
8+
import net.minecraft.world.item.ItemStack;
9+
import net.p3pp3rf1y.sophisticatedcore.linkedstorage.EnderLinkerItem;
10+
11+
import javax.annotation.Nullable;
12+
13+
public record EnderLinkerBound() implements ConditionalItemModelProperty {
14+
public static final MapCodec<EnderLinkerBound> MAP_CODEC = MapCodec.unit(new EnderLinkerBound());
15+
16+
@Override
17+
public boolean get(ItemStack itemStack, @Nullable ClientLevel clientLevel, @Nullable LivingEntity livingEntity, int seed,
18+
ItemDisplayContext itemDisplayContext) {
19+
return EnderLinkerItem.hasBoundPresentation(itemStack);
20+
}
21+
22+
@Override
23+
public MapCodec<? extends ConditionalItemModelProperty> type() {
24+
return MAP_CODEC;
25+
}
26+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package net.p3pp3rf1y.sophisticatedcore.client;
2+
3+
import net.minecraft.client.Minecraft;
4+
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
5+
import net.minecraft.world.inventory.AbstractContainerMenu;
6+
import net.minecraft.world.inventory.CraftingContainer;
7+
import net.minecraft.world.inventory.Slot;
8+
import net.neoforged.neoforge.client.network.ClientPacketDistributor;
9+
import net.p3pp3rf1y.sophisticatedcore.common.gui.ICraftingContainer;
10+
import net.p3pp3rf1y.sophisticatedcore.common.gui.StorageContainerMenuBase;
11+
import net.p3pp3rf1y.sophisticatedcore.common.gui.UpgradeContainerBase;
12+
import net.p3pp3rf1y.sophisticatedcore.network.RequestLinkerCraftingDiagnosticsPayload;
13+
import net.p3pp3rf1y.sophisticatedcore.network.SyncLinkerCraftingDiagnosticsPayload;
14+
15+
import javax.annotation.Nullable;
16+
17+
import java.util.HashMap;
18+
import java.util.List;
19+
import java.util.Map;
20+
21+
public final class LinkerCraftingDiagnostics {
22+
private static int lastRequestedContainerId = -1;
23+
private static int lastRequestedSignature;
24+
@Nullable
25+
private static AbstractContainerMenu lastRequestedMenu;
26+
private static final Map<Integer, String> diagnostics = new HashMap<>();
27+
28+
private LinkerCraftingDiagnostics() {
29+
}
30+
31+
public static void requestIfChanged(AbstractContainerMenu menu) {
32+
if (menu != lastRequestedMenu) {
33+
lastRequestedMenu = menu;
34+
lastRequestedContainerId = -1;
35+
diagnostics.clear();
36+
}
37+
int signature = 1;
38+
boolean hasCraftingGrid = false;
39+
for (Slot slot : menu.slots) {
40+
if (slot.container instanceof CraftingContainer) {
41+
signature = 31 * signature + 31 * slot.index + slot.getItem().hashCode();
42+
hasCraftingGrid = true;
43+
}
44+
}
45+
if (menu instanceof StorageContainerMenuBase<?> storageContainer) {
46+
for (UpgradeContainerBase<?, ?> upgradeContainer : storageContainer.getUpgradeContainers().values()) {
47+
if (upgradeContainer instanceof ICraftingContainer craftingContainer) {
48+
for (int slot = 0; slot < craftingContainer.getCraftMatrix().getContainerSize(); slot++) {
49+
signature = 31 * signature + craftingContainer.getCraftMatrix().getItem(slot).hashCode();
50+
}
51+
hasCraftingGrid = true;
52+
}
53+
}
54+
}
55+
if (!hasCraftingGrid) {
56+
diagnostics.clear();
57+
lastRequestedMenu = null;
58+
lastRequestedContainerId = -1;
59+
return;
60+
}
61+
if (menu.containerId == lastRequestedContainerId && signature == lastRequestedSignature) {
62+
return;
63+
}
64+
lastRequestedContainerId = menu.containerId;
65+
lastRequestedSignature = signature;
66+
diagnostics.clear();
67+
ClientPacketDistributor.sendToServer(new RequestLinkerCraftingDiagnosticsPayload(menu.containerId));
68+
}
69+
70+
public static void update(int containerId, List<SyncLinkerCraftingDiagnosticsPayload.Diagnostic> updatedDiagnostics) {
71+
if (!(Minecraft.getInstance().gui.screen() instanceof AbstractContainerScreen<?> screen) || screen.getMenu().containerId != containerId) {
72+
return;
73+
}
74+
diagnostics.clear();
75+
updatedDiagnostics.forEach(diagnostic -> diagnostics.put(diagnostic.slot(), diagnostic.statusMessageKey()));
76+
}
77+
78+
@Nullable
79+
public static String getStatusMessage(int slot) {
80+
return diagnostics.get(slot);
81+
}
82+
}

0 commit comments

Comments
 (0)