Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master-1.19-lts' into master-1.2…
Browse files Browse the repository at this point in the history
…0-lts
  • Loading branch information
rubensworks committed Oct 23, 2024
2 parents d6bba5d + 7da284f commit e21a0a8
Show file tree
Hide file tree
Showing 21 changed files with 1,263 additions and 206 deletions.
24 changes: 24 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,14 @@ repositories {
name 'jared'
url 'https://maven.blamejared.com/'
}
maven {
name "EMI"
url "https://maven.terraformersmc.com/"
}
maven {
name "REI"
url "https://maven.shedaniel.me/"
}
}

dependencies {
Expand Down Expand Up @@ -133,6 +141,12 @@ dependencies {

//runtimeOnly fg.deobf("top.theillusivec4.curios:curios-forge:${project.curios_version}") // https://maven.theillusivec4.top/top/theillusivec4/curios/curios-forge/
compileOnly fg.deobf("top.theillusivec4.curios:curios-forge:${project.curios_version}:api")

compileOnly fg.deobf("dev.emi:emi-forge:${emi_version}") // https://maven.terraformersmc.com/releases/dev/emi/emi-forge

compileOnly fg.deobf("me.shedaniel:RoughlyEnoughItems-forge:${rei_version}") // https://maven.shedaniel.me/me/shedaniel/RoughlyEnoughItems-forge/ or just look on CurseForge by modloader and MC version...
implementation fg.deobf("me.shedaniel.cloth:cloth-config-forge:$cloth_config_version");
implementation fg.deobf("dev.architectury:architectury-forge:$architectury_version");
}

minecraft {
Expand All @@ -143,6 +157,11 @@ minecraft {
workingDirectory project.file('run')
//property 'forge.logging.markers', 'REGISTRIES,REGISTRYDUMP'
property 'forge.logging.console.level', 'debug'

// Required for EMI
property 'mixin.env.remapRefMap', 'true'
property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg"

mods {
integratedterminalscompat {
source sourceSets.main
Expand All @@ -157,6 +176,11 @@ minecraft {
server {
workingDirectory project.file('run')
property 'forge.logging.console.level', 'debug'

// Required for EMI
property 'mixin.env.remapRefMap', 'true'
property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg"

mods {
integratedterminalscompat {
source sourceSets.main
Expand Down
8 changes: 6 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
mod_version=1.0.0
minecraft_version=1.20.1
forge_version=47.0.1
cyclopscore_version=1.18.4-340
cyclopscore_version=1.19.4-497
release_type=release
fingerprint=bd0353b3e8a2810d60dd584e256e364bc3bedd44

integrateddynamics_version=1.20.1-1.16.7-575
integratedterminals_version=1.20.1-1.4.8-281
integratedterminals_version=1.20.1-1.5.1-387
commoncapabilities_version=1.20.1-2.9.0-98
curios_version=1.19.4-5.1.5.3
jei_version=1.20.1-forge:15.1.0.19
emi_version=1.1.16+1.20.1
rei_version=12.1.780
cloth_config_version=11.1.136
architectury_version=9.2.14

# Workaround for Spotless bug
# https://github.com/diffplug/spotless/issues/834
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.cyclops.integratedterminalscompat.modcompat.common;

import net.minecraft.world.item.ItemStack;

/**
* @author rubensworks
*/
public interface RecipeInputSlot extends Iterable<ItemStack> {

public boolean isEmpty();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
package org.cyclops.integratedterminalscompat.modcompat.common;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Streams;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.items.wrapper.InvWrapper;
import org.apache.commons.lang3.tuple.Pair;
import org.cyclops.commoncapabilities.api.ingredient.IngredientComponent;
import org.cyclops.commoncapabilities.ingredient.storage.IngredientComponentStorageWrapperHandlerItemStack;
import org.cyclops.cyclopscore.ingredient.collection.IIngredientCollectionMutable;
import org.cyclops.cyclopscore.ingredient.collection.IngredientCollectionHelpers;
import org.cyclops.cyclopscore.ingredient.collection.IngredientCollectionPrototypeMap;
import org.cyclops.integratedterminals.api.terminalstorage.ITerminalStorageTabCommon;
import org.cyclops.integratedterminals.core.terminalstorage.TerminalStorageTabIngredientComponentClient;
import org.cyclops.integratedterminals.core.terminalstorage.TerminalStorageTabIngredientComponentItemStackCrafting;
import org.cyclops.integratedterminals.core.terminalstorage.TerminalStorageTabIngredientComponentItemStackCraftingCommon;
import org.cyclops.integratedterminals.inventory.container.ContainerTerminalStorageBase;
import org.cyclops.integratedterminalscompat.IntegratedTerminalsCompat;
import org.cyclops.integratedterminalscompat.network.packet.TerminalStorageIngredientItemStackCraftingGridSetRecipe;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
* Common helpers for JEI/EMI/REI
* @author rubensworks
*/
public class RecipeTransferHelpers {

// The amount of seconds recipeErrors will be cached for transferRecipe
private static final long RECIPE_ERROR_CACHE_TIME = 60;
private static final Cache<Object, Optional<RecipeTransferResult<?>>> recipeErrorCache = CacheBuilder.newBuilder()
.expireAfterAccess(RECIPE_ERROR_CACHE_TIME, TimeUnit.SECONDS)
.build();

public static Optional<Pair<TerminalStorageTabIngredientComponentItemStackCraftingCommon, TerminalStorageTabIngredientComponentClient<ItemStack, Integer>>> getTabs(ContainerTerminalStorageBase<?> container) {
if (Objects.equals(container.getSelectedTab(), TerminalStorageTabIngredientComponentItemStackCrafting.NAME.toString())) {
ITerminalStorageTabCommon tabCommon = container.getTabCommon(container.getSelectedTab());
TerminalStorageTabIngredientComponentItemStackCraftingCommon tabCommonCrafting =
(TerminalStorageTabIngredientComponentItemStackCraftingCommon) tabCommon;
TerminalStorageTabIngredientComponentClient tabClient = (TerminalStorageTabIngredientComponentClient)
container.getTabClient(container.getSelectedTab());
return Optional.of(Pair.of(tabCommonCrafting, tabClient));
}
return Optional.empty();
}

public static <T extends RecipeInputSlot> Optional<RecipeTransferResult<T>> getMissingItems(Object cacheKey, ContainerTerminalStorageBase<?> container, Iterable<T> recipeInputSlots, Player player, TerminalStorageTabIngredientComponentItemStackCraftingCommon tabCommonCrafting, TerminalStorageTabIngredientComponentClient<?, ?> tabClient, Function<ItemStack, Integer> itemStackToMatchCondition, Supplier<Integer> getId, Consumer<Integer> onChangeId) {
Callable<Optional<RecipeTransferResult<T>>> missingItemsSupplier =
() -> getMissingItemsUncached(container, recipeInputSlots, player, tabCommonCrafting, itemStackToMatchCondition, onChangeId);
if (getId.get() != tabClient.getLastChangeId()) {
// Clear cache when storage contents changed
recipeErrorCache.invalidateAll();
}
try {
return recipeErrorCache.get(cacheKey, (Callable) missingItemsSupplier);
} catch (ExecutionException e) {
// Throw exceptions from missingItemsSupplier
throw new RuntimeException(e);
}
}

public static <T extends RecipeInputSlot> Optional<RecipeTransferResult<T>> getMissingItemsUncached(ContainerTerminalStorageBase<?> container, Iterable<T> recipeInputSlots, Player player, TerminalStorageTabIngredientComponentItemStackCraftingCommon tabCommonCrafting, Function<ItemStack, Integer> itemStackToMatchCondition, Consumer<Integer> onChangeId) {
TerminalStorageTabIngredientComponentClient tabClient = (TerminalStorageTabIngredientComponentClient)
container.getTabClient(container.getSelectedTab());

// Check in the player inventory and local client view if the required recipe ingredients are available

// Build crafting grid index
IIngredientCollectionMutable<ItemStack, Integer> hayStackCraftingGrid = new IngredientCollectionPrototypeMap<>(IngredientComponent.ITEMSTACK);
for (int slot = 0; slot < tabCommonCrafting.getInventoryCrafting().getContainerSize(); slot++) {
hayStackCraftingGrid.add(tabCommonCrafting.getInventoryCrafting().getItem(slot));
}

// Build player inventory index
IIngredientCollectionMutable<ItemStack, Integer> hayStackPlayer = new IngredientCollectionPrototypeMap<>(IngredientComponent.ITEMSTACK);
hayStackPlayer.addAll(player.getInventory().items);

// Build local client view of storage
List<TerminalStorageTabIngredientComponentClient.InstanceWithMetadata<ItemStack>> unfilteredIngredients = tabClient
.getUnfilteredIngredientsView(container.getSelectedChannel());
IIngredientCollectionMutable<ItemStack, Integer> hayStack = IngredientCollectionHelpers.createCollapsedCollection(IngredientComponent.ITEMSTACK);
IIngredientCollectionMutable<ItemStack, Integer> hayStackCraftable = IngredientCollectionHelpers.createCollapsedCollection(IngredientComponent.ITEMSTACK);
hayStack.addAll(unfilteredIngredients
.stream()
.filter(i -> i.getCraftingOption() == null)
.map(TerminalStorageTabIngredientComponentClient.InstanceWithMetadata::getInstance)
.collect(Collectors.toList()));
hayStackCraftable.addAll(unfilteredIngredients
.stream()
.filter(i -> i.getCraftingOption() != null)
.map(TerminalStorageTabIngredientComponentClient.InstanceWithMetadata::getInstance)
.collect(Collectors.toList()));

List<T> slotsMissingItems = Lists.newArrayList();
List<T> slotsMissingCraftableItems = Lists.newArrayList();
for (T slot : recipeInputSlots) {
if (!slot.isEmpty()) {
boolean found = false;
boolean craftable = false;
for (ItemStack itemStack : slot) {
int matchCondition = itemStackToMatchCondition.apply(itemStack);

// First check in the crafting grid
if (hayStackCraftingGrid.contains(itemStack, matchCondition)) {
hayStackPlayer.remove(itemStack);
found = true;
break;
}

// Then check in player inventory
if (hayStackPlayer.contains(itemStack, matchCondition)) {
hayStackPlayer.remove(itemStack);
found = true;
break;
}

// Then check the storage
if (hayStack.contains(itemStack, matchCondition)) {
hayStack.remove(itemStack);
found = true;
break;
}

// Also check if this item could be craftable
if (hayStackCraftable.contains(itemStack, matchCondition)) {
craftable = true;
}
}

if (!found) {
if (craftable) {
slotsMissingCraftableItems.add(slot);
} else {
slotsMissingItems.add(slot);
}
}
}
}

onChangeId.accept(tabClient.getLastChangeId());
if (!slotsMissingItems.isEmpty() || !slotsMissingCraftableItems.isEmpty()) {
return Optional.of(new RecipeTransferResult<T>(slotsMissingItems, slotsMissingCraftableItems));
}

return Optional.empty();
}

public static <T extends RecipeInputSlot> void transferRecipe(ContainerTerminalStorageBase<?> container, Iterable<T> recipeInputSlots, Player player, TerminalStorageTabIngredientComponentItemStackCraftingCommon tabCommonCrafting, Function<ItemStack, Integer> itemStackToMatchCondition, boolean maxTransfer) {
IngredientComponentStorageWrapperHandlerItemStack.ComponentStorageWrapper playerInventory =
new IngredientComponentStorageWrapperHandlerItemStack.ComponentStorageWrapper(IngredientComponent.ITEMSTACK, new InvWrapper(player.getInventory()));

// Send a packet to the server if the recipe effectively needs to be applied to the grid
Map<Integer, Pair<ItemStack, Integer>> slottedIngredientsFromPlayer = Maps.newHashMap();
Map<Integer, List<Pair<ItemStack, Integer>>> slottedIngredientsFromStorage = Maps.newHashMap();
int slotOffset = tabCommonCrafting.getSlotCrafting().index;
int slotId = 0;
for (T recipeSlot : recipeInputSlots) {
if (!recipeSlot.isEmpty()) {
boolean found = false;

// First check if we can transfer from the player inventory
// No need to check the crafting grid, as the server will first clear the grid into the storage in TerminalStorageIngredientItemStackCraftingGridSetRecipe
for (ItemStack itemStack : recipeSlot) {
int matchCondition = itemStackToMatchCondition.apply(itemStack);

if (!playerInventory.extract(itemStack, matchCondition, true).isEmpty()) {
found = true;

// Move from player to crafting grid
ItemStack extracted = playerInventory.extract(itemStack, matchCondition, false);
Slot slot = container.getSlot(slotId + slotOffset);
slot.set(extracted);

// Do the exact same thing server-side
slottedIngredientsFromPlayer.put(slotId, Pair.of(itemStack, itemStackToMatchCondition.apply(itemStack)));

break;
}
}

if (!found) {
// Otherwise, request them from the storage
slottedIngredientsFromStorage.put(slotId, Streams.stream(recipeSlot)
.map(itemStack -> Pair.of(itemStack, itemStackToMatchCondition.apply(itemStack)))
.collect(Collectors.toList()));
}
}
slotId++;
}

IntegratedTerminalsCompat._instance.getPacketHandler().sendToServer(
new TerminalStorageIngredientItemStackCraftingGridSetRecipe(container.getSelectedTab(),
container.getSelectedChannel(), maxTransfer, slottedIngredientsFromPlayer, slottedIngredientsFromStorage, AbstractContainerScreen.hasControlDown()));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package org.cyclops.integratedterminalscompat.modcompat.common;

import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import org.cyclops.cyclopscore.helper.Helpers;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
* @author rubensworks
*/
public class RecipeTransferResult<T extends RecipeInputSlot> {

public static final boolean HAS_CMD = System.getProperty("os.name").equals("Mac OS X");

public static final int SLOT_COLOR_MISSING = Helpers.RGBAToInt(255, 0, 0, 100);
public static final int SLOT_COLOR_CRAFTABLE = Helpers.RGBAToInt(0, 0, 255, 100);

public static final int HIGHLIGHT_COLOR_FAIL = Helpers.RGBAToInt(255, 0, 0, 100);
public static final int HIGHLIGHT_COLOR_CRAFTABLE = Helpers.RGBAToInt(0, 0, 255, 100);
public static final int HIGHLIGHT_COLOR_CRAFTABLE_PARTIAL = Helpers.RGBAToInt(255, 125, 0, 100);

private final List<Component> message = new ArrayList<>();
private final Collection<T> slotsMissing;
private final Collection<T> slotsCraftable;
private final int color;

public RecipeTransferResult(Collection<T> slotsMissing, Collection<T> slotsCraftable) {
this.slotsMissing = slotsMissing;
this.slotsCraftable = slotsCraftable;
if (slotsCraftable.isEmpty() && slotsMissing.isEmpty()) {
this.color = HIGHLIGHT_COLOR_CRAFTABLE;
} else if (slotsMissing.isEmpty()) {
// Missing items, but they are all craftable
this.message.add(Component.translatable("gui.integratedterminalscompat.terminal_storage.jei.transfer.craftable").withStyle(ChatFormatting.RED));
this.message.add(Component.translatable(HAS_CMD ? "gui.integratedterminalscompat.terminal_storage.jei.transfer.craft.info_cmd" : "gui.integratedterminalscompat.terminal_storage.jei.transfer.craft.info").withStyle(ChatFormatting.ITALIC));
this.color = HIGHLIGHT_COLOR_CRAFTABLE;
} else if (!slotsCraftable.isEmpty()) {
// Missing items, but only some of them are craftable
this.message.add(Component.translatable("gui.integratedterminalscompat.terminal_storage.jei.transfer.craftable_partial").withStyle(ChatFormatting.RED));
this.message.add(Component.translatable(HAS_CMD ? "gui.integratedterminalscompat.terminal_storage.jei.transfer.craft.info_cmd" : "gui.integratedterminalscompat.terminal_storage.jei.transfer.craft.info").withStyle(ChatFormatting.ITALIC));
this.color = HIGHLIGHT_COLOR_CRAFTABLE_PARTIAL;
} else {
// Missing items, and none are craftable
this.message.add(Component.translatable("gui.integratedterminalscompat.terminal_storage.jei.transfer.missing").withStyle(ChatFormatting.ITALIC));
this.color = HIGHLIGHT_COLOR_FAIL;
}
}

public int getButtonHighlightColor() {
return this.color;
}

public List<Component> getMessage() {
return message;
}

public Collection<T> getSlotsCraftable() {
return slotsCraftable;
}

public Collection<T> getSlotsMissing() {
return slotsMissing;
}

}
Loading

0 comments on commit e21a0a8

Please sign in to comment.