Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
shartte committed Dec 26, 2023
1 parent 310f1e1 commit 76ea4c7
Show file tree
Hide file tree
Showing 21 changed files with 1,289 additions and 52 deletions.
46 changes: 46 additions & 0 deletions src/main/java/appeng/api/integrations/emi/EmiStackConverter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package appeng.api.integrations.emi;

import appeng.api.stacks.GenericStack;
import dev.emi.emi.api.stack.EmiStack;
import org.jetbrains.annotations.Nullable;

/**
* Implement this interface to provide AE2s EMI integration with a new way to convert between AE2 {@link GenericStack}
* and {@link dev.emi.emi.api.stack.EmiStack}.
* <ul>
* <li>Recipe transfers</li>
* <li>Pressing R/U on custom stacks in AE2 user interfaces</li>
* <li>Dragging ghost items of custom types from EMI to AE2 interfaces</li>
* </ul>
* <p/>
* To register your converter, see {@link EmiStackConverters}.
*/
public interface EmiStackConverter {
/**
* The EMI {@link EmiStack#getKeyOfType key type} handled by this converter.
* AE2 handles {@link net.minecraft.world.level.material.Fluid} and {@link net.minecraft.world.item.Item} already.
*/
Class<?> getKeyType();

/**
* Converts a generic stack into an EmiStack subtype handled by this converter.
* <p/>
* The converter needs to ensure the minimum amount of the returned ingredient is 1 if the resulting ingredient
* represents amounts of 0 as "empty", since this would not preserve the ingredient type correctly.
* <p/>
* Example: <code>Math.max(1, Ints.saturatedCast(stack.amount()))</code> (for Item and Fluid stacks).
*
* @return Null if the converter can't handle the stack.
*/
@Nullable
EmiStack getIngredientFromStack(GenericStack stack);

/**
* Converts an EmiStack handled by this converter into a generic stack.
*
* @return Null if the ingredient represents an "empty" ingredient (i.e.
* {@link EmiStack#EMPTY}.
*/
@Nullable
GenericStack getStackFromIngredient(EmiStack stack);
}
41 changes: 41 additions & 0 deletions src/main/java/appeng/api/integrations/emi/EmiStackConverters.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package appeng.api.integrations.emi;

import com.google.common.collect.ImmutableList;

import java.util.List;

/**
* Register your {@link EmiStackConverter} instances for JEI here.
*/
public final class EmiStackConverters {
private static List<EmiStackConverter> converters = ImmutableList.of();

private EmiStackConverters() {
}

/**
* Registers a new EMI stack-converter for handling custom {@link appeng.api.stacks.AEKey key types} in the AE2 EMI
* addon.
*
* @return false if a converter for the converters type has already been registered.
*/
public static synchronized boolean register(EmiStackConverter converter) {
for (var existingConverter : converters) {
if (existingConverter.getKeyType() == converter.getKeyType()) {
return false;
}
}
converters = ImmutableList.<EmiStackConverter>builder()
.addAll(converters)
.add(converter)
.build();
return true;
}

/**
* @return The currently registered converters.
*/
public static synchronized List<EmiStackConverter> getConverters() {
return converters;
}
}
79 changes: 74 additions & 5 deletions src/main/java/appeng/integration/modules/emi/AppEngEmiPlugin.java
Original file line number Diff line number Diff line change
@@ -1,33 +1,93 @@
package appeng.integration.modules.emi;

import appeng.api.config.CondenserOutput;
import appeng.api.features.P2PTunnelAttunementInternal;
import appeng.api.integrations.emi.EmiStackConverters;
import appeng.api.integrations.rei.IngredientConverters;
import appeng.core.AppEng;
import appeng.core.definitions.AEBlocks;
import appeng.core.definitions.AEItems;
import appeng.core.localization.ItemModText;
import appeng.integration.modules.emi.transfer.EmiEncodePatternHandler;
import appeng.integration.modules.emi.transfer.EmiUseCraftingRecipeHandler;
import appeng.menu.me.items.CraftingTermMenu;
import appeng.menu.me.items.PatternEncodingTermMenu;
import appeng.recipes.entropy.EntropyRecipe;
import appeng.recipes.handlers.ChargerRecipe;
import appeng.recipes.handlers.InscriberRecipe;
import appeng.recipes.transform.TransformRecipe;
import dev.emi.emi.api.EmiApi;
import dev.emi.emi.api.EmiEntrypoint;
import dev.emi.emi.api.EmiPlugin;
import dev.emi.emi.api.EmiRegistry;
import dev.emi.emi.api.recipe.EmiRecipe;
import dev.emi.emi.api.stack.EmiIngredient;
import dev.emi.emi.api.stack.EmiStack;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.Container;
import net.minecraft.world.inventory.MenuType;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.item.crafting.RecipeHolder;
import net.minecraft.world.item.crafting.RecipeType;

