Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,19 @@ repositories {
includeGroup "me.shedaniel.cloth"
}
}

maven {
// Teamresourceful, required by Chipped
name "Teamresourceful"
url "https://maven.teamresourceful.com/repository/maven-public"
content {
includeGroup "earth.terrarium.chipped"
includeGroup "com.teamresourceful.resourcefullib"
includeGroup "com.teamresourceful"
includeGroup "earth.terrarium.athena"
includeGroup "com.terraformersmc"
}
}
}

dependencies {
Expand Down Expand Up @@ -258,6 +271,11 @@ dependencies {
dependencies.ext.mod "com.github.Chocohead:Fabric-ASM:v2.3"
}

// Chipped
if (chipped_enabled) {
dependencies.ext.mod "earth.terrarium.chipped:chipped-fabric-${minecraft_version}:${chipped_version}"
}

//
// Stuff we just want to have at runtime
//
Expand Down
4 changes: 4 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -78,5 +78,9 @@ arch_version = 9.2.14
cloth_version = 11.1.118
cca_version = 5.2.2

# Chipped
chipped_enabled = true
chipped_version = 3.0.6

# Runtime Mod Dependencies
mod_menu_version = 7.2.1
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.kneelawk.extramodintegrations;

import com.kneelawk.extramodintegrations.util.ReflectionUtils;
import dev.emi.emi.api.EmiRegistry;
import net.fabricmc.loader.api.FabricLoader;
import org.jetbrains.annotations.Nullable;

public abstract class AbstractChippedIntegration {
@Nullable
public static final AbstractChippedIntegration INSTANCE;

static {
if (FabricLoader.getInstance().isModLoaded("chipped")) {
INSTANCE =
ReflectionUtils.newIntegrationInstance("com.kneelawk.extramodintegrations.chipped.ChippedIntegration",
"Chipped");
} else {
INSTANCE = null;
}
}

protected abstract void registerImpl(EmiRegistry registry);

public static void register(EmiRegistry registry) {
if (INSTANCE != null) {
INSTANCE.registerImpl(registry);
} else {
ExMIMod.logSkipping("Chipped");
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public void register(EmiRegistry registry) {
AbstractAE2Integration.register(registry);
AbstractTiCIntegration.register(registry);
AbstractDimDoorsIntegration.register(registry);
AbstractChippedIntegration.register(registry);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.kneelawk.extramodintegrations.chipped;

import com.kneelawk.extramodintegrations.ExMIMod;
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 net.minecraft.item.ItemStack;
import net.minecraft.recipe.Ingredient;
import net.minecraft.util.Identifier;

public class ChippedEmiRecipe extends BasicEmiRecipe {

public ChippedEmiRecipe(EmiRecipeCategory category, FlattenedRecipe recipe) {
super(category, new Identifier(ExMIMod.MOD_ID, "/chipped/" + recipe.id), 80, 18);
this.inputs.add(EmiIngredient.of(recipe.tag));
this.outputs.add(EmiStack.of(recipe.result));
}

@Override
public void addWidgets(WidgetHolder widgets) {
widgets.addTexture(EmiTexture.EMPTY_ARROW, 26, 1);
widgets.addSlot(inputs.get(0), 0, 0);
widgets.addSlot(outputs.get(0), 58, 0).recipeContext(this);
}

public record FlattenedRecipe(
String id,
Ingredient tag,
ItemStack result
) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package com.kneelawk.extramodintegrations.chipped;

import com.kneelawk.extramodintegrations.AbstractChippedIntegration;
import com.kneelawk.extramodintegrations.ExMIMod;
import dev.emi.emi.api.EmiRegistry;
import dev.emi.emi.api.recipe.EmiRecipeCategory;
import dev.emi.emi.api.stack.EmiStack;
import earth.terrarium.chipped.common.recipes.ChippedRecipe;
import earth.terrarium.chipped.common.registry.ModBlocks;
import earth.terrarium.chipped.common.registry.ModMenuTypes;
import earth.terrarium.chipped.common.registry.ModRecipeTypes;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.recipe.Ingredient;
import net.minecraft.recipe.RecipeManager;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.registry.entry.RegistryEntryList;
import net.minecraft.text.Text;

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

public class ChippedIntegration extends AbstractChippedIntegration {

public static final EmiRecipeCategory BOTANIST_WORKBENCH_CATEGORY = new ChippedEmiRecipeCategory(ModBlocks.BOTANIST_WORKBENCH);
public static final EmiRecipeCategory GLASSBLOWER_CATEGORY = new ChippedEmiRecipeCategory(ModBlocks.GLASSBLOWER);
public static final EmiRecipeCategory CARPENTERS_TABLE_CATEGORY = new ChippedEmiRecipeCategory(ModBlocks.CARPENTERS_TABLE);
public static final EmiRecipeCategory LOOM_TABLE_CATEGORY = new ChippedEmiRecipeCategory(ModBlocks.LOOM_TABLE);
public static final EmiRecipeCategory MASON_TABLE_CATEGORY = new ChippedEmiRecipeCategory(ModBlocks.MASON_TABLE);
public static final EmiRecipeCategory ALCHEMY_BENCH_CATEGORY = new ChippedEmiRecipeCategory(ModBlocks.ALCHEMY_BENCH);
public static final EmiRecipeCategory TINKERING_TABLE_CATEGORY = new ChippedEmiRecipeCategory(ModBlocks.TINKERING_TABLE);

private static List<ChippedEmiRecipe.FlattenedRecipe> flatten(Collection<ChippedRecipe> recipes) {
List<ChippedEmiRecipe.FlattenedRecipe> flattenedRecipes = new ArrayList<>();

for (ChippedRecipe recipe : recipes) {
for (RegistryEntryList<Item> tag : recipe.tags()) {
List<Item> items = tag.stream().filter(RegistryEntry::hasKeyAndValue).map(RegistryEntry::value).toList();
Ingredient ingredient = Ingredient.ofStacks(items.stream().map(ItemStack::new));

for (Item item : items) {
flattenedRecipes.add(new ChippedEmiRecipe.FlattenedRecipe(item.toString(), ingredient, new ItemStack(item)));
}
}
}
return flattenedRecipes;
}

@Override
protected void registerImpl(EmiRegistry registry) {

ExMIMod.logLoading("Chipped");

// categories
registry.addCategory(BOTANIST_WORKBENCH_CATEGORY);
registry.addCategory(GLASSBLOWER_CATEGORY);
registry.addCategory(CARPENTERS_TABLE_CATEGORY);
registry.addCategory(LOOM_TABLE_CATEGORY);
registry.addCategory(MASON_TABLE_CATEGORY);
registry.addCategory(ALCHEMY_BENCH_CATEGORY);
registry.addCategory(TINKERING_TABLE_CATEGORY);

// workstations
registry.addWorkstation(BOTANIST_WORKBENCH_CATEGORY, EmiStack.of(ModBlocks.BOTANIST_WORKBENCH.get()));
registry.addWorkstation(GLASSBLOWER_CATEGORY, EmiStack.of(ModBlocks.GLASSBLOWER.get()));
registry.addWorkstation(CARPENTERS_TABLE_CATEGORY, EmiStack.of(ModBlocks.CARPENTERS_TABLE.get()));
registry.addWorkstation(LOOM_TABLE_CATEGORY, EmiStack.of(ModBlocks.LOOM_TABLE.get()));
registry.addWorkstation(MASON_TABLE_CATEGORY, EmiStack.of(ModBlocks.MASON_TABLE.get()));
registry.addWorkstation(ALCHEMY_BENCH_CATEGORY, EmiStack.of(ModBlocks.ALCHEMY_BENCH.get()));
registry.addWorkstation(TINKERING_TABLE_CATEGORY, EmiStack.of(ModBlocks.TINKERING_TABLE.get()));

// handler
registry.addRecipeHandler(ModMenuTypes.WORKBENCH.get(), new ChippedWorkbenchHandler());

// recipes
RecipeManager manager = registry.getRecipeManager();

// Botanist Workbench Recipes
flatten(manager.listAllOfType(ModRecipeTypes.BOTANIST_WORKBENCH.get()))
.stream()
.map(recipe -> new ChippedEmiRecipe(BOTANIST_WORKBENCH_CATEGORY, recipe))
.forEach(registry::addRecipe);

// Glassblower Recipes
flatten(manager.listAllOfType(ModRecipeTypes.GLASSBLOWER.get()))
.stream()
.map(recipe -> new ChippedEmiRecipe(GLASSBLOWER_CATEGORY, recipe))
.forEach(registry::addRecipe);

// Carpenters Table Recipes
flatten(manager.listAllOfType(ModRecipeTypes.CARPENTERS_TABLE.get()))
.stream()
.map(recipe -> new ChippedEmiRecipe(CARPENTERS_TABLE_CATEGORY, recipe))
.forEach(registry::addRecipe);

// Loom Table Recipes
flatten(manager.listAllOfType(ModRecipeTypes.LOOM_TABLE.get()))
.stream()
.map(recipe -> new ChippedEmiRecipe(LOOM_TABLE_CATEGORY, recipe))
.forEach(registry::addRecipe);

// Mason Table Recipes
flatten(manager.listAllOfType(ModRecipeTypes.MASON_TABLE.get()))
.stream()
.map(recipe -> new ChippedEmiRecipe(MASON_TABLE_CATEGORY, recipe))
.forEach(registry::addRecipe);

// Alchemy Bench Recipes
flatten(manager.listAllOfType(ModRecipeTypes.ALCHEMY_BENCH.get()))
.stream()
.map(recipe -> new ChippedEmiRecipe(ALCHEMY_BENCH_CATEGORY, recipe))
.forEach(registry::addRecipe);

// Tinkering Table Recipes
flatten(manager.listAllOfType(ModRecipeTypes.TINKERING_TABLE.get()))
.stream()
.map(recipe -> new ChippedEmiRecipe(TINKERING_TABLE_CATEGORY, recipe))
.forEach(registry::addRecipe);

}

public static class ChippedEmiRecipeCategory extends EmiRecipeCategory {
private final Block block;

public ChippedEmiRecipeCategory(com.teamresourceful.resourcefullib.common.registry.RegistryEntry<Block> block) {
super(block.getId(), EmiStack.of(block.get()));
this.block = block.get();
}

@Override
public Text getName() {
return block.getName();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package com.kneelawk.extramodintegrations.chipped;

import dev.emi.emi.api.recipe.EmiRecipe;
import dev.emi.emi.api.recipe.handler.EmiCraftContext;
import dev.emi.emi.api.recipe.handler.StandardRecipeHandler;
import dev.emi.emi.api.stack.EmiIngredient;
import dev.emi.emi.api.stack.EmiStack;
import earth.terrarium.chipped.common.menus.WorkbenchMenu;
import net.minecraft.client.MinecraftClient;
import net.minecraft.item.Item;
import net.minecraft.screen.slot.Slot;
import net.minecraft.screen.slot.SlotActionType;

import java.util.List;

public class ChippedWorkbenchHandler implements StandardRecipeHandler<WorkbenchMenu> {

@Override
public List<Slot> getInputSources(WorkbenchMenu handler) {
return handler.slots.subList(0, 35);
}

@Override
public List<Slot> getCraftingSlots(WorkbenchMenu handler) {
return List.of();
}

@Override
public boolean supportsRecipe(EmiRecipe recipe) {
return recipe.getCategory() instanceof ChippedIntegration.ChippedEmiRecipeCategory; // && correct table.
}

@Override
public boolean canCraft(EmiRecipe recipe, EmiCraftContext<WorkbenchMenu> context) {
return recipe.getCategory().getName().getString().equals(context.getScreen().getTitle().getString()) && context.getInventory().canCraft(recipe);
}

@Override
public boolean craft(EmiRecipe recipe, EmiCraftContext<WorkbenchMenu> context) {

// context.getAmount(). Amount doesn't apply to Chipped Workbench.
MinecraftClient client = MinecraftClient.getInstance();

List<Slot> slots = getInputSources(context.getScreenHandler());
EmiIngredient ingredient = recipe.getInputs().get(0);
Item output = recipe.getOutputs().get(0).getItemStack().getItem();

for (int i = 0; i < slots.size(); i++) {
EmiStack slotStack = EmiStack.of(slots.get(i).getStack());
if (ingredient.getEmiStacks().contains(slotStack)) {
// Technically this should work, looks ok in client side, but server refuses to actually craft.
// So used client.interactionManager to simulate real click.
// context.getScreenHandler().selectStack(i);
client.interactionManager.clickSlot(context.getScreenHandler().syncId, i, 0, SlotActionType.PICKUP, client.player);
context.getScreenHandler().results().stream()
.filter(s -> s.getItem().equals(output))
.findFirst()
.ifPresent(itemStack -> context.getScreenHandler().setChosenStack(itemStack));

MinecraftClient.getInstance().setScreen(context.getScreen());
return true;
}
}

return false;
}
}