Generates recipes for Brick Oven for non-vanilla food items on command.

master
sealedinterface 2016-06-19 11:57:27 -07:00
parent c962617eb6
commit be9c6d272c
18 changed files with 604 additions and 15 deletions

View File

@ -1,5 +1,6 @@
package net.einsteinsci.betterbeginnings;
import net.einsteinsci.betterbeginnings.commands.JsonGenerateCommand;
import net.einsteinsci.betterbeginnings.config.BBConfig;
import net.einsteinsci.betterbeginnings.config.BBConfigFolderLoader;
import net.einsteinsci.betterbeginnings.event.BBEventHandler;
@ -119,4 +120,10 @@ public class ModMain
AchievementPage.registerAchievementPage(new AchievementPage(NAME, RegisterAchievements.getAchievements()));
LogUtil.logDebug("Finished post-initialization.");
}
@EventHandler
public void serverLoad(FMLServerStartingEvent e)
{
e.registerServerCommand(new JsonGenerateCommand());
}
}

View File

@ -0,0 +1,82 @@
package net.einsteinsci.betterbeginnings.commands;
import net.einsteinsci.betterbeginnings.config.BBConfigFolderLoader;
import net.einsteinsci.betterbeginnings.config.json.BrickOvenConfig;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.command.WrongUsageException;
import net.minecraft.util.BlockPos;
import net.minecraft.util.ChatComponentTranslation;
import java.util.ArrayList;
import java.util.List;
public class JsonGenerateCommand extends CommandBase
{
public static final String SMELTER = "smelter";
public static final String BRICKOVEN = "brickoven";
public static final String KILN = "kiln";
@Override
public String getCommandName()
{
return "jsongen";
}
@Override
public String getCommandUsage(ICommandSender sender)
{
// Do not translate this, as "smelter", "brickoven", and "kiln" are hardcoded.
return "jsongen <smelter|brickoven|kiln>";
}
public int getRequiredPermissionLevel()
{
return 2;
}
@Override
public void processCommand(ICommandSender sender, String[] args) throws CommandException
{
if (args.length == 0 || args.length > 1)
{
throw new WrongUsageException(getCommandUsage(sender));
}
String code = args[0];
if (code.equalsIgnoreCase(SMELTER))
{
}
else if (code.equalsIgnoreCase(BRICKOVEN))
{
BrickOvenConfig.INSTANCE.generateAutoConfig();
BBConfigFolderLoader.saveAutoJson(BrickOvenConfig.INSTANCE);
}
else if (code.equalsIgnoreCase(KILN))
{
}
else
{
throw new WrongUsageException(getCommandUsage(sender));
}
sender.addChatMessage(new ChatComponentTranslation("command.jsongen.complete"));
}
@Override
public List addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos)
{
List<String> res = new ArrayList<>();
if (args == null || args.length == 0)
{
res.add(SMELTER);
res.add(BRICKOVEN);
res.add(KILN);
}
return res;
}
}

View File

@ -1,6 +1,5 @@
package net.einsteinsci.betterbeginnings.config;
import net.einsteinsci.betterbeginnings.ModMain;
import net.einsteinsci.betterbeginnings.util.LogUtil;
import net.einsteinsci.betterbeginnings.util.RegistryUtil;
import net.minecraft.block.Block;
@ -8,6 +7,7 @@ import net.minecraft.item.Item;
import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.fml.common.registry.GameRegistry;
import org.apache.logging.log4j.Level;
import sun.security.krb5.Config;
import java.util.*;
@ -219,6 +219,16 @@ public class BBConfig
// Save //
//////////
save(config);
}
public static void TurnOffAutoJSON(Configuration config)
{
}
public static void save(Configuration config)
{
if (config.hasChanged())
{
config.save();

View File

@ -61,4 +61,12 @@ public class BBConfigFolderLoader
config.savePostLoad(subfolder);
}
public static void saveAutoJson(IJsonConfig config)
{
File subfolder = new File(configFolder, config.getSubFolder());
subfolder.mkdirs();
config.saveAutoJson(subfolder);
}
}

View File