import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;

@EmiEntrypoint
public class AppEngEmiPlugin implements EmiPlugin {
static final ResourceLocation TEXTURE = AppEng.makeId("textures/guis/jei.png");

@Override
public void register(EmiRegistry registry) {

EmiStackConverters.register(new EmiItemStackConverter());
EmiStackConverters.register(new EmiFluidStackConverter());

// Recipe transfer
registry.addRecipeHandler(PatternEncodingTermMenu.TYPE, new EmiEncodePatternHandler<>(PatternEncodingTermMenu.class));
registry.addRecipeHandler(CraftingTermMenu.TYPE, new EmiUseCraftingRecipeHandler<>(CraftingTermMenu.class));

// Inscriber
registry.addCategory(EmiInscriberRecipe.CATEGORY);
registry.addWorkstation(EmiInscriberRecipe.CATEGORY, EmiStack.of(AEBlocks.INSCRIBER));
adaptRecipeType(registry, InscriberRecipe.TYPE, EmiInscriberRecipe::new);

// Charger
registry.addCategory(EmiChargerRecipe.CATEGORY);
registry.addWorkstation(EmiChargerRecipe.CATEGORY, EmiStack.of(AEBlocks.CHARGER));
adaptRecipeType(registry, ChargerRecipe.TYPE, EmiChargerRecipe::new);

// P2P attunement
registry.addCategory(EmiP2PAttunementRecipe.CATEGORY);
registry.addDeferredRecipes(this::registerP2PAttunements);

registry.addWorkstation(EmiInscriberRecipe.CATEGORY, EmiStack.of(AEBlocks.INSCRIBER));
registry.getRecipeManager().getAllRecipesFor(InscriberRecipe.TYPE)
// Condenser
registry.addCategory(EmiCondenserRecipe.CATEGORY);
registry.addWorkstation(EmiCondenserRecipe.CATEGORY, EmiStack.of(AEBlocks.CONDENSER));
registry.addRecipe(new EmiCondenserRecipe(CondenserOutput.MATTER_BALLS));
registry.addRecipe(new EmiCondenserRecipe(CondenserOutput.SINGULARITY));

// Entropy Manipulator
registry.addCategory(EmiEntropyRecipe.CATEGORY);
registry.addWorkstation(EmiEntropyRecipe.CATEGORY, EmiStack.of(AEItems.ENTROPY_MANIPULATOR));
adaptRecipeType(registry, EntropyRecipe.TYPE, EmiEntropyRecipe::new);

// In-World Transformation
registry.addCategory(EmiTransformRecipe.CATEGORY);
adaptRecipeType(registry, TransformRecipe.TYPE, EmiTransformRecipe::new);

// Facades
registry.addDeferredRecipes(this::registerFacades);
}

private static <C extends Container, T extends Recipe<C>> void adaptRecipeType(EmiRegistry registry,
RecipeType<T> recipeType,
Function<RecipeHolder<T>, ? extends EmiRecipe> adapter) {
registry.getRecipeManager().getAllRecipesFor(recipeType)
.stream()
.map(EmiInscriberRecipe::new)
.map(adapter)
.forEach(registry::addRecipe);

registry.addDeferredRecipes(this::registerP2PAttunements);
}

private void registerP2PAttunements(Consumer<EmiRecipe> recipeConsumer) {
Expand Down Expand Up @@ -62,4 +122,13 @@ private void registerP2PAttunements(Consumer<EmiRecipe> recipeConsumer) {
);
}
}

