Skip to content

Commit

Permalink
Merge pull request #45 from UselessBullets/RecipeBuilder
Browse files Browse the repository at this point in the history
Recipe builder
  • Loading branch information
UselessBullets authored Jan 17, 2024
2 parents 579c00c + 8f9a309 commit 73bf788
Show file tree
Hide file tree
Showing 24 changed files with 799 additions and 2 deletions.
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

0 comments on commit 73bf788

Please sign in to comment.