@ -148,6 +148,10 @@ public class AdvancedCraftingConfig implements IJsonConfig
FileUtil.overwriteAllText(mainf, json);
}
@Override
public void saveAutoJson(File subfolder)
{ }
public JsonAdvancedCraftingHandler getMainRecipes()
{
return mainRecipes;

View File

@ -148,6 +148,10 @@ public class BoosterConfig implements IJsonConfig
FileUtil.overwriteAllText(customf, json);
}
@Override
public void saveAutoJson(File subfolder)
{ }
public JsonBoosterHandler getMainBoosters()
{
return mainBoosters;

View File

@ -3,25 +3,39 @@ package net.einsteinsci.betterbeginnings.config.json;
import net.einsteinsci.betterbeginnings.config.json.recipe.JsonBrickOvenRecipeHandler;
import net.einsteinsci.betterbeginnings.config.json.recipe.JsonBrickOvenShapedRecipe;
import net.einsteinsci.betterbeginnings.config.json.recipe.JsonBrickOvenShapelessRecipe;
import net.einsteinsci.betterbeginnings.register.recipe.BrickOvenRecipeHandler;
import net.einsteinsci.betterbeginnings.util.FileUtil;
import net.einsteinsci.betterbeginnings.util.LogUtil;
import net.einsteinsci.betterbeginnings.util.RegistryUtil;
import net.einsteinsci.betterbeginnings.util.Util;
import net.minecraft.item.Item;
import net.minecraft.item.ItemFood;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.CraftingManager;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.item.crafting.ShapedRecipes;
import net.minecraft.item.crafting.ShapelessRecipes;
import net.minecraft.util.Tuple;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.oredict.ShapedOreRecipe;
import net.minecraftforge.oredict.ShapelessOreRecipe;
import org.apache.logging.log4j.Level;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.*;
public class BrickOvenConfig implements IJsonConfig
{
public static final BrickOvenConfig INSTANCE = new BrickOvenConfig();
public static final List<ItemStack> AFFECTED_OUTPUTS = new ArrayList<>();
private static JsonBrickOvenRecipeHandler initialRecipes = new JsonBrickOvenRecipeHandler();
private JsonBrickOvenRecipeHandler mainRecipes = new JsonBrickOvenRecipeHandler();
private JsonBrickOvenRecipeHandler customRecipes = new JsonBrickOvenRecipeHandler();
private JsonBrickOvenRecipeHandler autoRecipes = new JsonBrickOvenRecipeHandler();
private List<JsonBrickOvenRecipeHandler> includes = new ArrayList<>();
@ -34,6 +48,128 @@ public class BrickOvenConfig implements IJsonConfig
initialRecipes.getShapeless().add(new JsonBrickOvenShapelessRecipe(output, args));
}
// Not entirely sure how reliable these methods will be.
public static JsonBrickOvenShapedRecipe convert(ShapedRecipes recipe)
{
char current = '1';
Map<Object, Character> map = new HashMap<>();
List<String> rows = new ArrayList<>();
for (int y = 0; y < recipe.recipeHeight; y++)
{
String row = "";
for (int x = 0; x < recipe.recipeWidth; x++)
{
int i = y * 3 + x;
Object obj = recipe.recipeItems[i];
char token = current;
Tuple res = RegistryUtil.getRecipeCharacter(map, obj, current);
if ((Boolean)res.getFirst())
{
current++;
}
row += token;
}
rows.add(row);
}
List<Object> res = new ArrayList<>();
res.addAll(rows);
for (Map.Entry<Object, Character> kvp : map.entrySet())
{
res.add(kvp.getValue());
res.add(kvp.getKey());
}
return new JsonBrickOvenShapedRecipe(recipe.getRecipeOutput(), res.toArray());
}
public static JsonBrickOvenShapedRecipe convert(ShapedOreRecipe recipe)
{
// Yeah...I know. But there's no other way to find the width and height of a ShapedOreRecipe.
Integer width = Util.getPrivateVariable(recipe, "width");
Integer height = Util.getPrivateVariable(recipe, "height");
if (width == null || height == null)
{
return null;
}
char current = '1';
Map<Object, Character> map = new HashMap<>();
List<String> rows = new ArrayList<>();
for (int y = 0; y < height; y++)
{
String row = "";
for (int x = 0; x < width; x++)
{
int i = y * 3 + x;
Object obj = recipe.getInput()[i];
char token = current;
Tuple res = RegistryUtil.getRecipeCharacter(map, obj, current);
if ((Boolean)res.getFirst())
{
current++;
}
row += token;
}
rows.add(row);
}
List<Object> res = new ArrayList<>();
res.addAll(rows);
for (Map.Entry<Object, Character> kvp : map.entrySet())
{
res.add(kvp.getValue());
res.add(kvp.getKey());
}
return new JsonBrickOvenShapedRecipe(recipe.getRecipeOutput(), res.toArray());
}
public static JsonBrickOvenShapelessRecipe convert(ShapelessRecipes recipe)
{
return new JsonBrickOvenShapelessRecipe(recipe.getRecipeOutput(), recipe.recipeItems);
}
public static JsonBrickOvenShapelessRecipe convert(ShapelessOreRecipe recipe)
{
List<Object> inputs = new ArrayList<>();
for (Object obj : recipe.getInput())
{
if (obj instanceof ItemStack)
{
inputs.add(obj);
}
else if (obj instanceof List)
{
try
{
String ore = RegistryUtil.getCommonOreDictName((List<ItemStack>)obj);
inputs.add(ore);
}
catch (ClassCastException ex)
{
LogUtil.log(Level.ERROR, "Failed to cast list in ore dictionary conversion: " + ex.toString());
}
}
}
return new JsonBrickOvenShapelessRecipe(recipe.getRecipeOutput(), inputs);
}
public static JsonBrickOvenShapelessRecipe convertFurnace(ItemStack input, ItemStack output)
{
return new JsonBrickOvenShapelessRecipe(output, input);
}
private static boolean hasGenerated = false;
@Override
public String getSubFolder()
{
@ -57,7 +193,14 @@ public class BrickOvenConfig implements IJsonConfig
@Override
public String getAutoJson(File subfolder)
{
return "{}";
File autof = new File(subfolder, "auto.json");
String json = FileUtil.readAllText(autof);
if (json == null)
{
json = "{}";
}
return json;
}
@Override
@ -109,6 +252,105 @@ public class BrickOvenConfig implements IJsonConfig
{
r.register();
}
autoRecipes = BBJsonLoader.deserializeObject(autoJson, JsonBrickOvenRecipeHandler.class);
for (JsonBrickOvenShapedRecipe r : autoRecipes.getShaped())
{
r.register();
}
for (JsonBrickOvenShapelessRecipe r : autoRecipes.getShapeless())
{
r.register();
}
}
public void generateAutoConfig()
{
for (Object obj : CraftingManager.getInstance().getRecipeList())
{
if (!(obj instanceof IRecipe))
{
continue;
}
IRecipe r = (IRecipe)obj;
ItemStack output = r.getRecipeOutput();
if (output == null)
{
continue; // no idea why this happens
}
Item item = output.getItem();
if (item != null && item instanceof ItemFood &&
!RegistryUtil.getModOwner(item).equals("minecraft"))
{
if (Util.listContainsItemStackIgnoreSize(AFFECTED_OUTPUTS, r.getRecipeOutput()))
{
AFFECTED_OUTPUTS.add(r.getRecipeOutput());
}
// Don't add recipes for items already added.
if (BrickOvenRecipeHandler.instance().existsRecipeFor(output))
{
continue;
}
if (r instanceof ShapedOreRecipe)
{
autoRecipes.getShaped().add(convert((ShapedOreRecipe)r));
}
else if (r instanceof ShapedRecipes)
{
autoRecipes.getShaped().add(convert((ShapedRecipes)r));
}
else if (r instanceof ShapelessOreRecipe)
{
autoRecipes.getShapeless().add(convert((ShapelessOreRecipe)r));
}
else if (r instanceof ShapelessRecipes)
{
autoRecipes.getShapeless().add(convert((ShapelessRecipes)r));
}
}
}
hasGenerated = true;
}
// generates affected outputs without adding recipes
public void generateAffectedOutputs()
{
if (!hasGenerated)
{
for (Object obj : CraftingManager.getInstance().getRecipeList())
{
if (!(obj instanceof IRecipe))
{
continue;
}
IRecipe r = (IRecipe)obj;
ItemStack output = r.getRecipeOutput();
if (output == null)
{
continue; // no idea why this happens
}
Item item = output.getItem();
if (item != null && item instanceof ItemFood &&
!RegistryUtil.getModOwner(item).equals("minecraft"))
{
if (Util.listContainsItemStackIgnoreSize(AFFECTED_OUTPUTS, r.getRecipeOutput()))
{
AFFECTED_OUTPUTS.add(r.getRecipeOutput());
}
}
}
hasGenerated = true;
}
}
@Override
@ -160,6 +402,13 @@ public class BrickOvenConfig implements IJsonConfig
FileUtil.overwriteAllText(customf, json);
}
public void saveAutoJson(File subfolder)
{
String json = BBJsonLoader.serializeObject(autoRecipes);
File autof = new File(subfolder, "auto.json");
FileUtil.overwriteAllText(autof, json);
}
public JsonBrickOvenRecipeHandler getMainRecipes()
{
return mainRecipes;

View File

@ -193,6 +193,10 @@ public class CampfireConfig implements IJsonConfig
FileUtil.overwriteAllText(customf, json);
}
@Override
public void saveAutoJson(File subfolder)
{ }
public JsonCampfireRecipeHandler getMainRecipes()
{
return mainRecipes;

View File

@ -19,4 +19,5 @@ public interface IJsonConfig
void loadIncludedConfig(FMLInitializationEvent e, List<String> includedJsons);
void savePostLoad(File subfolder);
void saveAutoJson(File subfolder);
}