private void registerFacades(Consumer<EmiRecipe> recipeConsumer) {
var generator = new EmiFacadeGenerator();
EmiApi.getIndexStacks().stream()
.map(generator::getRecipeFor)
.filter(Optional::isPresent)
.map(Optional::get)
.forEach(recipeConsumer);
}
}
61 changes: 25 additions & 36 deletions src/main/java/appeng/integration/modules/emi/EmiChargerRecipe.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,57 +7,46 @@
import appeng.recipes.handlers.ChargerRecipe;
import dev.emi.emi.api.recipe.BasicEmiRecipe;
import dev.emi.emi.api.recipe.EmiRecipeCategory;
import dev.emi.emi.api.render.EmiTexture;
import dev.emi.emi.api.stack.EmiIngredient;
import dev.emi.emi.api.stack.EmiStack;
import dev.emi.emi.api.widget.WidgetHolder;
import me.shedaniel.math.Point;
import me.shedaniel.rei.api.client.gui.widgets.Widget;
import me.shedaniel.rei.api.client.gui.widgets.Widgets;
import me.shedaniel.rei.api.common.util.EntryIngredients;
import me.shedaniel.rei.api.common.util.EntryStacks;
import net.minecraft.world.item.crafting.RecipeHolder;

import java.util.ArrayList;

class EmiChargerRecipe extends BasicEmiRecipe {
public static final EmiRecipeCategory CATEGORY = new AppEngRecipeCategory("charger", EmiStack.of(AEBlocks.CHARGER), EmiText.CATEGORY_CHARGER);
private final ChargerRecipe recipe;

private final EmiIngredient ingredient;
private final EmiStack result;

public EmiChargerRecipe(RecipeHolder<ChargerRecipe> holder) {
super(CATEGORY, holder.id(), 130, 50);
recipe = holder.value();
this.ingredient = EmiIngredient.of(recipe.getIngredient());
inputs.add(this.ingredient);
this.result = EmiStack.of(recipe.getResultItem());
outputs.add(this.result);

catalysts.add(EmiStack.of(AEBlocks.CRANK));
}

@Override
public void addWidgets(WidgetHolder widgets) {
var widgets = new ArrayList<Widget>();

widgets.add(
Widgets.createSlot(new Point(x + 31, y + 8))
.markInput()
.backgroundEnabled(true)
.entries(EntryIngredients.ofIngredient(display.recipe().getIngredient())));
widgets.add(
Widgets.createSlot(new Point(x + 81, y + 8))
.markOutput()
.backgroundEnabled(true)
.entry(EntryStacks.of(display.recipe().getResultItem())));

widgets.add(
Widgets.createSlot(new Point(x + 3, y + 30))
.unmarkInputOrOutput()
.backgroundEnabled(false)
.entry(EntryStacks.of(AEBlocks.CRANK.stack())));

widgets.add(Widgets.createArrow(new Point(x + 52, y + 8)));

var turns = (ChargerBlockEntity.POWER_MAXIMUM_AMOUNT + CrankBlockEntity.POWER_PER_CRANK_TURN - 1)
/ CrankBlockEntity.POWER_PER_CRANK_TURN;
widgets.add(Widgets
.createLabel(new Point(x + 20, y + 35),
ItemModText.CHARGER_REQUIRED_POWER.text(turns, ChargerBlockEntity.POWER_MAXIMUM_AMOUNT))
.color(0x7E7E7E)
.noShadow()
.leftAligned());

widgets.addSlot(ingredient, 30, 7);
widgets.addSlot(result, 80, 7);
widgets.addSlot(EmiStack.of(AEBlocks.CRANK), 2, 29)
.drawBack(false);

widgets.addTexture(EmiTexture.EMPTY_ARROW, 52, 8);

var turns = (ChargerBlockEntity.POWER_MAXIMUM_AMOUNT + CrankBlockEntity.POWER_PER_CRANK_TURN - 1)
/ CrankBlockEntity.POWER_PER_CRANK_TURN;
widgets.addText(
ItemModText.CHARGER_REQUIRED_POWER.text(turns, ChargerBlockEntity.POWER_MAXIMUM_AMOUNT),
20, 35,
0x7E7E7E,
false);
}
}
Loading

0 comments on commit 76ea4c7

Please sign in to comment.