Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recipe builder #45

Merged
merged 9 commits into from
Jan 17, 2024
Merged
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
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ bta_version=7.1-pre1a
loader_version=0.14.19-babric.3-bta

# Mod
mod_version=3.1.4
mod_version=3.2.0
mod_group=turniplabs
mod_name=halplibe

4 changes: 4 additions & 0 deletions src/main/java/turniplabs/halplibe/HalpLibe.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public class HalpLibe implements ModInitializer, PreLaunchEntrypoint{
public static final String MOD_ID = "halplibe";
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
public static boolean sendModlist;
public static boolean exportRecipes;
public static final TomlConfigHandler CONFIG;
static {
Toml toml = new Toml();
Expand All @@ -31,12 +32,15 @@ public class HalpLibe implements ModInitializer, PreLaunchEntrypoint{
toml.addEntry("Experimental.RequireTextures", "Require texture to exist on startup", false);
toml.addCategory("Network");
toml.addEntry("Network.SendModlistPack", "This sends a modlist packet to clients that join the server when enabled, however it may cause issues if the clients do not have halplibe installed", true);
toml.addCategory("Debug");
toml.addEntry("Debug.ExportRecipes", "Writes all the loaded game recipes to dumpRecipes after startup", false);


CONFIG = new TomlConfigHandler(MOD_ID, toml);

Global.TEXTURE_ATLAS_WIDTH_TILES = Math.max(32, CONFIG.getInt("Experimental.AtlasWidth"));
sendModlist = CONFIG.getBoolean("Network.SendModlistPack");
exportRecipes = CONFIG.getBoolean("Debug.ExportRecipes");

// Initialize Block and Item static fields
try {
Expand Down
143 changes: 143 additions & 0 deletions src/main/java/turniplabs/halplibe/helper/RecipeBuilder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package turniplabs.halplibe.helper;

import com.b100.utils.FileUtils;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.TypeAdapter;
import com.google.gson.reflect.TypeToken;
import net.minecraft.core.Global;
import net.minecraft.core.WeightedRandomBag;
import net.minecraft.core.WeightedRandomLootObject;
import net.minecraft.core.data.registry.Registries;
import net.minecraft.core.data.registry.recipe.HasJsonAdapter;
import net.minecraft.core.data.registry.recipe.RecipeEntryBase;
import net.minecraft.core.data.registry.recipe.RecipeGroup;
import net.minecraft.core.data.registry.recipe.RecipeNamespace;
import net.minecraft.core.data.registry.recipe.RecipeSymbol;
import net.minecraft.core.data.registry.recipe.adapter.ItemStackJsonAdapter;
import net.minecraft.core.data.registry.recipe.adapter.RecipeJsonAdapter;
import net.minecraft.core.data.registry.recipe.adapter.RecipeSymbolJsonAdapter;
import net.minecraft.core.data.registry.recipe.adapter.WeightedRandomBagJsonAdapter;
import net.minecraft.core.data.registry.recipe.adapter.WeightedRandomLootObjectJsonAdapter;
import net.minecraft.core.item.ItemStack;
import turniplabs.halplibe.helper.recipeBuilders.RecipeBuilderBlastFurnace;
import turniplabs.halplibe.helper.recipeBuilders.RecipeBuilderFurnace;
import turniplabs.halplibe.helper.recipeBuilders.RecipeBuilderShaped;
import turniplabs.halplibe.helper.recipeBuilders.RecipeBuilderShapeless;
import turniplabs.halplibe.helper.recipeBuilders.RecipeBuilderTrommel;
import turniplabs.halplibe.helper.recipeBuilders.modifiers.BlastFurnaceModifier;
import turniplabs.halplibe.helper.recipeBuilders.modifiers.FurnaceModifier;
import turniplabs.halplibe.helper.recipeBuilders.modifiers.TrommelModifier;
import turniplabs.halplibe.helper.recipeBuilders.modifiers.WorkbenchModifier;

import javax.annotation.Nonnull;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public final class RecipeBuilder {
@Nonnull
public static RecipeNamespace getRecipeNamespace(String modID){
if (Registries.RECIPES.getItem(modID) != null){
return Registries.RECIPES.getItem(modID);
}
RecipeNamespace modSpace = new RecipeNamespace();
Registries.RECIPES.register(modID, modSpace);
return Objects.requireNonNull(modSpace);
}
@Nonnull
public static RecipeGroup<?> getRecipeGroup(String modID, String key, RecipeSymbol symbol){
return getRecipeGroup(getRecipeNamespace(modID), key, symbol);
}
@Nonnull
public static RecipeGroup<?> getRecipeGroup(RecipeNamespace namespace, String key, RecipeSymbol symbol){
if (namespace.getItem(key) != null){
return namespace.getItem(key);
}
RecipeGroup<?> group = new RecipeGroup<>(symbol);
namespace.register(key, group);
return Objects.requireNonNull(group);
}
public static RecipeBuilderShaped Shaped(String modID){
return new RecipeBuilderShaped(modID);
}
public static RecipeBuilderShaped Shaped(String modID, String... shape){
return new RecipeBuilderShaped(modID, shape);
}
public static RecipeBuilderShapeless Shapeless(String modID){
return new RecipeBuilderShapeless(modID);
}
public static RecipeBuilderFurnace Furnace(String modID){
return new RecipeBuilderFurnace(modID);
}
public static RecipeBuilderBlastFurnace BlastFurnace(String modID){
return new RecipeBuilderBlastFurnace(modID);
}
public static RecipeBuilderTrommel Trommel(String modID){
return new RecipeBuilderTrommel(modID);
}
public static TrommelModifier ModifyTrommel(String namespace, String key){
return new TrommelModifier(namespace, key);
}
public static WorkbenchModifier ModifyWorkbench(String namespace){
return new WorkbenchModifier(namespace);
}
public static FurnaceModifier ModifyFurnace(String namespace){
return new FurnaceModifier(namespace);
}
public static BlastFurnaceModifier ModifyBlastFurnace(String namespace){
return new BlastFurnaceModifier(namespace);
}
public static boolean isExporting = false;
public static void exportRecipes(){
isExporting = true;
Path filePath = Paths.get(Global.accessor.getMinecraftDir() + "/" + "recipeDump");
createDir(filePath);
String path = filePath + "/recipes.json";
List<RecipeEntryBase<?, ?, ?>> recipes = Registries.RECIPES.getAllSerializableRecipes();
GsonBuilder builder = new GsonBuilder();
builder.setPrettyPrinting();
ArrayList usedAdapters = new ArrayList();
for (RecipeEntryBase<?, ?, ?> recipe : recipes) {
HasJsonAdapter hasJsonAdapter = (HasJsonAdapter) recipe;
RecipeJsonAdapter<?> recipeJsonAdapter = hasJsonAdapter.getAdapter();
if (usedAdapters.contains(recipeJsonAdapter)) continue;
builder.registerTypeAdapter(recipe.getClass(), recipeJsonAdapter);
usedAdapters.add(recipeJsonAdapter);
}
builder.registerTypeAdapter(ItemStack.class, new ItemStackJsonAdapter());
builder.registerTypeAdapter(RecipeSymbol.class, new RecipeSymbolJsonAdapter());
builder.registerTypeAdapter(new TypeToken<WeightedRandomBag<WeightedRandomLootObject>>(){}.getType(), new WeightedRandomBagJsonAdapter());
builder.registerTypeAdapter(WeightedRandomLootObject.class, new WeightedRandomLootObjectJsonAdapter());
Gson gson = builder.create();
JsonArray jsonArray = new JsonArray();
for (RecipeEntryBase recipeEntryBase : recipes) {
TypeAdapter<RecipeEntryBase> typeAdapter = (TypeAdapter<RecipeEntryBase>) gson.getAdapter(recipeEntryBase.getClass());
JsonElement json = typeAdapter.toJsonTree(recipeEntryBase);
jsonArray.add(json);
}
File file = FileUtils.createNewFile(new File(path));
try (FileWriter fileWriter = new FileWriter(file)){
gson.toJson(jsonArray, fileWriter);
} catch (IOException iOException) {
throw new RuntimeException(iOException);
}
isExporting = false;
}
private static void createDir(Path path){
try {
Files.createDirectories(path);
} catch (IOException e) {
System.err.println("Failed to create directory!" + e.getMessage());
}
}
}
8 changes: 8 additions & 0 deletions src/main/java/turniplabs/halplibe/helper/RecipeHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,19 @@
import net.minecraft.core.crafting.legacy.recipe.IRecipe;
import net.minecraft.core.crafting.legacy.recipe.RecipesBlastFurnace;
import net.minecraft.core.crafting.legacy.recipe.RecipesFurnace;
import net.minecraft.core.data.registry.Registries;
import net.minecraft.core.data.registry.recipe.RecipeEntryBase;
import net.minecraft.core.data.registry.recipe.RecipeGroup;
import net.minecraft.core.data.registry.recipe.RecipeNamespace;
import net.minecraft.core.data.registry.recipe.RecipeSymbol;
import net.minecraft.core.item.Item;
import net.minecraft.core.item.ItemStack;

import javax.annotation.Nonnull;
import java.util.Objects;
/**
* @deprecated Class will be removed once the Legacy crafting manager is removed from BTA
* Replace by the RecipeBuilder
*/
@Deprecated
public class RecipeHelper {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package turniplabs.halplibe.helper.recipeBuilders;

import net.minecraft.core.item.ItemStack;

import java.util.Objects;

abstract class RecipeBuilderBase implements Cloneable {
protected String modID;
public RecipeBuilderBase(String modID){
this.modID = Objects.requireNonNull(modID, "ModID must not be null!");
}
public <T> T clone(T object){
return (T) clone();
}
@Override
public RecipeBuilderBase clone() {
try {
// none of the fields are mutated so this should be fine
return (RecipeBuilderBase) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
protected abstract void create(String recipeID, ItemStack outputStack);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package turniplabs.halplibe.helper.recipeBuilders;

import net.minecraft.core.block.Block;
import net.minecraft.core.data.registry.recipe.RecipeGroup;
import net.minecraft.core.data.registry.recipe.RecipeSymbol;
import net.minecraft.core.data.registry.recipe.entry.RecipeEntryBlastFurnace;
import net.minecraft.core.item.ItemStack;
import turniplabs.halplibe.helper.RecipeBuilder;

public class RecipeBuilderBlastFurnace extends RecipeBuilderFurnace{
public RecipeBuilderBlastFurnace(String modID) {
super(modID);
}
@Override
public void create(String recipeID, ItemStack outputStack) {
((RecipeGroup< RecipeEntryBlastFurnace>) RecipeBuilder.getRecipeGroup(modID, "blast_furnace", new RecipeSymbol(Block.furnaceStoneActive.getDefaultStack())))
.register(recipeID, new RecipeEntryBlastFurnace(input, outputStack));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package turniplabs.halplibe.helper.recipeBuilders;

import net.minecraft.core.block.Block;
import net.minecraft.core.data.registry.recipe.RecipeGroup;
import net.minecraft.core.data.registry.recipe.RecipeSymbol;
import net.minecraft.core.data.registry.recipe.entry.RecipeEntryFurnace;
import net.minecraft.core.item.IItemConvertible;
import net.minecraft.core.item.ItemStack;
import turniplabs.halplibe.helper.RecipeBuilder;

import java.util.Objects;

public class RecipeBuilderFurnace extends RecipeBuilderBase{
protected RecipeSymbol input;
public RecipeBuilderFurnace(String modID) {
super(modID);
}
public RecipeBuilderFurnace setInput(IItemConvertible item){
return setInput(item, 0);
}
public RecipeBuilderFurnace setInput(IItemConvertible item, int meta){
return setInput(new ItemStack(item, 1, meta));
}
public RecipeBuilderFurnace setInput(ItemStack input){
return setInput(new RecipeSymbol(input));
}
public RecipeBuilderFurnace setInput(String itemGroup){
return setInput(new RecipeSymbol(itemGroup));
}
public RecipeBuilderFurnace setInput(RecipeSymbol input){
RecipeBuilderFurnace builder = this.clone(this);
builder.input = Objects.requireNonNull(input, "Input symbol must not be null!");
return builder;
}

@Override
public void create(String recipeID, ItemStack outputStack) {
Objects.requireNonNull(input, "Input symbol must not be null!");
((RecipeGroup<RecipeEntryFurnace>) RecipeBuilder.getRecipeGroup(modID, "furnace", new RecipeSymbol(Block.furnaceStoneActive.getDefaultStack())))
.register(recipeID, new RecipeEntryFurnace(input, outputStack));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package turniplabs.halplibe.helper.recipeBuilders;

import net.minecraft.core.block.Block;
import net.minecraft.core.data.registry.recipe.RecipeGroup;
import net.minecraft.core.data.registry.recipe.RecipeSymbol;
import net.minecraft.core.data.registry.recipe.entry.RecipeEntryCrafting;
import net.minecraft.core.data.registry.recipe.entry.RecipeEntryCraftingShaped;
import net.minecraft.core.item.IItemConvertible;
import net.minecraft.core.item.ItemStack;
import turniplabs.halplibe.helper.RecipeBuilder;

import java.util.Arrays;
import java.util.HashMap;

public class RecipeBuilderShaped extends RecipeBuilderBase{
protected String[] shape; // Only used for shaped recipes
protected int width;
protected int height;
protected boolean consumeContainer = false; // Only used for shapedRecipes
protected final HashMap<Character, RecipeSymbol> symbolShapedMap = new HashMap<>();
public RecipeBuilderShaped(String modID){
super(modID);
}
public RecipeBuilderShaped(String modID, String... shape) {
super(modID);
setShapeLocal(shape);
}
public RecipeBuilderShaped setShape(String... shapeTemplate){
RecipeBuilderShaped builder = this.clone(this);
builder.setShapeLocal(shapeTemplate);
return builder;
}
protected void setShapeLocal(String... shape){
if (shape == null){
throw new IllegalArgumentException("Shape Template cannot be set to null!");
}
if (shape.length == 0){
throw new IllegalArgumentException("Shape Template cannot have a size of 0!");
}
if (shape.length > 3){
throw new IllegalArgumentException("Shape Template height cannot exceed 3!\n" + Arrays.toString(shape));
}
if (shape[0].length() > 3){
throw new IllegalArgumentException("Shape Template width cannot exceed 3!\n" + Arrays.toString(shape));
}
this.height = shape.length;
this.width = shape[0].length();
this.shape = shape;
}
public RecipeBuilderShaped setConsumeContainer(boolean consumeContainer){
RecipeBuilderShaped builder = this.clone(this);
builder.consumeContainer = consumeContainer;
return builder;
}
public RecipeBuilderShaped addInput(char templateSymbol, IItemConvertible stack){
return addInput(templateSymbol, stack, 0);
}
public RecipeBuilderShaped addInput(char templateSymbol, IItemConvertible stack, int meta){
ItemStack _stack = stack.getDefaultStack();
_stack.setMetadata(meta);
return addInput(templateSymbol, _stack);
}
public RecipeBuilderShaped addInput(char templateSymbol, ItemStack stack){
return addInput(templateSymbol, new RecipeSymbol(stack));
}
public RecipeBuilderShaped addInput(char templateSymbol, String itemGroup) {
return addInput(templateSymbol, new RecipeSymbol(itemGroup));
}
public RecipeBuilderShaped addInput(char templateSymbol, RecipeSymbol symbol){
RecipeBuilderShaped builder = this.clone(this);
symbolShapedMap.put(templateSymbol, symbol);
return builder;
}
public void create(String recipeID, ItemStack outputStack) {
if (shape == null) throw new RuntimeException("Shaped recipe: " + recipeID + " attempted to build without a assigned shape!!");
RecipeSymbol[] recipe = new RecipeSymbol[height * width];
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
Character cha = null;
if (shape[y].length() > x) {
cha = shape[y].charAt(x);
}
RecipeSymbol tempplate = symbolShapedMap.get(cha);
if (tempplate == null){
recipe[x + y * 3] = null;
} else {
recipe[x + y * 3] = new RecipeSymbol(cha == null ? ' ' : cha, tempplate.getStack(), tempplate.getItemGroup());
}

}
}
((RecipeGroup<RecipeEntryCrafting<?, ?>>) RecipeBuilder.getRecipeGroup(modID, "workbench", new RecipeSymbol(Block.workbench.getDefaultStack())))
.register(recipeID, new RecipeEntryCraftingShaped(width, height, recipe, outputStack, consumeContainer));
}
}
Loading
Loading