View File

@ -163,6 +163,10 @@ public class KilnConfig implements IJsonConfig
FileUtil.overwriteAllText(customf, json);
}
@Override
public void saveAutoJson(File subfolder)
{ }
public JsonKilnRecipeHandler getMainRecipes()
{
return mainRecipes;

View File

@ -136,6 +136,10 @@ public class RemovalConfig implements IJsonConfig
}
}
@Override
public void saveAutoJson(File subfolder)
{ }
public JsonRemoveRecipesHandler getCustomRecipes()
{
return customRecipes;

View File

@ -149,6 +149,10 @@ public class RepairInfusionConfig implements IJsonConfig
FileUtil.overwriteAllText(customf, json);
}
@Override
public void saveAutoJson(File subfolder)
{ }
public JsonRepairInfusionHandler getMainAssociations()
{
return mainAssociations;

View File

@ -165,6 +165,10 @@ public class SmelterConfig implements IJsonConfig
FileUtil.overwriteAllText(customf, json);
}
@Override
public void saveAutoJson(File subfolder)
{ }
public JsonSmelterRecipeHandler getMainRecipes()
{
return mainRecipes;

View File

@ -3,6 +3,7 @@ package net.einsteinsci.betterbeginnings.register;
import net.einsteinsci.betterbeginnings.config.BBConfig;
import net.einsteinsci.betterbeginnings.util.LogUtil;
import net.einsteinsci.betterbeginnings.util.RegistryUtil;
import net.einsteinsci.betterbeginnings.util.Util;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
@ -184,7 +185,7 @@ public class RemoveRecipes
boolean removeMe = false;
for (ItemStack customRemoved : customRemovedCraftingRecipes)
{
if (RegistryUtil.areItemStacksEqualIgnoreSize(customRemoved, result))
if (Util.areItemStacksEqualIgnoreSize(customRemoved, result))
{
LogUtil.logDebug(Level.INFO, "Custom removed crafting recipe for " + result.getDisplayName());
@ -265,7 +266,7 @@ public class RemoveRecipes
boolean removeMe = false;
for (ItemStack customRemoved : customRemovedFurnaceRecipes)
{
if (RegistryUtil.areItemStacksEqualIgnoreSize(customRemoved, result))
if (Util.areItemStacksEqualIgnoreSize(customRemoved, result))
{
removeMe = true;
break;

View File

@ -2,6 +2,7 @@ package net.einsteinsci.betterbeginnings.register.recipe;
import net.einsteinsci.betterbeginnings.tileentity.TileEntityBrickOven;
import net.einsteinsci.betterbeginnings.util.LogUtil;
import net.einsteinsci.betterbeginnings.util.Util;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
@ -204,6 +205,19 @@ public class BrickOvenRecipeHandler
return false;
}
public boolean existsRecipeFor(ItemStack stack)
{
for (IBrickOvenRecipe recipe : recipes)
{
if (Util.areItemStacksEqualIgnoreSize(recipe.getRecipeOutput(), stack))
{
return true;
}
}
return false;
}
public static List<IBrickOvenRecipe> getRecipeList()
{
return instance().recipes;

View File

@ -4,8 +4,16 @@ import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Tuple;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.oredict.OreDictionary;
import org.apache.logging.log4j.Level;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class RegistryUtil
{
@ -64,18 +72,135 @@ public class RegistryUtil
return getForgeName(stack.getItem());
}
public static boolean areItemStacksEqualIgnoreSize(ItemStack template, ItemStack tested)
public static String getModOwner(Item item)
{
if (template == null)
String forgeName = getForgeName(item);
String res = "";
for (char c : forgeName.toCharArray())
{
return tested == null;
}
else if (tested == null)
{
return false;
if (c == ':')
{
break;
}
res += c;
}
return template.getItem() == tested.getItem() && (template.getMetadata() == tested.getMetadata() ||
template.getMetadata() == OreDictionary.WILDCARD_VALUE);
return res;
}
public static String getCommonOreDictName(List<ItemStack> items)
{
List<String> commonNames = null;
for (ItemStack is : items)
{
if (commonNames == null)
{
commonNames = getOreNames(is);
}
else
{
List<String> compared = getOreNames(is);
Iterator<String> iter = commonNames.iterator();
while (iter.hasNext())
{
String s = iter.next();
if (!compared.contains(s))
{
iter.remove();
}
}
if (commonNames.isEmpty())
{
return null;
}
}
}
if (commonNames == null || commonNames.isEmpty())
{
return null;
}
return commonNames.get(0);
}
public static List<String> getOreNames(ItemStack item)
{
List<String> res = new ArrayList<>();
for (String ore : OreDictionary.getOreNames())
{
if (OreDictionary.getOres(ore).contains(item))
{
res.add(ore);
}
}
return res;
}
// Kinda sketchy
public static Tuple getRecipeCharacter(Map<Object, Character> map, Object obj, Character current)
{
boolean res = false;
Character token = '0';
if (obj instanceof ItemStack)
{
ItemStack stack = (ItemStack)obj;
boolean found = false;
for (Map.Entry<Object, Character> kvp : map.entrySet())
{
if (kvp.getKey() instanceof ItemStack)
{
ItemStack k = (ItemStack)kvp.getKey();
if (Util.areItemStacksEqualIgnoreSize(k, stack))
{
token = kvp.getValue();
found = true;
break;
}
}
}
if (!found)
{
map.put(stack, token);
res = true;
}
}
else if (obj instanceof List)
{
String ore = null;
try
{
ore = RegistryUtil.getCommonOreDictName((List<ItemStack>)obj);
}
catch (ClassCastException ex)
{
LogUtil.log(Level.ERROR, "Failed to cast list in ore dictionary conversion: " + ex.toString());
}
if (ore != null)
{
if (map.containsKey(ore))
{
token = map.get(ore);
}
else
{
map.put(ore, current);
res = true;
}
}
}
return new Tuple(res, token);
}
}

View File

@ -0,0 +1,62 @@
package net.einsteinsci.betterbeginnings.util;
import net.minecraft.item.ItemStack;
import net.minecraftforge.oredict.OreDictionary;
import java.lang.reflect.Field;
import java.util.List;
// General-purpose Util class
public class Util
{
public static boolean areItemStacksEqualIgnoreSize(ItemStack template, ItemStack tested)
{
if (template == null)
{
return tested == null;
}
else if (tested == null)
{
return false;
}
return template.getItem() == tested.getItem() && (template.getMetadata() == tested.getMetadata() ||
template.getMetadata() == OreDictionary.WILDCARD_VALUE);
}
public static <TObject, TField> TField getPrivateVariable(TObject obj, String fieldName)
{
Field privateStringField = null;
try
{
privateStringField = obj.getClass().getDeclaredField(fieldName);
}
catch (NoSuchFieldException e)
{
return null;
}
privateStringField.setAccessible(true);
try
{
return (TField)privateStringField.get(obj);
}
catch (IllegalAccessException e)
{
return null;
}
}
public static boolean listContainsItemStackIgnoreSize(List<ItemStack> list, ItemStack stack)
{
for (ItemStack s : list)
{
if (areItemStacksEqualIgnoreSize(s, stack))
{
return true;
}
}
return false;
}
}

View File

@ -124,6 +124,8 @@ blockbreak.success=Ouch! But at least it worked.
blockbreak.wrongtool=Wrong tool!
blockbreak.wrongtool.message=Requires %1$s %2$s.
command.jsongen.complete=JSON generation complete!
scroll.notool=No tool on table.
scroll.repaired=Tool is repaired.
scroll.error=Next ingredient is NULL.