From c81efe9779405a88afe7cb13eb1eb2112811cd32 Mon Sep 17 00:00:00 2001 From: Johannes Lohrer Date: Sat, 18 Apr 2015 22:24:30 +0200 Subject: [PATCH 1/7] moved recipes into own class for vanilla added gregtech recipe options --- src/main/scala/li/cil/oc/common/Proxy.scala | 3 +- .../li/cil/oc/common/recipe/Recipes.scala | 198 +++++++-------- .../scala/li/cil/oc/integration/Mods.scala | 5 +- .../oc/integration/gregtech/ModGregtech.scala | 2 + .../integration/gregtech/RecipeRegistry.scala | 236 ++++++++++++++++++ .../oc/integration/vanilla/ModVanilla.scala | 1 + .../integration/vanilla/RecipeRegistry.scala | 76 ++++++ 7 files changed, 404 insertions(+), 117 deletions(-) create mode 100644 src/main/scala/li/cil/oc/integration/gregtech/RecipeRegistry.scala create mode 100644 src/main/scala/li/cil/oc/integration/vanilla/RecipeRegistry.scala diff --git a/src/main/scala/li/cil/oc/common/Proxy.scala b/src/main/scala/li/cil/oc/common/Proxy.scala index 1dc753c2b..c23a90f90 100644 --- a/src/main/scala/li/cil/oc/common/Proxy.scala +++ b/src/main/scala/li/cil/oc/common/Proxy.scala @@ -77,13 +77,14 @@ class Proxy { OpenComputers.channel.register(server.PacketHandler) Loot.init() - Recipes.init() Achievement.init() EntityRegistry.registerModEntity(classOf[Drone], "Drone", 0, OpenComputers, 80, 1, true) OpenComputers.log.info("Initializing mod integration.") Mods.init() + OpenComputers.log.info("Initializing Recipes.") + Recipes.init() } def postInit(e: FMLPostInitializationEvent) { diff --git a/src/main/scala/li/cil/oc/common/recipe/Recipes.scala b/src/main/scala/li/cil/oc/common/recipe/Recipes.scala index 06dde6562..fe2328eb7 100644 --- a/src/main/scala/li/cil/oc/common/recipe/Recipes.scala +++ b/src/main/scala/li/cil/oc/common/recipe/Recipes.scala @@ -2,6 +2,7 @@ package li.cil.oc.common.recipe import java.io.File import java.io.FileReader +import java.util import com.typesafe.config._ import cpw.mods.fml.common.Loader @@ -22,6 +23,7 @@ import net.minecraft.item.ItemStack import net.minecraft.item.crafting.FurnaceRecipes import net.minecraft.nbt.NBTTagCompound import net.minecraft.util.RegistryNamespaced +import net.minecraftforge.fluids.{Fluid, FluidRegistry} import net.minecraftforge.oredict.OreDictionary import net.minecraftforge.oredict.RecipeSorter import net.minecraftforge.oredict.RecipeSorter.Category @@ -34,6 +36,12 @@ object Recipes { val list = mutable.LinkedHashMap.empty[ItemStack, String] val oreDictEntries = mutable.LinkedHashMap.empty[String, ItemStack] var hadErrors = false + val recipeMap = mutable.LinkedHashMap.empty[String, (ItemStack, Config) => Unit] + + + def registerRecipe(name: String, recipe: (ItemStack, Config) => Unit): Unit = { + recipeMap += name -> recipe + } def addBlock(instance: Block, name: String, oreDict: String = null) = { Items.registerBlock(instance, name) @@ -254,21 +262,10 @@ object Recipes { val recipe = list.getConfig(name) val recipeType = tryGetType(recipe) try { - recipeType match { - case "shaped" => addShapedRecipe(output, recipe) - case "shapeless" => addShapelessRecipe(output, recipe) - case "furnace" => addFurnaceRecipe(output, recipe) - case "gt_assembler" => - if (Mods.GregTech.isAvailable) { - addGTAssemblingMachineRecipe(output, recipe) - } - else { - OpenComputers.log.error(s"Skipping GregTech assembler recipe for '$name' because GregTech is not present, you will not be able to craft this item.") - hadErrors = true - } - case other => - OpenComputers.log.error(s"Failed adding recipe for '$name', you will not be able to craft this item. The error was: Invalid recipe type '$other'.") - hadErrors = true + recipeMap.get(recipeType) match { + case Some(x) => x(output, recipe) + case _ => OpenComputers.log.error(s"Failed adding $recipeType recipe for '$name', you will not be able to craft this item!") + } } catch { @@ -291,106 +288,79 @@ object Recipes { hadErrors = true } } - catch { - case e: Throwable => - OpenComputers.log.error(s"Failed adding recipe for '$name', you will not be able to craft this item.", e) - hadErrors = true + + // private def addRecipe(output: ItemStack, list: Config, name: String) = try { + // if (list.hasPath(name)) { + // val value = list.getValue(name) + // value.valueType match { + // case ConfigValueType.OBJECT => + // val recipe = list.getConfig(name) + // val recipeType = tryGetType(recipe) + // try { + // recipeType match { + // case "shaped" => addShapedRecipe(output, recipe) + // case "shapeless" => addShapelessRecipe(output, recipe) + // case "furnace" => addFurnaceRecipe(output, recipe) + // case "gt_assembler" => + // if (Mods.GregTech.isAvailable) { + // addGTAssemblingMachineRecipe(output, recipe) + // } + // else { + // OpenComputers.log.error(s"Skipping GregTech assembler recipe for '$name' because GregTech is not present, you will not be able to craft this item.") + // hadErrors = true + // } + // case "gt_alloysmelter" => + // if (Mods.GregTech.isAvailable) { + // addGTAlloySmelterRecipe(output, recipe) + // } + // else { + // OpenComputers.log.error(s"Skipping GregTech alloy smelter recipe for '$name' because GregTech is not present, you will not be able to craft this item.") + // hadErrors = true + // } + // case other => + // OpenComputers.log.error(s"Failed adding recipe for '$name', you will not be able to craft this item. The error was: Invalid recipe type '$other'.") + // hadErrors = true + // } + // } + // catch { + // case e: RecipeException => + // OpenComputers.log.error(s"Failed adding $recipeType recipe for '$name', you will not be able to craft this item! The error was: ${e.getMessage}") + // hadErrors = true + // } + // case ConfigValueType.BOOLEAN => + // // Explicitly disabled, keep in NEI if true. + // if (!value.unwrapped.asInstanceOf[Boolean]) { + // hide(output) + // } + // case _ => + // OpenComputers.log.error(s"Failed adding recipe for '$name', you will not be able to craft this item. The error was: Invalid value for recipe.") + // hadErrors = true + // } + // } + // else { + // OpenComputers.log.warn(s"No recipe for '$name', you will not be able to craft this item. To suppress this warning, disable the recipe (assign `false` to it).") + // hadErrors = true + // } + // } + // catch { + // case e: Throwable => + // OpenComputers.log.error(s"Failed adding recipe for '$name', you will not be able to craft this item.", e) + // hadErrors = true + // } + + + def parseFluidIngredient(entry: AnyRef): Option[Fluid] = entry match { + case name: String => { + if (name == null || name.trim.isEmpty) None + else if (FluidRegistry.getFluid(name) != null) Option(FluidRegistry.getFluid(name)) + else None + } + case _ => None + } - private def addShapedRecipe(output: ItemStack, recipe: Config) { - val rows = recipe.getList("input").unwrapped().map { - case row: java.util.List[AnyRef]@unchecked => row.map(parseIngredient) - case other => throw new RecipeException(s"Invalid row entry for shaped recipe (not a list: $other).") - } - output.stackSize = tryGetCount(recipe) - var number = -1 - var shape = mutable.ArrayBuffer.empty[String] - val input = mutable.ArrayBuffer.empty[AnyRef] - for (row <- rows) { - val (pattern, ingredients) = row.foldLeft((new StringBuilder, Seq.empty[AnyRef]))((acc, ingredient) => { - val (pattern, ingredients) = acc - ingredient match { - case _@(_: ItemStack | _: String) => - number += 1 - (pattern.append(('a' + number).toChar), ingredients ++ Seq(Char.box(('a' + number).toChar), ingredient)) - case _ => (pattern.append(' '), ingredients) - } - }) - shape += pattern.toString - input ++= ingredients - } - if (input.size > 0 && output.stackSize > 0) { - GameRegistry.addRecipe(new ExtendedShapedOreRecipe(output, shape ++ input: _*)) - } - } - - private def addShapelessRecipe(output: ItemStack, recipe: Config) { - val input = recipe.getValue("input").unwrapped() match { - case list: java.util.List[AnyRef]@unchecked => list.map(parseIngredient) - case other => Seq(parseIngredient(other)) - } - output.stackSize = tryGetCount(recipe) - - if (input.size > 0 && output.stackSize > 0) { - GameRegistry.addRecipe(new ExtendedShapelessOreRecipe(output, input: _*)) - } - } - - private def addGTAssemblingMachineRecipe(output: ItemStack, recipe: Config) { - val inputs = (recipe.getValue("input").unwrapped() match { - case list: java.util.List[AnyRef]@unchecked => list.map(parseIngredient) - case other => Seq(parseIngredient(other)) - }) map { - case null => Array.empty[ItemStack] - case stack: ItemStack => Array(stack) - case name: String => Array(OreDictionary.getOres(name): _*) - case other => throw new RecipeException(s"Invalid ingredient type: $other.") - } - output.stackSize = tryGetCount(recipe) - - if (inputs.size < 1 || inputs.size > 2) { - throw new RecipeException(s"Invalid recipe length: ${inputs.size}, should be 1 or 2.") - } - - val inputCount = recipe.getIntList("count") - if (inputCount.size() != inputs.size) { - throw new RecipeException(s"Ingredient and input count mismatch: ${inputs.size} != ${inputCount.size}.") - } - - val eu = recipe.getInt("eu") - val duration = recipe.getInt("time") - - (inputs, inputCount).zipped.foreach((stacks, count) => stacks.foreach(stack => if (stack != null && count > 0) stack.stackSize = stack.getMaxStackSize min count)) - inputs.padTo(2, null) - - if (inputs.head != null) { - for (input1 <- inputs.head) { - if (inputs.last != null) { - for (input2 <- inputs.last) - gregtech.api.GregTech_API.sRecipeAdder.addAssemblerRecipe(input1, input2, output, duration, eu) - } - else gregtech.api.GregTech_API.sRecipeAdder.addAssemblerRecipe(input1, null, output, duration, eu) - } - } - } - - private def addFurnaceRecipe(output: ItemStack, recipe: Config) { - val input = parseIngredient(recipe.getValue("input").unwrapped()) - output.stackSize = tryGetCount(recipe) - - input match { - case stack: ItemStack => - FurnaceRecipes.smelting.func_151394_a(stack, output, 0) - case name: String => - for (stack <- OreDictionary.getOres(name)) { - FurnaceRecipes.smelting.func_151394_a(stack, output, 0) - } - case _ => - } - } - - private def parseIngredient(entry: AnyRef) = entry match { + def parseIngredient(entry: AnyRef) = entry match { case map: java.util.Map[AnyRef, AnyRef]@unchecked => if (map.contains("oreDict")) { map.get("oreDict") match { @@ -453,7 +423,7 @@ object Recipes { private def tryGetType(recipe: Config) = if (recipe.hasPath("type")) recipe.getString("type") else "shaped" - private def tryGetCount(recipe: Config) = if (recipe.hasPath("output")) recipe.getInt("output") else 1 + def tryGetCount(recipe: Config) = if (recipe.hasPath("output")) recipe.getInt("output") else 1 private def tryGetId(ingredient: java.util.Map[AnyRef, AnyRef]): Int = if (ingredient.contains("subID")) ingredient.get("subID") match { @@ -492,6 +462,6 @@ object Recipes { } } - private class RecipeException(message: String) extends RuntimeException(message) + class RecipeException(message: String) extends RuntimeException(message) } diff --git a/src/main/scala/li/cil/oc/integration/Mods.scala b/src/main/scala/li/cil/oc/integration/Mods.scala index 49198bd73..dadd4cec3 100644 --- a/src/main/scala/li/cil/oc/integration/Mods.scala +++ b/src/main/scala/li/cil/oc/integration/Mods.scala @@ -40,7 +40,7 @@ object Mods { val Forestry = new SimpleMod(IDs.Forestry) val ForgeMultipart = new SimpleMod(IDs.ForgeMultipart) val Galacticraft = new SimpleMod(IDs.Galacticraft, providesPower = true) - val GregTech = new ClassBasedMod(IDs.GregTech,"gregtech.api.GregTech_API")() + val GregTech = new ClassBasedMod(IDs.GregTech, "gregtech.api.GregTech_API")() val IndustrialCraft2 = new SimpleMod(IDs.IndustrialCraft2, providesPower = true) val IndustrialCraft2Classic = new SimpleMod(IDs.IndustrialCraft2Classic, providesPower = true) val Mekanism = new SimpleMod(IDs.Mekanism, providesPower = true) @@ -155,7 +155,8 @@ object Mods { final val Factorization = "factorization" final val Forestry = "Forestry" final val ForgeMultipart = "ForgeMultipart" - final val DeepStorageUnit = "MineFactoryReloaded|DeepStorageUnit" // Doesn't really exist. + final val DeepStorageUnit = "MineFactoryReloaded|DeepStorageUnit" + // Doesn't really exist. final val Galacticraft = "Galacticraft API" final val GregTech = "gregtech" final val IndustrialCraft2 = "IC2" diff --git a/src/main/scala/li/cil/oc/integration/gregtech/ModGregtech.scala b/src/main/scala/li/cil/oc/integration/gregtech/ModGregtech.scala index 4ea66e917..a4400b938 100644 --- a/src/main/scala/li/cil/oc/integration/gregtech/ModGregtech.scala +++ b/src/main/scala/li/cil/oc/integration/gregtech/ModGregtech.scala @@ -15,5 +15,7 @@ object ModGregtech extends ModProxy { MinecraftForge.EVENT_BUS.register(EventHandlerGregTech) Driver.add(new DriverEnergyContainer) + + RecipeRegistry.init() } } \ No newline at end of file diff --git a/src/main/scala/li/cil/oc/integration/gregtech/RecipeRegistry.scala b/src/main/scala/li/cil/oc/integration/gregtech/RecipeRegistry.scala new file mode 100644 index 000000000..d5808e2ca --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/gregtech/RecipeRegistry.scala @@ -0,0 +1,236 @@ +package li.cil.oc.integration.gregtech + +import java.util + +import com.typesafe.config.Config +import li.cil.oc.common.recipe.Recipes +import li.cil.oc.common.recipe.Recipes.RecipeException +import net.minecraft.item.ItemStack +import net.minecraftforge.fluids.FluidStack +import net.minecraftforge.oredict.OreDictionary + +import scala.collection.convert.WrapAsScala._ + +object RecipeRegistry { + + def getGTRecipesWithEU(output: ItemStack, recipe: Config): (Array[ItemStack], Option[Array[ItemStack]], Option[FluidStack], Option[FluidStack], Option[ItemStack], Int, Int) = { + + val inputs = (recipe.getValue("input").unwrapped() match { + case list: util.List[AnyRef]@unchecked => list.map(Recipes.parseIngredient) + case other => Seq(Recipes.parseIngredient(other)) + }) map { + case null => Array.empty[ItemStack] + case stack: ItemStack => Array(stack) + case name: String => Array(OreDictionary.getOres(name): _*) + case other => throw new RecipeException(s"Invalid ingredient type: $other.") + } + output.stackSize = Recipes.tryGetCount(recipe) + + if (inputs.size < 1 || inputs.size > 2) { + throw new RecipeException(s"Invalid recipe length: ${inputs.size}, should be 1 or 2.") + } + + val inputCount = recipe.getIntList("count") + if (inputCount.size() != inputs.size) { + throw new RecipeException(s"Ingredient and input count mismatch: ${inputs.size} != ${inputCount.size}.") + } + + var inputFluidStack: Option[FluidStack] = None: Option[FluidStack] + if (recipe.hasPath("inputLiquid")) Recipes.parseFluidIngredient(recipe.getString("inputLiquid")) match { + case Some(fluid) => + var inputFluidAmount = 1000 + if (recipe.hasPath("inputFluidAmount")) inputFluidAmount = recipe.getInt("inputFluidAmount") + inputFluidStack = Option(new FluidStack(fluid, inputFluidAmount)) + case _ => + } + + var outputFluidStack: Option[FluidStack] = None: Option[FluidStack] + if (recipe.hasPath("outputLiquid")) Recipes.parseFluidIngredient(recipe.getString("outputLiquid")) match { + case Some(fluid) => + var fluidAmount = 1000 + if (recipe.hasPath("outputFluidAmount")) fluidAmount = recipe.getInt("outputFluidAmount") + outputFluidStack = Option(new FluidStack(fluid, fluidAmount)) + case _ => + } + + val eu = recipe.getInt("eu") + val duration = recipe.getInt("time") + + //TODO add output + val additionalOutput: Option[ItemStack] = None + + (inputs, inputCount).zipped.foreach((stacks, count) => stacks.foreach(stack => if (stack != null && count > 0) stack.stackSize = stack.getMaxStackSize min count)) + inputs.padTo(2, null) + val input = inputs.head + (input, Option(inputs.last), inputFluidStack, outputFluidStack, additionalOutput, eu, duration) + } + + def addGTAlloySmelterRecipe(output: ItemStack, recipe: Config) { + val (inputs1, inputs2, fluidStackIn, fluidStackOut, additionalOutput, eu, duration) = getGTRecipesWithEU(output, recipe) + for (input1 <- inputs1) { + inputs2 match { + case Some(inputs2List) => + for (input2 <- inputs2List) + gregtech.api.GregTech_API.sRecipeAdder.addAlloySmelterRecipe(input1, input2, output, duration, eu) + case None => + gregtech.api.GregTech_API.sRecipeAdder.addAlloySmelterRecipe(input1, null, output, duration, eu) + } + } + } + + def addGTAssemblingMachineRecipe(output: ItemStack, recipe: Config) { + val (inputs1, inputs2, fluidStackIn, fluidStackOut, additionalOutput, eu, duration) = getGTRecipesWithEU(output, recipe) + for (input1 <- inputs1) { + inputs2 match { + case Some(inputs2List) => + for (input2 <- inputs2List) + fluidStackIn match { + case Some(fluid) => + + gregtech.api.GregTech_API.sRecipeAdder.addAssemblerRecipe(input1, input2, fluid, output, duration, eu) + case None => + gregtech.api.GregTech_API.sRecipeAdder.addAssemblerRecipe(input1, input2, output, duration, eu) + } + + case None => + fluidStackIn match { + case Some(fluid) => + gregtech.api.GregTech_API.sRecipeAdder.addAssemblerRecipe(input1, null, fluid, output, duration, eu) + case None => + gregtech.api.GregTech_API.sRecipeAdder.addAssemblerRecipe(input1, null, output, duration, eu) + } + } + } + } + + def addGTBenderRecipe(output: ItemStack, recipe: Config) { + val (inputs1, inputs2, fluidStackIn, fluidStackOut, additionalOutput, eu, duration) = getGTRecipesWithEU(output, recipe) + for (input1 <- inputs1) { + gregtech.api.GregTech_API.sRecipeAdder.addBenderRecipe(input1, output, duration, eu) + } + } + + def addGTCutterRecipe(output: ItemStack, recipe: Config) { + val (inputs1, inputs2, fluidStackIn, fluidStackOut, additionalOutput, eu, duration) = getGTRecipesWithEU(output, recipe) + var add :ItemStack = null + additionalOutput match{ + case Some(a) => add = a + case _=> + } + for (input1 <- inputs1) { + fluidStackIn match { + case Some(fluid) => + gregtech.api.GregTech_API.sRecipeAdder.addCutterRecipe(input1, fluid, output, add, duration, eu) + + case None => + gregtech.api.GregTech_API.sRecipeAdder.addCutterRecipe(input1, output, add, duration, eu) + } + } + } + + def addGTCannerRecipe(output: ItemStack, recipe: Config) { + val (inputs1, inputs2, fluidStackIn, fluidStackOut, additionalOutput, eu, duration) = getGTRecipesWithEU(output, recipe) + var add :ItemStack = null + additionalOutput match{ + case Some(a) => add = a + case _=> + } + for (input1 <- inputs1) { + inputs2 match { + case Some(inputs2List) => + for (input2 <- inputs2List) + gregtech.api.GregTech_API.sRecipeAdder.addCannerRecipe(input1, input2, output, add, duration, eu) + case None => + gregtech.api.GregTech_API.sRecipeAdder.addCannerRecipe(input1, null, output, add, duration, eu) + + + } + } + } + + def addGTChemicalRecipe(output: ItemStack, recipe: Config) { + val (inputs1, inputs2, fluidStackIn, fluidStackOut, additionalOutput, eu, duration) = getGTRecipesWithEU(output, recipe) + for (input1 <- inputs1) { + inputs2 match { + case Some(inputs2List) => + for (input2 <- inputs2List) + fluidStackIn match { + case Some(fluid) => + fluidStackOut match { + case Some(fluidOut) => + gregtech.api.GregTech_API.sRecipeAdder.addChemicalRecipe(input1, input2, fluid, fluidOut, output, duration) + + case _ => + gregtech.api.GregTech_API.sRecipeAdder.addChemicalRecipe(input1, input2, fluid, null, output, duration) + } + case None => + fluidStackOut match { + case Some(fluidOut) => + gregtech.api.GregTech_API.sRecipeAdder.addChemicalRecipe(input1, input2, null, fluidOut, output, duration) + case _ => + gregtech.api.GregTech_API.sRecipeAdder.addChemicalRecipe(input1, input2, output, duration) + } + } + + case None => + fluidStackIn match { + case Some(fluid) => + fluidStackOut match { + case Some(fluidOut) => + gregtech.api.GregTech_API.sRecipeAdder.addChemicalRecipe(input1, null, fluid, fluidOut, output, duration) + + case _ => + gregtech.api.GregTech_API.sRecipeAdder.addChemicalRecipe(input1, null, fluid, null, output, duration) + } + case None => + fluidStackOut match { + case Some(fluidOut) => + gregtech.api.GregTech_API.sRecipeAdder.addChemicalRecipe(input1, null, null, fluidOut, output, duration) + case _ => + gregtech.api.GregTech_API.sRecipeAdder.addChemicalRecipe(input1, null, output, duration) + } + } + } + } + } + + def addGTCNCRecipe(output: ItemStack, recipe: Config) { + val (inputs1, inputs2, fluidStackIn, fluidStackOut, additionalOutput, eu, duration) = getGTRecipesWithEU(output, recipe) + for (input1 <- inputs1) { + gregtech.api.GregTech_API.sRecipeAdder.addCNCRecipe(input1, output, duration, eu) + } + } + + def addGTLatheRecipe(output: ItemStack, recipe: Config) { + val (inputs1, inputs2, fluidStackIn, fluidStackOut, additionalOutput, eu, duration) = getGTRecipesWithEU(output, recipe) + var add :ItemStack = null + additionalOutput match{ + case Some(a) => add = a + case _=> + } + for (input1 <- inputs1) { + gregtech.api.GregTech_API.sRecipeAdder.addLatheRecipe(input1, output, add, duration, eu) + } + } + + def addGTWireMillRecipe(output: ItemStack, recipe: Config) { + val (inputs1, inputs2, fluidStackIn, fluidStackOut, additionalOutput, eu, duration) = getGTRecipesWithEU(output, recipe) + for (input1 <- inputs1) { + gregtech.api.GregTech_API.sRecipeAdder.addWiremillRecipe(input1, output, duration, eu) + } + } + + + def init(): Unit = { + Recipes.registerRecipe("gt_alloySmelter", addGTAlloySmelterRecipe) + Recipes.registerRecipe("gt_assembler", addGTAssemblingMachineRecipe) + Recipes.registerRecipe("gt_bender", addGTBenderRecipe) + Recipes.registerRecipe("gt_canner", addGTCannerRecipe) + Recipes.registerRecipe("gt_chemical", addGTChemicalRecipe) + Recipes.registerRecipe("gt_cnc", addGTCNCRecipe) + Recipes.registerRecipe("gt_cutter", addGTCutterRecipe) + Recipes.registerRecipe("gt_lathe", addGTLatheRecipe) + Recipes.registerRecipe("gt_wiremill", addGTWireMillRecipe) + + } +} diff --git a/src/main/scala/li/cil/oc/integration/vanilla/ModVanilla.scala b/src/main/scala/li/cil/oc/integration/vanilla/ModVanilla.scala index d428dc3a1..5aeae9039 100644 --- a/src/main/scala/li/cil/oc/integration/vanilla/ModVanilla.scala +++ b/src/main/scala/li/cil/oc/integration/vanilla/ModVanilla.scala @@ -34,5 +34,6 @@ object ModVanilla extends ModProxy { Driver.add(ConverterNBT) Driver.add(ConverterWorld) Driver.add(ConverterWorldProvider) + RecipeRegistry.init() } } diff --git a/src/main/scala/li/cil/oc/integration/vanilla/RecipeRegistry.scala b/src/main/scala/li/cil/oc/integration/vanilla/RecipeRegistry.scala new file mode 100644 index 000000000..007685b7b --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/vanilla/RecipeRegistry.scala @@ -0,0 +1,76 @@ +package li.cil.oc.integration.vanilla + +import com.typesafe.config.Config +import cpw.mods.fml.common.registry.GameRegistry +import li.cil.oc.common.recipe.Recipes.RecipeException +import li.cil.oc.common.recipe.{Recipes, ExtendedShapelessOreRecipe, ExtendedShapedOreRecipe} +import net.minecraft.item.ItemStack +import net.minecraft.item.crafting.FurnaceRecipes +import net.minecraftforge.oredict.OreDictionary + +import scala.collection.convert.WrapAsScala._ +import scala.collection.mutable + +object RecipeRegistry { + + def addShapedRecipe(output: ItemStack, recipe: Config) { + val rows = recipe.getList("input").unwrapped().map { + case row: java.util.List[AnyRef]@unchecked => row.map(Recipes.parseIngredient) + case other => throw new RecipeException(s"Invalid row entry for shaped recipe (not a list: $other).") + } + output.stackSize = Recipes.tryGetCount(recipe) + + var number = -1 + var shape = mutable.ArrayBuffer.empty[String] + val input = mutable.ArrayBuffer.empty[AnyRef] + for (row <- rows) { + val (pattern, ingredients) = row.foldLeft((new StringBuilder, Seq.empty[AnyRef]))((acc, ingredient) => { + val (pattern, ingredients) = acc + ingredient match { + case _@(_: ItemStack | _: String) => + number += 1 + (pattern.append(('a' + number).toChar), ingredients ++ Seq(Char.box(('a' + number).toChar), ingredient)) + case _ => (pattern.append(' '), ingredients) + } + }) + shape += pattern.toString + input ++= ingredients + } + if (input.size > 0 && output.stackSize > 0) { + GameRegistry.addRecipe(new ExtendedShapedOreRecipe(output, shape ++ input: _*)) + } + } + + def addShapelessRecipe(output: ItemStack, recipe: Config) { + val input = recipe.getValue("input").unwrapped() match { + case list: java.util.List[AnyRef]@unchecked => list.map(Recipes.parseIngredient) + case other => Seq(Recipes.parseIngredient(other)) + } + output.stackSize = Recipes.tryGetCount(recipe) + + if (input.size > 0 && output.stackSize > 0) { + GameRegistry.addRecipe(new ExtendedShapelessOreRecipe(output, input: _*)) + } + } + + def addFurnaceRecipe(output: ItemStack, recipe: Config) { + val input = Recipes.parseIngredient(recipe.getValue("input").unwrapped()) + output.stackSize = Recipes.tryGetCount(recipe) + + input match { + case stack: ItemStack => + FurnaceRecipes.smelting.func_151394_a(stack, output, 0) + case name: String => + for (stack <- OreDictionary.getOres(name)) { + FurnaceRecipes.smelting.func_151394_a(stack, output, 0) + } + case _ => + } + } + + def init(): Unit = { + Recipes.registerRecipe("shaped", addShapedRecipe) + Recipes.registerRecipe("shapeless", addShapelessRecipe) + Recipes.registerRecipe("furnace", addFurnaceRecipe) + } +} From f534e1b3b6fc5e7017050e5d71edfccb9674e01d Mon Sep 17 00:00:00 2001 From: Johannes Lohrer Date: Sun, 19 Apr 2015 20:50:13 +0200 Subject: [PATCH 2/7] made additional outputs a sequence to allow additional machines so these commits should basically close #760 --- .../integration/gregtech/RecipeRegistry.scala | 48 +++++++++++++------ 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/src/main/scala/li/cil/oc/integration/gregtech/RecipeRegistry.scala b/src/main/scala/li/cil/oc/integration/gregtech/RecipeRegistry.scala index d5808e2ca..bfd69d8ec 100644 --- a/src/main/scala/li/cil/oc/integration/gregtech/RecipeRegistry.scala +++ b/src/main/scala/li/cil/oc/integration/gregtech/RecipeRegistry.scala @@ -13,7 +13,7 @@ import scala.collection.convert.WrapAsScala._ object RecipeRegistry { - def getGTRecipesWithEU(output: ItemStack, recipe: Config): (Array[ItemStack], Option[Array[ItemStack]], Option[FluidStack], Option[FluidStack], Option[ItemStack], Int, Int) = { + def getGTRecipesWithEU(output: ItemStack, recipe: Config): (Array[ItemStack], Option[Array[ItemStack]], Option[FluidStack], Option[FluidStack], Seq[ItemStack], Int, Int) = { val inputs = (recipe.getValue("input").unwrapped() match { case list: util.List[AnyRef]@unchecked => list.map(Recipes.parseIngredient) @@ -55,11 +55,34 @@ object RecipeRegistry { val eu = recipe.getInt("eu") val duration = recipe.getInt("time") + var additionalOutput = Seq.empty[ItemStack] + if(recipe.hasPath("additionalOutput")) + { + additionalOutput = (recipe.getValue("additionalOutput").unwrapped() match { + case list: util.List[AnyRef]@unchecked => list.map(Recipes.parseIngredient) + case other => Seq(Recipes.parseIngredient(other)) + }) map { + case stack: ItemStack => stack + case name: String => val ores = OreDictionary.getOres(name) + if(ores.size()>0) + ores.get(0) + else + null + case other => throw new RecipeException(s"Invalid ingredient type: $other.") + } + + val outputCount = recipe.getIntList("outputCount") + if (outputCount.size() != additionalOutput.size) { + throw new RecipeException(s"Outputs and output count mismatch: ${additionalOutput.size} != ${outputCount.size}.") + } + (additionalOutput, outputCount).zipped.foreach((stack, count) => if (stack != null && count > 0) stack.stackSize = stack.getMaxStackSize min count) + } - //TODO add output - val additionalOutput: Option[ItemStack] = None (inputs, inputCount).zipped.foreach((stacks, count) => stacks.foreach(stack => if (stack != null && count > 0) stack.stackSize = stack.getMaxStackSize min count)) + + + inputs.padTo(2, null) val input = inputs.head (input, Option(inputs.last), inputFluidStack, outputFluidStack, additionalOutput, eu, duration) @@ -113,10 +136,8 @@ object RecipeRegistry { def addGTCutterRecipe(output: ItemStack, recipe: Config) { val (inputs1, inputs2, fluidStackIn, fluidStackOut, additionalOutput, eu, duration) = getGTRecipesWithEU(output, recipe) var add :ItemStack = null - additionalOutput match{ - case Some(a) => add = a - case _=> - } + if(additionalOutput.size>1) + add = additionalOutput.head for (input1 <- inputs1) { fluidStackIn match { case Some(fluid) => @@ -131,10 +152,9 @@ object RecipeRegistry { def addGTCannerRecipe(output: ItemStack, recipe: Config) { val (inputs1, inputs2, fluidStackIn, fluidStackOut, additionalOutput, eu, duration) = getGTRecipesWithEU(output, recipe) var add :ItemStack = null - additionalOutput match{ - case Some(a) => add = a - case _=> - } + if(additionalOutput.size>1) + add = additionalOutput.head + for (input1 <- inputs1) { inputs2 match { case Some(inputs2List) => @@ -204,10 +224,8 @@ object RecipeRegistry { def addGTLatheRecipe(output: ItemStack, recipe: Config) { val (inputs1, inputs2, fluidStackIn, fluidStackOut, additionalOutput, eu, duration) = getGTRecipesWithEU(output, recipe) var add :ItemStack = null - additionalOutput match{ - case Some(a) => add = a - case _=> - } + if(additionalOutput.size>1) + add = additionalOutput.head for (input1 <- inputs1) { gregtech.api.GregTech_API.sRecipeAdder.addLatheRecipe(input1, output, add, duration, eu) } From 7a248833b7f92c5f6fee8148b656ae8743b7cc80 Mon Sep 17 00:00:00 2001 From: Johannes Lohrer Date: Sun, 19 Apr 2015 20:50:13 +0200 Subject: [PATCH 3/7] made additional outputs a sequence to allow additional machines so these commits should basically close #760 --- .../integration/gregtech/RecipeRegistry.scala | 53 ++++++++++++------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/src/main/scala/li/cil/oc/integration/gregtech/RecipeRegistry.scala b/src/main/scala/li/cil/oc/integration/gregtech/RecipeRegistry.scala index d5808e2ca..35a886133 100644 --- a/src/main/scala/li/cil/oc/integration/gregtech/RecipeRegistry.scala +++ b/src/main/scala/li/cil/oc/integration/gregtech/RecipeRegistry.scala @@ -13,7 +13,7 @@ import scala.collection.convert.WrapAsScala._ object RecipeRegistry { - def getGTRecipesWithEU(output: ItemStack, recipe: Config): (Array[ItemStack], Option[Array[ItemStack]], Option[FluidStack], Option[FluidStack], Option[ItemStack], Int, Int) = { + def getGTRecipesWithEU(output: ItemStack, recipe: Config): (Array[ItemStack], Option[Array[ItemStack]], Option[FluidStack], Option[FluidStack], Seq[ItemStack], Int, Int) = { val inputs = (recipe.getValue("input").unwrapped() match { case list: util.List[AnyRef]@unchecked => list.map(Recipes.parseIngredient) @@ -55,11 +55,33 @@ object RecipeRegistry { val eu = recipe.getInt("eu") val duration = recipe.getInt("time") + var additionalOutput = Seq.empty[ItemStack] + if (recipe.hasPath("additionalOutput")) { + additionalOutput = (recipe.getValue("additionalOutput").unwrapped() match { + case list: util.List[AnyRef]@unchecked => list.map(Recipes.parseIngredient) + case other => Seq(Recipes.parseIngredient(other)) + }) map { + case stack: ItemStack => stack + case name: String => val ores = OreDictionary.getOres(name) + if (ores.size() > 0) + ores.get(0) + else + null + case other => throw new RecipeException(s"Invalid ingredient type: $other.") + } + + val outputCount = recipe.getIntList("outputCount") + if (outputCount.size() != additionalOutput.size) { + throw new RecipeException(s"Outputs and output count mismatch: ${additionalOutput.size} != ${outputCount.size}.") + } + (additionalOutput, outputCount).zipped.foreach((stack, count) => if (stack != null && count > 0) stack.stackSize = stack.getMaxStackSize min count) + } - //TODO add output - val additionalOutput: Option[ItemStack] = None (inputs, inputCount).zipped.foreach((stacks, count) => stacks.foreach(stack => if (stack != null && count > 0) stack.stackSize = stack.getMaxStackSize min count)) + + + inputs.padTo(2, null) val input = inputs.head (input, Option(inputs.last), inputFluidStack, outputFluidStack, additionalOutput, eu, duration) @@ -112,11 +134,9 @@ object RecipeRegistry { def addGTCutterRecipe(output: ItemStack, recipe: Config) { val (inputs1, inputs2, fluidStackIn, fluidStackOut, additionalOutput, eu, duration) = getGTRecipesWithEU(output, recipe) - var add :ItemStack = null - additionalOutput match{ - case Some(a) => add = a - case _=> - } + var add: ItemStack = null + if (additionalOutput.size > 1) + add = additionalOutput.head for (input1 <- inputs1) { fluidStackIn match { case Some(fluid) => @@ -130,11 +150,10 @@ object RecipeRegistry { def addGTCannerRecipe(output: ItemStack, recipe: Config) { val (inputs1, inputs2, fluidStackIn, fluidStackOut, additionalOutput, eu, duration) = getGTRecipesWithEU(output, recipe) - var add :ItemStack = null - additionalOutput match{ - case Some(a) => add = a - case _=> - } + var add: ItemStack = null + if (additionalOutput.size > 1) + add = additionalOutput.head + for (input1 <- inputs1) { inputs2 match { case Some(inputs2List) => @@ -203,11 +222,9 @@ object RecipeRegistry { def addGTLatheRecipe(output: ItemStack, recipe: Config) { val (inputs1, inputs2, fluidStackIn, fluidStackOut, additionalOutput, eu, duration) = getGTRecipesWithEU(output, recipe) - var add :ItemStack = null - additionalOutput match{ - case Some(a) => add = a - case _=> - } + var add: ItemStack = null + if (additionalOutput.size > 1) + add = additionalOutput.head for (input1 <- inputs1) { gregtech.api.GregTech_API.sRecipeAdder.addLatheRecipe(input1, output, add, duration, eu) } From a8389f705671eb285b6a550d93a7a88a8ee9f8fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Mon, 20 Apr 2015 12:44:34 +0200 Subject: [PATCH 4/7] Documented GT recipe handlers in recipe set. Renamed a few things, simplified a few things, scalafied a few things. --- .../opencomputers/recipes/gregtech.recipes | 28 ++ src/main/scala/li/cil/oc/common/Proxy.scala | 3 +- .../li/cil/oc/common/recipe/Recipes.scala | 55 ++-- .../scala/li/cil/oc/integration/Mods.scala | 3 +- .../oc/integration/gregtech/ModGregtech.scala | 2 +- .../integration/gregtech/RecipeHandler.scala | 188 +++++++++++++ .../integration/gregtech/RecipeRegistry.scala | 253 ------------------ .../oc/integration/vanilla/ModVanilla.scala | 3 +- ...cipeRegistry.scala => RecipeHandler.scala} | 21 +- 9 files changed, 256 insertions(+), 300 deletions(-) create mode 100644 src/main/scala/li/cil/oc/integration/gregtech/RecipeHandler.scala delete mode 100644 src/main/scala/li/cil/oc/integration/gregtech/RecipeRegistry.scala rename src/main/scala/li/cil/oc/integration/vanilla/{RecipeRegistry.scala => RecipeHandler.scala} (83%) diff --git a/src/main/resources/assets/opencomputers/recipes/gregtech.recipes b/src/main/resources/assets/opencomputers/recipes/gregtech.recipes index 398be6a8d..d7855fe98 100644 --- a/src/main/resources/assets/opencomputers/recipes/gregtech.recipes +++ b/src/main/resources/assets/opencomputers/recipes/gregtech.recipes @@ -1,6 +1,34 @@ # Do not change this file, it is rewritten each time you start the game. # Instead, use the user.recipes file to edit recipes by redefining them there. +# Note that there is support for a number of GregTech machines, by using the +# appropriate `type` specifier. Available types are: +# - gt_alloySmelter : Alloy Smelter Recipe +# - gt_assembler : Circuit Assembler Machine +# - gt_bender : Plate Bending Machine Recipe +# - gt_canner : Canning Machine Recipe +# - gt_chemical : Chemical Recipe +# - gt_cnc : CNC-Machine Recipe +# - gt_cutter : Cutter Recipe +# - gt_lathe : Lathe Machine Recipe +# - gt_wiremill : Wiremill Recipe +# +# For these types, there a few more options for inputs and outputs. A full +# recipe using all these options would look like this: +# name { +# type: gt_??? +# input: ["primaryInput", "possiblyOptionalSecondaryInput"] +# count: [1, 2] # would mean 1 of primary, 2 of secondary +# output: 2 # size of primary output stack +# eu: EU consumed for the operation +# time: time it takes to complete the operation, in ticks. +# # The following are usually optional. +# secondaryOutput: ["secondaryOutput1", "secondaryOutput2"] # Max number depends on machine. +# secondaryOutputCount: [2, 2] # Like `count` to `input`. +# inputFluid: {name="water", amount="500"} +# outputFluid: {name="lava"} # defaults to amount = 1000 +# } + include file("hardmode.recipes") analyzer { diff --git a/src/main/scala/li/cil/oc/common/Proxy.scala b/src/main/scala/li/cil/oc/common/Proxy.scala index c23a90f90..f8bc531b6 100644 --- a/src/main/scala/li/cil/oc/common/Proxy.scala +++ b/src/main/scala/li/cil/oc/common/Proxy.scala @@ -83,7 +83,8 @@ class Proxy { OpenComputers.log.info("Initializing mod integration.") Mods.init() - OpenComputers.log.info("Initializing Recipes.") + + OpenComputers.log.info("Initializing recipes.") Recipes.init() } diff --git a/src/main/scala/li/cil/oc/common/recipe/Recipes.scala b/src/main/scala/li/cil/oc/common/recipe/Recipes.scala index d2c1a54ac..f56152bac 100644 --- a/src/main/scala/li/cil/oc/common/recipe/Recipes.scala +++ b/src/main/scala/li/cil/oc/common/recipe/Recipes.scala @@ -2,7 +2,6 @@ package li.cil.oc.common.recipe import java.io.File import java.io.FileReader -import java.util import com.typesafe.config._ import cpw.mods.fml.common.Loader @@ -14,17 +13,16 @@ import li.cil.oc.common.init.Items import li.cil.oc.common.item.Delegator import li.cil.oc.common.item.SimpleItem import li.cil.oc.common.item.data.PrintData -import li.cil.oc.integration.Mods import li.cil.oc.integration.util.NEI import li.cil.oc.util.Color import net.minecraft.block.Block import net.minecraft.item.Item import net.minecraft.item.ItemBlock import net.minecraft.item.ItemStack -import net.minecraft.item.crafting.FurnaceRecipes import net.minecraft.nbt.NBTTagCompound import net.minecraft.util.RegistryNamespaced -import net.minecraftforge.fluids.{Fluid, FluidRegistry} +import net.minecraftforge.fluids.FluidRegistry +import net.minecraftforge.fluids.FluidStack import net.minecraftforge.oredict.OreDictionary import net.minecraftforge.oredict.RecipeSorter import net.minecraftforge.oredict.RecipeSorter.Category @@ -37,11 +35,10 @@ object Recipes { val list = mutable.LinkedHashMap.empty[ItemStack, String] val oreDictEntries = mutable.LinkedHashMap.empty[String, ItemStack] var hadErrors = false - val recipeMap = mutable.LinkedHashMap.empty[String, (ItemStack, Config) => Unit] + val recipeHandlers = mutable.LinkedHashMap.empty[String, (ItemStack, Config) => Unit] - - def registerRecipe(name: String, recipe: (ItemStack, Config) => Unit): Unit = { - recipeMap += name -> recipe + def registerRecipeHandler(name: String, recipe: (ItemStack, Config) => Unit): Unit = { + recipeHandlers += name -> recipe } def addBlock(instance: Block, name: String, oreDict: String*) = { @@ -290,34 +287,22 @@ object Recipes { list.clear() } - private def addRecipe(output: ItemStack, recipe: Config, name: String) = { - + private def addRecipe(output: ItemStack, recipe: Config, name: String) = try { val recipeType = tryGetType(recipe) - try { - recipeMap.get(recipeType) match { - case Some(x) => x(output, recipe) - case _ => OpenComputers.log.error(s"Failed adding $recipeType recipe for '$name', you will not be able to craft this item!") - hadErrors = true - - } - } - catch { - case e: RecipeException => - OpenComputers.log.error(s"Failed adding $recipeType recipe for $name, you will not be able to craft this item! The error was: ${e.getMessage}") + recipeHandlers.get(recipeType) match { + case Some(recipeHandler) => recipeHandler(output, recipe) + case _ => + OpenComputers.log.error(s"Failed adding recipe for $name, you will not be able to craft this item. The error was: Invalid recipe type '$recipeType'.") hadErrors = true } } - - def parseFluidIngredient(entry: AnyRef): Option[Fluid] = entry match { - case name: String => { - if (name == null || name.trim.isEmpty) None - else if (FluidRegistry.getFluid(name) != null) Option(FluidRegistry.getFluid(name)) - else None - } - case _ => None - + catch { + case e: RecipeException => + OpenComputers.log.error(s"Failed adding recipe for $name, you will not be able to craft this item.", e) + hadErrors = true } + def tryGetCount(recipe: Config) = if (recipe.hasPath("output")) recipe.getInt("output") else 1 def parseIngredient(entry: AnyRef) = entry match { case map: java.util.Map[AnyRef, AnyRef]@unchecked => @@ -366,6 +351,14 @@ object Recipes { case other => throw new RecipeException(s"Invalid ingredient type (not a map or string): $other") } + def parseFluidIngredient(entry: Config): Option[FluidStack] = { + val fluid = FluidRegistry.getFluid(entry.getString("name")) + val amount = + if (entry.hasPath("amount")) entry.getInt("amount") + else 1000 + Option(new FluidStack(fluid, amount)) + } + private def findItem(name: String) = getObjectWithoutFallback(Item.itemRegistry, name).orElse(Item.itemRegistry.find { case item: Item => item.getUnlocalizedName == name || item.getUnlocalizedName == "item." + name case _ => false @@ -382,8 +375,6 @@ object Recipes { private def tryGetType(recipe: Config) = if (recipe.hasPath("type")) recipe.getString("type") else "shaped" - def tryGetCount(recipe: Config) = if (recipe.hasPath("output")) recipe.getInt("output") else 1 - private def tryGetId(ingredient: java.util.Map[AnyRef, AnyRef]): Int = if (ingredient.contains("subID")) ingredient.get("subID") match { case id: Number => id.intValue diff --git a/src/main/scala/li/cil/oc/integration/Mods.scala b/src/main/scala/li/cil/oc/integration/Mods.scala index 3d094a071..4c645a182 100644 --- a/src/main/scala/li/cil/oc/integration/Mods.scala +++ b/src/main/scala/li/cil/oc/integration/Mods.scala @@ -156,8 +156,7 @@ object Mods { final val Factorization = "factorization" final val Forestry = "Forestry" final val ForgeMultipart = "ForgeMultipart" - final val DeepStorageUnit = "MineFactoryReloaded|DeepStorageUnit" - // Doesn't really exist. + final val DeepStorageUnit = "MineFactoryReloaded|DeepStorageUnit" // Doesn't really exist. final val Galacticraft = "Galacticraft API" final val GregTech = "gregtech" final val IndustrialCraft2 = "IC2" diff --git a/src/main/scala/li/cil/oc/integration/gregtech/ModGregtech.scala b/src/main/scala/li/cil/oc/integration/gregtech/ModGregtech.scala index a4400b938..1d8a9afb0 100644 --- a/src/main/scala/li/cil/oc/integration/gregtech/ModGregtech.scala +++ b/src/main/scala/li/cil/oc/integration/gregtech/ModGregtech.scala @@ -16,6 +16,6 @@ object ModGregtech extends ModProxy { Driver.add(new DriverEnergyContainer) - RecipeRegistry.init() + RecipeHandler.init() } } \ No newline at end of file diff --git a/src/main/scala/li/cil/oc/integration/gregtech/RecipeHandler.scala b/src/main/scala/li/cil/oc/integration/gregtech/RecipeHandler.scala new file mode 100644 index 000000000..42027979b --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/gregtech/RecipeHandler.scala @@ -0,0 +1,188 @@ +package li.cil.oc.integration.gregtech + +import java.util + +import com.typesafe.config.Config +import com.typesafe.config.ConfigValue +import li.cil.oc.common.recipe.Recipes +import li.cil.oc.common.recipe.Recipes.RecipeException +import net.minecraft.item.ItemStack +import net.minecraftforge.fluids.FluidStack +import net.minecraftforge.oredict.OreDictionary + +import scala.collection.convert.WrapAsScala._ + +object RecipeHandler { + def init(): Unit = { + Recipes.registerRecipeHandler("gt_alloySmelter", addGTAlloySmelterRecipe) + Recipes.registerRecipeHandler("gt_assembler", addGTAssemblingMachineRecipe) + Recipes.registerRecipeHandler("gt_bender", addGTBenderRecipe) + Recipes.registerRecipeHandler("gt_canner", addGTCannerRecipe) + Recipes.registerRecipeHandler("gt_chemical", addGTChemicalRecipe) + Recipes.registerRecipeHandler("gt_cnc", addGTCNCRecipe) + Recipes.registerRecipeHandler("gt_cutter", addGTCutterRecipe) + Recipes.registerRecipeHandler("gt_lathe", addGTLatheRecipe) + Recipes.registerRecipeHandler("gt_wiremill", addGTWireMillRecipe) + } + + def addGTAlloySmelterRecipe(output: ItemStack, recipe: Config) { + val (primaryInputs, secondaryInputs, _, _, _, eu, duration) = parseRecipe(output, recipe) + secondaryInputs match { + case Some(value) => + for (primaryInput <- primaryInputs; secondaryInput <- value) { + gregtech.api.GregTech_API.sRecipeAdder.addAlloySmelterRecipe(primaryInput, secondaryInput, output, duration, eu) + } + case _ => + for (primaryInput <- primaryInputs) { + gregtech.api.GregTech_API.sRecipeAdder.addAlloySmelterRecipe(primaryInput, null, output, duration, eu) + } + } + } + + def addGTAssemblingMachineRecipe(output: ItemStack, recipe: Config) { + val (primaryInputs, secondaryInputs, fluidInput, _, _, eu, duration) = parseRecipe(output, recipe) + secondaryInputs match { + case Some(value) => + for (primaryInput <- primaryInputs; secondaryInput <- value) { + gregtech.api.GregTech_API.sRecipeAdder.addAssemblerRecipe(primaryInput, secondaryInput, fluidInput.orNull, output, duration, eu) + } + case _ => + for (primaryInput <- primaryInputs) { + gregtech.api.GregTech_API.sRecipeAdder.addAssemblerRecipe(primaryInput, null, fluidInput.orNull, output, duration, eu) + } + } + } + + def addGTBenderRecipe(output: ItemStack, recipe: Config) { + val (primaryInputs, _, _, _, _, eu, duration) = parseRecipe(output, recipe) + for (primaryInput <- primaryInputs) { + gregtech.api.GregTech_API.sRecipeAdder.addBenderRecipe(primaryInput, output, duration, eu) + } + } + + def addGTCannerRecipe(output: ItemStack, recipe: Config) { + val (primaryInputs, secondaryInputs, _, _, secondaryOutputs, eu, duration) = parseRecipe(output, recipe) + val secondaryOutput = secondaryOutputs.headOption.orNull + secondaryInputs match { + case Some(value) => + for (primaryInput <- primaryInputs; secondaryInput <- value) { + gregtech.api.GregTech_API.sRecipeAdder.addCannerRecipe(primaryInput, secondaryInput, output, secondaryOutput, duration, eu) + } + case None => + for (primaryInput <- primaryInputs) { + gregtech.api.GregTech_API.sRecipeAdder.addCannerRecipe(primaryInput, null, output, secondaryOutput, duration, eu) + } + } + } + + def addGTChemicalRecipe(output: ItemStack, recipe: Config) { + val (primaryInputs, secondaryInputs, fluidInput, fluidOutput, _, _, duration) = parseRecipe(output, recipe) + secondaryInputs match { + case Some(value) => + for (primaryInput <- primaryInputs; secondaryOutput <- value) { + gregtech.api.GregTech_API.sRecipeAdder.addChemicalRecipe(primaryInput, secondaryOutput, fluidInput.orNull, fluidOutput.orNull, output, duration) + } + case _ => + for (primaryInput <- primaryInputs) { + gregtech.api.GregTech_API.sRecipeAdder.addChemicalRecipe(primaryInput, null, fluidInput.orNull, fluidOutput.orNull, output, duration) + } + } + } + + def addGTCNCRecipe(output: ItemStack, recipe: Config) { + val (primaryInputs, _, _, _, _, eu, duration) = parseRecipe(output, recipe) + for (primaryInput <- primaryInputs) { + gregtech.api.GregTech_API.sRecipeAdder.addCNCRecipe(primaryInput, output, duration, eu) + } + } + + def addGTCutterRecipe(output: ItemStack, recipe: Config) { + val (primaryInputs, _, fluidInput, _, secondaryOutputs, eu, duration) = parseRecipe(output, recipe) + val secondaryOutput = secondaryOutputs.headOption.orNull + fluidInput match { + case Some(fluid) => + for (primaryInput <- primaryInputs) { + gregtech.api.GregTech_API.sRecipeAdder.addCutterRecipe(primaryInput, fluid, output, secondaryOutput, duration, eu) + } + case _ => + for (primaryInput <- primaryInputs) { + gregtech.api.GregTech_API.sRecipeAdder.addCutterRecipe(primaryInput, output, secondaryOutput, duration, eu) + } + } + } + + def addGTLatheRecipe(output: ItemStack, recipe: Config) { + val (primaryInputs, _, _, _, secondaryOutputs, eu, duration) = parseRecipe(output, recipe) + val secondaryOutput = secondaryOutputs.headOption.orNull + for (primaryInput <- primaryInputs) { + gregtech.api.GregTech_API.sRecipeAdder.addLatheRecipe(primaryInput, output, secondaryOutput, duration, eu) + } + } + + def addGTWireMillRecipe(output: ItemStack, recipe: Config) { + val (primaryInputs, _, _, _, _, eu, duration) = parseRecipe(output, recipe) + for (primaryInput <- primaryInputs) { + gregtech.api.GregTech_API.sRecipeAdder.addWiremillRecipe(primaryInput, output, duration, eu) + } + } + + private def parseRecipe(output: ItemStack, recipe: Config) = { + val inputs = parseIngredientList(recipe.getValue("input")).toBuffer + output.stackSize = Recipes.tryGetCount(recipe) + + if (inputs.size < 1 || inputs.size > 2) { + throw new RecipeException(s"Invalid recipe length: ${inputs.size}, should be 1 or 2.") + } + + val inputCount = recipe.getIntList("count") + if (inputCount.size() != inputs.size) { + throw new RecipeException(s"Mismatched ingredient count: ${inputs.size} != ${inputCount.size}.") + } + + (inputs, inputCount).zipped.foreach((stacks, count) => + stacks.foreach(stack => + if (stack != null && count > 0) + stack.stackSize = stack.getMaxStackSize min count)) + + inputs.padTo(2, null) + + val outputs = + if (recipe.hasPath("secondaryOutput")) { + val secondaryOutput = parseIngredientList(recipe.getValue("secondaryOutput")).map(_.headOption) + + val outputCount = recipe.getIntList("secondaryOutputCount") + if (outputCount.size() != secondaryOutput.size) { + throw new RecipeException(s"Mismatched secondary output count: ${secondaryOutput.size} != ${outputCount.size}.") + } + + (secondaryOutput, outputCount).zipped.foreach((stack, count) => + if (count > 0) stack.foreach(s => s.stackSize = s.getMaxStackSize min count)) + secondaryOutput.collect { case Some(stack) => stack } + } + else Iterable.empty[ItemStack] + + val inputFluidStack = + if (recipe.hasPath("inputFluid")) Recipes.parseFluidIngredient(recipe.getConfig("inputFluid")) + else None + + val outputFluidStack = + if (recipe.hasPath("outputFluid")) Recipes.parseFluidIngredient(recipe.getConfig("outputFluid")) + else None + + val eu = recipe.getInt("eu") + val duration = recipe.getInt("time") + + (inputs.head, Option(inputs.last), inputFluidStack, outputFluidStack, outputs, eu, duration) + } + + private def parseIngredientList(list: ConfigValue) = + (list.unwrapped() match { + case list: util.List[AnyRef]@unchecked => list.map(Recipes.parseIngredient) + case other => Iterable(Recipes.parseIngredient(other)) + }) map { + case null => Array.empty[ItemStack] + case stack: ItemStack => Array(stack) + case name: String => Array(OreDictionary.getOres(name): _*) + case other => throw new RecipeException(s"Invalid ingredient type: $other.") + } +} diff --git a/src/main/scala/li/cil/oc/integration/gregtech/RecipeRegistry.scala b/src/main/scala/li/cil/oc/integration/gregtech/RecipeRegistry.scala deleted file mode 100644 index 35a886133..000000000 --- a/src/main/scala/li/cil/oc/integration/gregtech/RecipeRegistry.scala +++ /dev/null @@ -1,253 +0,0 @@ -package li.cil.oc.integration.gregtech - -import java.util - -import com.typesafe.config.Config -import li.cil.oc.common.recipe.Recipes -import li.cil.oc.common.recipe.Recipes.RecipeException -import net.minecraft.item.ItemStack -import net.minecraftforge.fluids.FluidStack -import net.minecraftforge.oredict.OreDictionary - -import scala.collection.convert.WrapAsScala._ - -object RecipeRegistry { - - def getGTRecipesWithEU(output: ItemStack, recipe: Config): (Array[ItemStack], Option[Array[ItemStack]], Option[FluidStack], Option[FluidStack], Seq[ItemStack], Int, Int) = { - - val inputs = (recipe.getValue("input").unwrapped() match { - case list: util.List[AnyRef]@unchecked => list.map(Recipes.parseIngredient) - case other => Seq(Recipes.parseIngredient(other)) - }) map { - case null => Array.empty[ItemStack] - case stack: ItemStack => Array(stack) - case name: String => Array(OreDictionary.getOres(name): _*) - case other => throw new RecipeException(s"Invalid ingredient type: $other.") - } - output.stackSize = Recipes.tryGetCount(recipe) - - if (inputs.size < 1 || inputs.size > 2) { - throw new RecipeException(s"Invalid recipe length: ${inputs.size}, should be 1 or 2.") - } - - val inputCount = recipe.getIntList("count") - if (inputCount.size() != inputs.size) { - throw new RecipeException(s"Ingredient and input count mismatch: ${inputs.size} != ${inputCount.size}.") - } - - var inputFluidStack: Option[FluidStack] = None: Option[FluidStack] - if (recipe.hasPath("inputLiquid")) Recipes.parseFluidIngredient(recipe.getString("inputLiquid")) match { - case Some(fluid) => - var inputFluidAmount = 1000 - if (recipe.hasPath("inputFluidAmount")) inputFluidAmount = recipe.getInt("inputFluidAmount") - inputFluidStack = Option(new FluidStack(fluid, inputFluidAmount)) - case _ => - } - - var outputFluidStack: Option[FluidStack] = None: Option[FluidStack] - if (recipe.hasPath("outputLiquid")) Recipes.parseFluidIngredient(recipe.getString("outputLiquid")) match { - case Some(fluid) => - var fluidAmount = 1000 - if (recipe.hasPath("outputFluidAmount")) fluidAmount = recipe.getInt("outputFluidAmount") - outputFluidStack = Option(new FluidStack(fluid, fluidAmount)) - case _ => - } - - val eu = recipe.getInt("eu") - val duration = recipe.getInt("time") - var additionalOutput = Seq.empty[ItemStack] - if (recipe.hasPath("additionalOutput")) { - additionalOutput = (recipe.getValue("additionalOutput").unwrapped() match { - case list: util.List[AnyRef]@unchecked => list.map(Recipes.parseIngredient) - case other => Seq(Recipes.parseIngredient(other)) - }) map { - case stack: ItemStack => stack - case name: String => val ores = OreDictionary.getOres(name) - if (ores.size() > 0) - ores.get(0) - else - null - case other => throw new RecipeException(s"Invalid ingredient type: $other.") - } - - val outputCount = recipe.getIntList("outputCount") - if (outputCount.size() != additionalOutput.size) { - throw new RecipeException(s"Outputs and output count mismatch: ${additionalOutput.size} != ${outputCount.size}.") - } - (additionalOutput, outputCount).zipped.foreach((stack, count) => if (stack != null && count > 0) stack.stackSize = stack.getMaxStackSize min count) - } - - - (inputs, inputCount).zipped.foreach((stacks, count) => stacks.foreach(stack => if (stack != null && count > 0) stack.stackSize = stack.getMaxStackSize min count)) - - - - inputs.padTo(2, null) - val input = inputs.head - (input, Option(inputs.last), inputFluidStack, outputFluidStack, additionalOutput, eu, duration) - } - - def addGTAlloySmelterRecipe(output: ItemStack, recipe: Config) { - val (inputs1, inputs2, fluidStackIn, fluidStackOut, additionalOutput, eu, duration) = getGTRecipesWithEU(output, recipe) - for (input1 <- inputs1) { - inputs2 match { - case Some(inputs2List) => - for (input2 <- inputs2List) - gregtech.api.GregTech_API.sRecipeAdder.addAlloySmelterRecipe(input1, input2, output, duration, eu) - case None => - gregtech.api.GregTech_API.sRecipeAdder.addAlloySmelterRecipe(input1, null, output, duration, eu) - } - } - } - - def addGTAssemblingMachineRecipe(output: ItemStack, recipe: Config) { - val (inputs1, inputs2, fluidStackIn, fluidStackOut, additionalOutput, eu, duration) = getGTRecipesWithEU(output, recipe) - for (input1 <- inputs1) { - inputs2 match { - case Some(inputs2List) => - for (input2 <- inputs2List) - fluidStackIn match { - case Some(fluid) => - - gregtech.api.GregTech_API.sRecipeAdder.addAssemblerRecipe(input1, input2, fluid, output, duration, eu) - case None => - gregtech.api.GregTech_API.sRecipeAdder.addAssemblerRecipe(input1, input2, output, duration, eu) - } - - case None => - fluidStackIn match { - case Some(fluid) => - gregtech.api.GregTech_API.sRecipeAdder.addAssemblerRecipe(input1, null, fluid, output, duration, eu) - case None => - gregtech.api.GregTech_API.sRecipeAdder.addAssemblerRecipe(input1, null, output, duration, eu) - } - } - } - } - - def addGTBenderRecipe(output: ItemStack, recipe: Config) { - val (inputs1, inputs2, fluidStackIn, fluidStackOut, additionalOutput, eu, duration) = getGTRecipesWithEU(output, recipe) - for (input1 <- inputs1) { - gregtech.api.GregTech_API.sRecipeAdder.addBenderRecipe(input1, output, duration, eu) - } - } - - def addGTCutterRecipe(output: ItemStack, recipe: Config) { - val (inputs1, inputs2, fluidStackIn, fluidStackOut, additionalOutput, eu, duration) = getGTRecipesWithEU(output, recipe) - var add: ItemStack = null - if (additionalOutput.size > 1) - add = additionalOutput.head - for (input1 <- inputs1) { - fluidStackIn match { - case Some(fluid) => - gregtech.api.GregTech_API.sRecipeAdder.addCutterRecipe(input1, fluid, output, add, duration, eu) - - case None => - gregtech.api.GregTech_API.sRecipeAdder.addCutterRecipe(input1, output, add, duration, eu) - } - } - } - - def addGTCannerRecipe(output: ItemStack, recipe: Config) { - val (inputs1, inputs2, fluidStackIn, fluidStackOut, additionalOutput, eu, duration) = getGTRecipesWithEU(output, recipe) - var add: ItemStack = null - if (additionalOutput.size > 1) - add = additionalOutput.head - - for (input1 <- inputs1) { - inputs2 match { - case Some(inputs2List) => - for (input2 <- inputs2List) - gregtech.api.GregTech_API.sRecipeAdder.addCannerRecipe(input1, input2, output, add, duration, eu) - case None => - gregtech.api.GregTech_API.sRecipeAdder.addCannerRecipe(input1, null, output, add, duration, eu) - - - } - } - } - - def addGTChemicalRecipe(output: ItemStack, recipe: Config) { - val (inputs1, inputs2, fluidStackIn, fluidStackOut, additionalOutput, eu, duration) = getGTRecipesWithEU(output, recipe) - for (input1 <- inputs1) { - inputs2 match { - case Some(inputs2List) => - for (input2 <- inputs2List) - fluidStackIn match { - case Some(fluid) => - fluidStackOut match { - case Some(fluidOut) => - gregtech.api.GregTech_API.sRecipeAdder.addChemicalRecipe(input1, input2, fluid, fluidOut, output, duration) - - case _ => - gregtech.api.GregTech_API.sRecipeAdder.addChemicalRecipe(input1, input2, fluid, null, output, duration) - } - case None => - fluidStackOut match { - case Some(fluidOut) => - gregtech.api.GregTech_API.sRecipeAdder.addChemicalRecipe(input1, input2, null, fluidOut, output, duration) - case _ => - gregtech.api.GregTech_API.sRecipeAdder.addChemicalRecipe(input1, input2, output, duration) - } - } - - case None => - fluidStackIn match { - case Some(fluid) => - fluidStackOut match { - case Some(fluidOut) => - gregtech.api.GregTech_API.sRecipeAdder.addChemicalRecipe(input1, null, fluid, fluidOut, output, duration) - - case _ => - gregtech.api.GregTech_API.sRecipeAdder.addChemicalRecipe(input1, null, fluid, null, output, duration) - } - case None => - fluidStackOut match { - case Some(fluidOut) => - gregtech.api.GregTech_API.sRecipeAdder.addChemicalRecipe(input1, null, null, fluidOut, output, duration) - case _ => - gregtech.api.GregTech_API.sRecipeAdder.addChemicalRecipe(input1, null, output, duration) - } - } - } - } - } - - def addGTCNCRecipe(output: ItemStack, recipe: Config) { - val (inputs1, inputs2, fluidStackIn, fluidStackOut, additionalOutput, eu, duration) = getGTRecipesWithEU(output, recipe) - for (input1 <- inputs1) { - gregtech.api.GregTech_API.sRecipeAdder.addCNCRecipe(input1, output, duration, eu) - } - } - - def addGTLatheRecipe(output: ItemStack, recipe: Config) { - val (inputs1, inputs2, fluidStackIn, fluidStackOut, additionalOutput, eu, duration) = getGTRecipesWithEU(output, recipe) - var add: ItemStack = null - if (additionalOutput.size > 1) - add = additionalOutput.head - for (input1 <- inputs1) { - gregtech.api.GregTech_API.sRecipeAdder.addLatheRecipe(input1, output, add, duration, eu) - } - } - - def addGTWireMillRecipe(output: ItemStack, recipe: Config) { - val (inputs1, inputs2, fluidStackIn, fluidStackOut, additionalOutput, eu, duration) = getGTRecipesWithEU(output, recipe) - for (input1 <- inputs1) { - gregtech.api.GregTech_API.sRecipeAdder.addWiremillRecipe(input1, output, duration, eu) - } - } - - - def init(): Unit = { - Recipes.registerRecipe("gt_alloySmelter", addGTAlloySmelterRecipe) - Recipes.registerRecipe("gt_assembler", addGTAssemblingMachineRecipe) - Recipes.registerRecipe("gt_bender", addGTBenderRecipe) - Recipes.registerRecipe("gt_canner", addGTCannerRecipe) - Recipes.registerRecipe("gt_chemical", addGTChemicalRecipe) - Recipes.registerRecipe("gt_cnc", addGTCNCRecipe) - Recipes.registerRecipe("gt_cutter", addGTCutterRecipe) - Recipes.registerRecipe("gt_lathe", addGTLatheRecipe) - Recipes.registerRecipe("gt_wiremill", addGTWireMillRecipe) - - } -} diff --git a/src/main/scala/li/cil/oc/integration/vanilla/ModVanilla.scala b/src/main/scala/li/cil/oc/integration/vanilla/ModVanilla.scala index 5aeae9039..a1916d1be 100644 --- a/src/main/scala/li/cil/oc/integration/vanilla/ModVanilla.scala +++ b/src/main/scala/li/cil/oc/integration/vanilla/ModVanilla.scala @@ -34,6 +34,7 @@ object ModVanilla extends ModProxy { Driver.add(ConverterNBT) Driver.add(ConverterWorld) Driver.add(ConverterWorldProvider) - RecipeRegistry.init() + + RecipeHandler.init() } } diff --git a/src/main/scala/li/cil/oc/integration/vanilla/RecipeRegistry.scala b/src/main/scala/li/cil/oc/integration/vanilla/RecipeHandler.scala similarity index 83% rename from src/main/scala/li/cil/oc/integration/vanilla/RecipeRegistry.scala rename to src/main/scala/li/cil/oc/integration/vanilla/RecipeHandler.scala index 007685b7b..d544b6422 100644 --- a/src/main/scala/li/cil/oc/integration/vanilla/RecipeRegistry.scala +++ b/src/main/scala/li/cil/oc/integration/vanilla/RecipeHandler.scala @@ -2,8 +2,10 @@ package li.cil.oc.integration.vanilla import com.typesafe.config.Config import cpw.mods.fml.common.registry.GameRegistry +import li.cil.oc.common.recipe.ExtendedShapedOreRecipe +import li.cil.oc.common.recipe.ExtendedShapelessOreRecipe +import li.cil.oc.common.recipe.Recipes import li.cil.oc.common.recipe.Recipes.RecipeException -import li.cil.oc.common.recipe.{Recipes, ExtendedShapelessOreRecipe, ExtendedShapedOreRecipe} import net.minecraft.item.ItemStack import net.minecraft.item.crafting.FurnaceRecipes import net.minecraftforge.oredict.OreDictionary @@ -11,7 +13,12 @@ import net.minecraftforge.oredict.OreDictionary import scala.collection.convert.WrapAsScala._ import scala.collection.mutable -object RecipeRegistry { +object RecipeHandler { + def init(): Unit = { + Recipes.registerRecipeHandler("shaped", addShapedRecipe) + Recipes.registerRecipeHandler("shapeless", addShapelessRecipe) + Recipes.registerRecipeHandler("furnace", addFurnaceRecipe) + } def addShapedRecipe(output: ItemStack, recipe: Config) { val rows = recipe.getList("input").unwrapped().map { @@ -24,12 +31,12 @@ object RecipeRegistry { var shape = mutable.ArrayBuffer.empty[String] val input = mutable.ArrayBuffer.empty[AnyRef] for (row <- rows) { - val (pattern, ingredients) = row.foldLeft((new StringBuilder, Seq.empty[AnyRef]))((acc, ingredient) => { + val (pattern, ingredients) = row.foldLeft((new StringBuilder, Iterable.empty[AnyRef]))((acc, ingredient) => { val (pattern, ingredients) = acc ingredient match { case _@(_: ItemStack | _: String) => number += 1 - (pattern.append(('a' + number).toChar), ingredients ++ Seq(Char.box(('a' + number).toChar), ingredient)) + (pattern.append(('a' + number).toChar), ingredients ++ Iterable(Char.box(('a' + number).toChar), ingredient)) case _ => (pattern.append(' '), ingredients) } }) @@ -67,10 +74,4 @@ object RecipeRegistry { case _ => } } - - def init(): Unit = { - Recipes.registerRecipe("shaped", addShapedRecipe) - Recipes.registerRecipe("shapeless", addShapelessRecipe) - Recipes.registerRecipe("furnace", addFurnaceRecipe) - } } From fa3690817054a5ce11bad147b15677eecb027a09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 22 Apr 2015 12:58:58 +0200 Subject: [PATCH 5/7] Allow using glowstone block to increase prints light level faster. Block increases light level by 4, dust by 1 as before. --- .../li/cil/oc/common/recipe/ExtendedRecipe.scala | 12 ++++++++++-- src/main/scala/li/cil/oc/common/recipe/Recipes.scala | 10 ++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/scala/li/cil/oc/common/recipe/ExtendedRecipe.scala b/src/main/scala/li/cil/oc/common/recipe/ExtendedRecipe.scala index 00b66c128..0afcd0e3c 100644 --- a/src/main/scala/li/cil/oc/common/recipe/ExtendedRecipe.scala +++ b/src/main/scala/li/cil/oc/common/recipe/ExtendedRecipe.scala @@ -126,7 +126,8 @@ object ExtendedRecipe { new ItemStack(net.minecraft.init.Blocks.diamond_block) ) - val glowstone = new ItemStack(net.minecraft.init.Items.glowstone_dust) + val glowstoneDust = new ItemStack(net.minecraft.init.Items.glowstone_dust) + val glowstone = new ItemStack(net.minecraft.init.Blocks.glowstone) for (stack <- inputs) { if (beaconBlocks.exists(_.isItemEqual(stack))) { if (data.isBeaconBase) { @@ -135,13 +136,20 @@ object ExtendedRecipe { } data.isBeaconBase = true } - if (glowstone.isItemEqual(stack)) { + if (glowstoneDust.isItemEqual(stack)) { if (data.lightLevel == 15) { // Crafting wouldn't change anything, prevent accidental resource loss. return null } data.lightLevel = math.min(15, data.lightLevel + 1) } + if (glowstone.isItemEqual(stack)) { + if (data.lightLevel == 15) { + // Crafting wouldn't change anything, prevent accidental resource loss. + return null + } + data.lightLevel = math.min(15, data.lightLevel + 4) + } } // Finally apply modified data. diff --git a/src/main/scala/li/cil/oc/common/recipe/Recipes.scala b/src/main/scala/li/cil/oc/common/recipe/Recipes.scala index f56152bac..ec5ac0ffe 100644 --- a/src/main/scala/li/cil/oc/common/recipe/Recipes.scala +++ b/src/main/scala/li/cil/oc/common/recipe/Recipes.scala @@ -280,6 +280,16 @@ object Recipes { GameRegistry.addRecipe(new ExtendedShapelessOreRecipe( lightPrint, print.createItemStack(1), new ItemStack(net.minecraft.init.Items.glowstone_dust))) + + { + val printData = new PrintData(lightPrint) + printData.lightLevel = 4 + printData.save(lightPrint) + } + + GameRegistry.addRecipe(new ExtendedShapelessOreRecipe( + lightPrint, + print.createItemStack(1), new ItemStack(net.minecraft.init.Blocks.glowstone))) } catch { case e: Throwable => OpenComputers.log.error("Error parsing recipes, you may not be able to craft any items from this mod!", e) From 20239780e194470589f46d04cf4b57e180934c64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 22 Apr 2015 15:21:43 +0200 Subject: [PATCH 6/7] Extended file system API to allow specifying a speed multiplier for file systems. For now, valid range is [1,6]. Floppies use 1, HDDs use 2-4, Raid is 6. Deprecated some internal FileSystem interface methods to allow simplifying the interface a bit when the time comes. Let's hope nobody is shipping the API \o/ --- src/main/java/li/cil/oc/api/API.java | 2 +- src/main/java/li/cil/oc/api/FileSystem.java | 107 ++++++++++++++---- .../li/cil/oc/api/detail/FileSystemAPI.java | 66 +++++++---- src/main/java/li/cil/oc/api/fs/Label.java | 2 +- .../li/cil/oc/common/tileentity/Raid.scala | 2 +- .../opencomputers/DriverFileSystem.scala | 8 +- .../cil/oc/server/component/FileSystem.scala | 71 +++++++++++- .../li/cil/oc/server/fs/FileSystem.scala | 16 ++- .../li/cil/oc/server/machine/Machine.scala | 2 +- 9 files changed, 212 insertions(+), 64 deletions(-) diff --git a/src/main/java/li/cil/oc/api/API.java b/src/main/java/li/cil/oc/api/API.java index adbec7d9c..d3c61206c 100644 --- a/src/main/java/li/cil/oc/api/API.java +++ b/src/main/java/li/cil/oc/api/API.java @@ -16,7 +16,7 @@ import li.cil.oc.api.detail.NetworkAPI; */ public class API { public static final String ID_OWNER = "OpenComputers|Core"; - public static final String VERSION = "5.1.1"; + public static final String VERSION = "5.2.0"; public static DriverAPI driver = null; public static FileSystemAPI fileSystem = null; diff --git a/src/main/java/li/cil/oc/api/FileSystem.java b/src/main/java/li/cil/oc/api/FileSystem.java index b9170805b..e126f6440 100644 --- a/src/main/java/li/cil/oc/api/FileSystem.java +++ b/src/main/java/li/cil/oc/api/FileSystem.java @@ -141,6 +141,63 @@ public final class FileSystem { * access sounds. *

* The container may be null, if no such context can be provided. + *

+ * The access sound is the name of the sound effect to play when the file + * system is accessed, for example by listing a directory or reading from + * a file. It may be null to create a silent file system. + *

+ * The speed multiplier controls how fast read and write operations on the + * file system are. It must be a value in [1,6], and controls the access + * speed, with the default being one. + * For reference, floppies are using the default, hard drives scale with + * their tiers, i.e. a tier one hard drive uses speed two, tier three uses + * speed four. + * + * @param fileSystem the file system to wrap. + * @param label the label of the file system. + * @param host the tile entity containing the file system. + * @param accessSound the name of the sound effect to play when the file + * system is accessed. This has to be the fully + * qualified resource name, e.g. + * opencomputers:floppy_access. + * @param speed the speed multiplier for this file system. + * @return the network node wrapping the file system. + */ + public static ManagedEnvironment asManagedEnvironment(final li.cil.oc.api.fs.FileSystem fileSystem, final Label label, final EnvironmentHost host, final String accessSound, int speed) { + if (API.fileSystem != null) + return API.fileSystem.asManagedEnvironment(fileSystem, label, host, accessSound, speed); + return null; + } + + /** + * Creates a network node that makes the specified file system available via + * the common file system driver. + *

+ * Creates a file system with the a read-only label and the specified + * access sound and file system speed. + * + * @param fileSystem the file system to wrap. + * @param label the label of the file system. + * @param host the tile entity containing the file system. + * @param accessSound the name of the sound effect to play when the file + * system is accessed. This has to be the fully + * qualified resource name, e.g. + * opencomputers:floppy_access. + * @param speed the speed multiplier for this file system. + * @return the network node wrapping the file system. + */ + public static ManagedEnvironment asManagedEnvironment(final li.cil.oc.api.fs.FileSystem fileSystem, final String label, final EnvironmentHost host, final String accessSound, int speed) { + if (API.fileSystem != null) + return API.fileSystem.asManagedEnvironment(fileSystem, label, host, accessSound, speed); + return null; + } + + /** + * Creates a network node that makes the specified file system available via + * the common file system driver. + *

+ * Creates a file system with the specified label and the specified access + * sound, using the default file system speed. * * @param fileSystem the file system to wrap. * @param label the label of the file system. @@ -152,14 +209,15 @@ public final class FileSystem { * @return the network node wrapping the file system. */ public static ManagedEnvironment asManagedEnvironment(final li.cil.oc.api.fs.FileSystem fileSystem, final Label label, final EnvironmentHost host, final String accessSound) { - if (API.fileSystem != null) - return API.fileSystem.asManagedEnvironment(fileSystem, label, host, accessSound); - return null; + return asManagedEnvironment(fileSystem, label, host, accessSound, 1); } /** - * Like {@link #asManagedEnvironment(li.cil.oc.api.fs.FileSystem, Label, li.cil.oc.api.driver.EnvironmentHost, String)}, - * but creates a read-only label initialized to the specified value. + * Creates a network node that makes the specified file system available via + * the common file system driver. + *

+ * Creates a file system with a read-only label and the specified access + * sound, using the default file system speed. * * @param fileSystem the file system to wrap. * @param label the read-only label of the file system. @@ -171,51 +229,52 @@ public final class FileSystem { * @return the network node wrapping the file system. */ public static ManagedEnvironment asManagedEnvironment(final li.cil.oc.api.fs.FileSystem fileSystem, final String label, final EnvironmentHost host, final String accessSound) { - if (API.fileSystem != null) - return API.fileSystem.asManagedEnvironment(fileSystem, label, host, accessSound); - return null; + return asManagedEnvironment(fileSystem, label, host, accessSound, 1); } /** - * Like {@link #asManagedEnvironment(li.cil.oc.api.fs.FileSystem, Label, li.cil.oc.api.driver.EnvironmentHost, String)}, - * but does not provide a container. + * Creates a network node that makes the specified file system available via + * the common file system driver. + *

+ * Creates a file system with the specified label, without an environment + * and access sound, using the default file system speed. * * @param fileSystem the file system to wrap. * @param label the label of the file system. * @return the network node wrapping the file system. */ public static ManagedEnvironment asManagedEnvironment(final li.cil.oc.api.fs.FileSystem fileSystem, final Label label) { - if (API.fileSystem != null) - return API.fileSystem.asManagedEnvironment(fileSystem, label); - return null; + return asManagedEnvironment(fileSystem, label, null, null, 1); } /** - * Like {@link #asManagedEnvironment(li.cil.oc.api.fs.FileSystem, Label)}, - * but creates a read-only label initialized to the specified value. + * Creates a network node that makes the specified file system available via + * the common file system driver. + *

+ * Creates a file system with a read-only label, without an environment and + * access sound, using the default file system speed. * * @param fileSystem the file system to wrap. * @param label the read-only label of the file system. * @return the network node wrapping the file system. */ public static ManagedEnvironment asManagedEnvironment(final li.cil.oc.api.fs.FileSystem fileSystem, final String label) { - if (API.fileSystem != null) - return API.fileSystem.asManagedEnvironment(fileSystem, label); - return null; + return asManagedEnvironment(fileSystem, label, null, null, 1); } /** - * Like {@link #asManagedEnvironment(li.cil.oc.api.fs.FileSystem, Label)}, - * but creates an unlabeled file system (i.e. the label can neither be read - * nor written). + * Creates a network node that makes the specified file system available via + * the common file system driver. + *

+ * Creates an unlabeled file system (i.e. the label can neither be read nor + * written), without an environment and access sound, using the default + * file system speed. * * @param fileSystem the file system to wrap. * @return the network node wrapping the file system. */ public static ManagedEnvironment asManagedEnvironment(final li.cil.oc.api.fs.FileSystem fileSystem) { - if (API.fileSystem != null) - return API.fileSystem.asManagedEnvironment(fileSystem); - return null; + return asManagedEnvironment(fileSystem, (Label) null, null, null, 1); } // ----------------------------------------------------------------------- // diff --git a/src/main/java/li/cil/oc/api/detail/FileSystemAPI.java b/src/main/java/li/cil/oc/api/detail/FileSystemAPI.java index e0a53518d..b45bd5b3e 100644 --- a/src/main/java/li/cil/oc/api/detail/FileSystemAPI.java +++ b/src/main/java/li/cil/oc/api/detail/FileSystemAPI.java @@ -97,56 +97,76 @@ public interface FileSystemAPI { * access sounds. *

* The container may be null, if no such context can be provided. + *

+ * The access sound is the name of the sound effect to play when the file + * system is accessed, for example by listing a directory or reading from + * a file. It may be null to create a silent file system. + *

+ * The speed multiplier controls how fast read and write operations on the + * file system are. It must be a value in [1,6], and controls the access + * speed, with the default being one. + * For reference, floppies are using the default, hard drives scale with + * their tiers, i.e. a tier one hard drive uses speed two, tier three uses + * speed four. * * @param fileSystem the file system to wrap. * @param label the label of the file system. * @param host the tile entity containing the file system. * @param accessSound the name of the sound effect to play when the file - * system is accessed. + * system is accessed. This has to be the fully + * qualified resource name, e.g. + * opencomputers:floppy_access. + * @param speed the speed multiplier for this file system. * @return the network node wrapping the file system. */ - ManagedEnvironment asManagedEnvironment(FileSystem fileSystem, Label label, EnvironmentHost host, String accessSound); + ManagedEnvironment asManagedEnvironment(FileSystem fileSystem, Label label, EnvironmentHost host, String accessSound, int speed); /** - * Like {@link #asManagedEnvironment(li.cil.oc.api.fs.FileSystem, Label, li.cil.oc.api.driver.EnvironmentHost, String)}, - * but creates a read-only label initialized to the specified value. + * Creates a network node that makes the specified file system available via + * the common file system driver. + *

+ * Creates a file system with the a read-only label and the specified + * access sound and file system speed. * * @param fileSystem the file system to wrap. * @param label the read-only label of the file system. * @param host the tile entity containing the file system. * @param accessSound the name of the sound effect to play when the file - * system is accessed. + * system is accessed. This has to be the fully + * qualified resource name, e.g. + * opencomputers:floppy_access. + * @param speed the speed multiplier for this file system. * @return the network node wrapping the file system. */ + ManagedEnvironment asManagedEnvironment(FileSystem fileSystem, String label, EnvironmentHost host, String accessSound, int speed); + + /** + * @deprecated Don't use this directly, use the wrapper in {@link li.cil.oc.api.FileSystem}. + */ + @Deprecated + ManagedEnvironment asManagedEnvironment(FileSystem fileSystem, Label label, EnvironmentHost host, String accessSound); + + /** + * @deprecated Don't use this directly, use the wrapper in {@link li.cil.oc.api.FileSystem}. + */ + @Deprecated ManagedEnvironment asManagedEnvironment(FileSystem fileSystem, String label, EnvironmentHost host, String accessSound); /** - * Like {@link #asManagedEnvironment(li.cil.oc.api.fs.FileSystem, Label, li.cil.oc.api.driver.EnvironmentHost, String)}, - * but does not provide a container and access sound. - * - * @param fileSystem the file system to wrap. - * @param label the label of the file system. - * @return the network node wrapping the file system. + * @deprecated Don't use this directly, use the wrapper in {@link li.cil.oc.api.FileSystem}. */ + @Deprecated ManagedEnvironment asManagedEnvironment(FileSystem fileSystem, Label label); /** - * Like {@link #asManagedEnvironment(li.cil.oc.api.fs.FileSystem, Label)}, - * but creates a read-only label initialized to the specified value. - * - * @param fileSystem the file system to wrap. - * @param label the read-only label of the file system. - * @return the network node wrapping the file system. + * @deprecated Don't use this directly, use the wrapper in {@link li.cil.oc.api.FileSystem}. */ + @Deprecated ManagedEnvironment asManagedEnvironment(FileSystem fileSystem, String label); /** - * Like {@link #asManagedEnvironment(li.cil.oc.api.fs.FileSystem, Label)}, - * but creates an unlabeled file system (i.e. the label can neither be read - * nor written). - * - * @param fileSystem the file system to wrap. - * @return the network node wrapping the file system. + * @deprecated Don't use this directly, use the wrapper in {@link li.cil.oc.api.FileSystem}. */ + @Deprecated ManagedEnvironment asManagedEnvironment(FileSystem fileSystem); } \ No newline at end of file diff --git a/src/main/java/li/cil/oc/api/fs/Label.java b/src/main/java/li/cil/oc/api/fs/Label.java index e98e45cdb..4256c80ff 100644 --- a/src/main/java/li/cil/oc/api/fs/Label.java +++ b/src/main/java/li/cil/oc/api/fs/Label.java @@ -5,7 +5,7 @@ import li.cil.oc.api.Persistable; /** * Used by file system components to get and set the file system's label. * - * @see li.cil.oc.api.FileSystem#asManagedEnvironment(FileSystem, Label) + * @see li.cil.oc.api.FileSystem#asManagedEnvironment */ public interface Label extends Persistable { /** diff --git a/src/main/scala/li/cil/oc/common/tileentity/Raid.scala b/src/main/scala/li/cil/oc/common/tileentity/Raid.scala index def714fda..590a56cea 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Raid.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Raid.scala @@ -81,7 +81,7 @@ class Raid extends traits.Environment with traits.Inventory with traits.Rotatabl filesystem.foreach(fs => if (fs.node != null) fs.node.remove()) val fs = api.FileSystem.asManagedEnvironment( api.FileSystem.fromSaveDirectory(id, wipeDisksAndComputeSpace, Settings.get.bufferChanges), - label, this, Settings.resourceDomain + ":hdd_access"). + label, this, Settings.resourceDomain + ":hdd_access", 6). asInstanceOf[FileSystem] val nbtToSetAddress = new NBTTagCompound() nbtToSetAddress.setString("address", id) diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/DriverFileSystem.scala b/src/main/scala/li/cil/oc/integration/opencomputers/DriverFileSystem.scala index 17a7304fe..824d04533 100644 --- a/src/main/scala/li/cil/oc/integration/opencomputers/DriverFileSystem.scala +++ b/src/main/scala/li/cil/oc/integration/opencomputers/DriverFileSystem.scala @@ -22,8 +22,8 @@ object DriverFileSystem extends Item { override def createEnvironment(stack: ItemStack, host: EnvironmentHost) = Delegator.subItem(stack) match { - case Some(hdd: HardDiskDrive) => createEnvironment(stack, hdd.kiloBytes * 1024, host) - case Some(disk: FloppyDisk) => createEnvironment(stack, Settings.get.floppySize * 1024, host) + case Some(hdd: HardDiskDrive) => createEnvironment(stack, hdd.kiloBytes * 1024, host, hdd.tier + 2) + case Some(disk: FloppyDisk) => createEnvironment(stack, Settings.get.floppySize * 1024, host, 1) case _ => null } @@ -40,14 +40,14 @@ object DriverFileSystem extends Item { case _ => 0 } - private def createEnvironment(stack: ItemStack, capacity: Int, host: EnvironmentHost) = { + private def createEnvironment(stack: ItemStack, capacity: Int, host: EnvironmentHost, speed: Int) = { // We have a bit of a chicken-egg problem here, because we want to use the // node's address as the folder name... so we generate the address here, // if necessary. No one will know, right? Right!? val address = addressFromTag(dataTag(stack)) val isFloppy = api.Items.get(stack) == api.Items.get(Constants.ItemName.Floppy) val fs = oc.api.FileSystem.fromSaveDirectory(address, capacity, Settings.get.bufferChanges) - val environment = oc.api.FileSystem.asManagedEnvironment(fs, new ReadWriteItemLabel(stack), host, Settings.resourceDomain + ":" + (if (isFloppy) "floppy_access" else "hdd_access")) + val environment = oc.api.FileSystem.asManagedEnvironment(fs, new ReadWriteItemLabel(stack), host, Settings.resourceDomain + ":" + (if (isFloppy) "floppy_access" else "hdd_access"), speed) if (environment != null && environment.node != null) { environment.node.asInstanceOf[oc.server.network.Node].address = address } diff --git a/src/main/scala/li/cil/oc/server/component/FileSystem.scala b/src/main/scala/li/cil/oc/server/component/FileSystem.scala index 552b7d14b..10d6e3487 100644 --- a/src/main/scala/li/cil/oc/server/component/FileSystem.scala +++ b/src/main/scala/li/cil/oc/server/component/FileSystem.scala @@ -23,7 +23,7 @@ import net.minecraftforge.common.util.Constants.NBT import scala.collection.mutable -class FileSystem(val fileSystem: IFileSystem, var label: Label, val host: Option[EnvironmentHost] = None, val sound: Option[String] = None) extends prefab.ManagedEnvironment { +class FileSystem(val fileSystem: IFileSystem, var label: Label, val host: Option[EnvironmentHost], val sound: Option[String]) extends prefab.ManagedEnvironment { override val node = Network.newNode(this, Visibility.Network). withComponent("filesystem", Visibility.Neighbors). withConnector(). @@ -151,7 +151,6 @@ class FileSystem(val fileSystem: IFileSystem, var label: Label, val host: Option result(handle) } - @Callback(direct = true, limit = 4, doc = """function(handle:number, count:number):string or nil -- Reads up to the specified amount of data from an open file descriptor with the specified handle. Returns nil when EOF is reached.""") def read(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized { val handle = args.checkInteger(0) val n = math.min(Settings.get.maxReadBuffer, math.max(0, args.checkInteger(1))) @@ -183,7 +182,6 @@ class FileSystem(val fileSystem: IFileSystem, var label: Label, val host: Option } } - @Callback(direct = true, limit = 4, doc = """function(handle:number, whence:string, offset:number):number -- Seeks in an open file descriptor with the specified handle. Returns the new pointer position.""") def seek(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized { val handle = args.checkInteger(0) val whence = args.checkString(1) @@ -202,7 +200,6 @@ class FileSystem(val fileSystem: IFileSystem, var label: Label, val host: Option } } - @Callback(doc = """function(handle:number, value:string):boolean -- Writes the specified data to an open file descriptor with the specified handle.""") def write(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized { val handle = args.checkInteger(0) val value = args.checkByteArray(1) @@ -315,3 +312,69 @@ class FileSystem(val fileSystem: IFileSystem, var label: Label, val host: Option } } } + +object FileSystem { + // I really need to come up with a way to make the call limit dynamic... + def apply(fileSystem: IFileSystem, label: Label, host: Option[EnvironmentHost], sound: Option[String], speed: Int = 1): FileSystem = speed match { + case 6 => new FileSystem(fileSystem, label, host, sound) { + @Callback(direct = true, limit = 15, doc = """function(handle:number, count:number):string or nil -- Reads up to the specified amount of data from an open file descriptor with the specified handle. Returns nil when EOF is reached.""") + override def read(context: Context, args: Arguments): Array[AnyRef] = super.read(context, args) + + @Callback(direct = true, limit = 15, doc = """function(handle:number, whence:string, offset:number):number -- Seeks in an open file descriptor with the specified handle. Returns the new pointer position.""") + override def seek(context: Context, args: Arguments): Array[AnyRef] = super.seek(context, args) + + @Callback(direct = true, limit = 6, doc = """function(handle:number, value:string):boolean -- Writes the specified data to an open file descriptor with the specified handle.""") + override def write(context: Context, args: Arguments): Array[AnyRef] = super.write(context, args) + } + case 5 => new FileSystem(fileSystem, label, host, sound) { + @Callback(direct = true, limit = 13, doc = """function(handle:number, count:number):string or nil -- Reads up to the specified amount of data from an open file descriptor with the specified handle. Returns nil when EOF is reached.""") + override def read(context: Context, args: Arguments): Array[AnyRef] = super.read(context, args) + + @Callback(direct = true, limit = 13, doc = """function(handle:number, whence:string, offset:number):number -- Seeks in an open file descriptor with the specified handle. Returns the new pointer position.""") + override def seek(context: Context, args: Arguments): Array[AnyRef] = super.seek(context, args) + + @Callback(direct = true, limit = 5, doc = """function(handle:number, value:string):boolean -- Writes the specified data to an open file descriptor with the specified handle.""") + override def write(context: Context, args: Arguments): Array[AnyRef] = super.write(context, args) + } + case 4 => new FileSystem(fileSystem, label, host, sound) { + @Callback(direct = true, limit = 10, doc = """function(handle:number, count:number):string or nil -- Reads up to the specified amount of data from an open file descriptor with the specified handle. Returns nil when EOF is reached.""") + override def read(context: Context, args: Arguments): Array[AnyRef] = super.read(context, args) + + @Callback(direct = true, limit = 10, doc = """function(handle:number, whence:string, offset:number):number -- Seeks in an open file descriptor with the specified handle. Returns the new pointer position.""") + override def seek(context: Context, args: Arguments): Array[AnyRef] = super.seek(context, args) + + @Callback(direct = true, limit = 4, doc = """function(handle:number, value:string):boolean -- Writes the specified data to an open file descriptor with the specified handle.""") + override def write(context: Context, args: Arguments): Array[AnyRef] = super.write(context, args) + } + case 3 => new FileSystem(fileSystem, label, host, sound) { + @Callback(direct = true, limit = 7, doc = """function(handle:number, count:number):string or nil -- Reads up to the specified amount of data from an open file descriptor with the specified handle. Returns nil when EOF is reached.""") + override def read(context: Context, args: Arguments): Array[AnyRef] = super.read(context, args) + + @Callback(direct = true, limit = 7, doc = """function(handle:number, whence:string, offset:number):number -- Seeks in an open file descriptor with the specified handle. Returns the new pointer position.""") + override def seek(context: Context, args: Arguments): Array[AnyRef] = super.seek(context, args) + + @Callback(direct = true, limit = 3, doc = """function(handle:number, value:string):boolean -- Writes the specified data to an open file descriptor with the specified handle.""") + override def write(context: Context, args: Arguments): Array[AnyRef] = super.write(context, args) + } + case 2 => new FileSystem(fileSystem, label, host, sound) { + @Callback(direct = true, limit = 4, doc = """function(handle:number, count:number):string or nil -- Reads up to the specified amount of data from an open file descriptor with the specified handle. Returns nil when EOF is reached.""") + override def read(context: Context, args: Arguments): Array[AnyRef] = super.read(context, args) + + @Callback(direct = true, limit = 4, doc = """function(handle:number, whence:string, offset:number):number -- Seeks in an open file descriptor with the specified handle. Returns the new pointer position.""") + override def seek(context: Context, args: Arguments): Array[AnyRef] = super.seek(context, args) + + @Callback(direct = true, limit = 2, doc = """function(handle:number, value:string):boolean -- Writes the specified data to an open file descriptor with the specified handle.""") + override def write(context: Context, args: Arguments): Array[AnyRef] = super.write(context, args) + } + case _ => new FileSystem(fileSystem, label, host, sound) { + @Callback(direct = true, limit = 1, doc = """function(handle:number, count:number):string or nil -- Reads up to the specified amount of data from an open file descriptor with the specified handle. Returns nil when EOF is reached.""") + override def read(context: Context, args: Arguments): Array[AnyRef] = super.read(context, args) + + @Callback(direct = true, limit = 1, doc = """function(handle:number, whence:string, offset:number):number -- Seeks in an open file descriptor with the specified handle. Returns the new pointer position.""") + override def seek(context: Context, args: Arguments): Array[AnyRef] = super.seek(context, args) + + @Callback(direct = true, limit = 1, doc = """function(handle:number, value:string):boolean -- Writes the specified data to an open file descriptor with the specified handle.""") + override def write(context: Context, args: Arguments): Array[AnyRef] = super.write(context, args) + } + } +} diff --git a/src/main/scala/li/cil/oc/server/fs/FileSystem.scala b/src/main/scala/li/cil/oc/server/fs/FileSystem.scala index 86422ab36..4f500240c 100644 --- a/src/main/scala/li/cil/oc/server/fs/FileSystem.scala +++ b/src/main/scala/li/cil/oc/server/fs/FileSystem.scala @@ -104,20 +104,26 @@ object FileSystem extends api.detail.FileSystemAPI { } else null + def asManagedEnvironment(fileSystem: api.fs.FileSystem, label: Label, host: EnvironmentHost, accessSound: String, speed: Int) = + Option(fileSystem).flatMap(fs => Some(component.FileSystem(fs, label, Option(host), Option(accessSound), speed))).orNull + + def asManagedEnvironment(fileSystem: api.fs.FileSystem, label: String, host: EnvironmentHost, accessSound: String, speed: Int) = + asManagedEnvironment(fileSystem, new ReadOnlyLabel(label), host, accessSound, speed) + def asManagedEnvironment(fileSystem: api.fs.FileSystem, label: Label, host: EnvironmentHost, sound: String) = - Option(fileSystem).flatMap(fs => Some(new component.FileSystem(fs, label, Option(host), Option(sound)))).orNull + asManagedEnvironment(fileSystem, label, host, sound, 1) def asManagedEnvironment(fileSystem: api.fs.FileSystem, label: String, host: EnvironmentHost, sound: String) = - asManagedEnvironment(fileSystem, new ReadOnlyLabel(label), host, sound) + asManagedEnvironment(fileSystem, new ReadOnlyLabel(label), host, sound, 1) def asManagedEnvironment(fileSystem: api.fs.FileSystem, label: Label) = - Option(fileSystem).flatMap(fs => Some(new component.FileSystem(fs, label))).orNull + asManagedEnvironment(fileSystem, label, null, null, 1) def asManagedEnvironment(fileSystem: api.fs.FileSystem, label: String) = - asManagedEnvironment(fileSystem, new ReadOnlyLabel(label)) + asManagedEnvironment(fileSystem, new ReadOnlyLabel(label), null, null, 1) def asManagedEnvironment(fileSystem: api.fs.FileSystem) = - asManagedEnvironment(fileSystem, null: Label) + asManagedEnvironment(fileSystem, null: Label, null, null, 1) abstract class ItemLabel(val stack: ItemStack) extends Label diff --git a/src/main/scala/li/cil/oc/server/machine/Machine.scala b/src/main/scala/li/cil/oc/server/machine/Machine.scala index 92033ef97..bb63cddf8 100644 --- a/src/main/scala/li/cil/oc/server/machine/Machine.scala +++ b/src/main/scala/li/cil/oc/server/machine/Machine.scala @@ -53,7 +53,7 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach val tmp = if (Settings.get.tmpSize > 0) { Option(FileSystem.asManagedEnvironment(FileSystem. - fromMemory(Settings.get.tmpSize * 1024), "tmpfs")) + fromMemory(Settings.get.tmpSize * 1024), "tmpfs", null, null, 5)) } else None var architecture: Architecture = _ From 9ac38ad1b2cea70a65e6d3dd596654eb9fc4c2f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 22 Apr 2015 17:47:34 +0200 Subject: [PATCH 7/7] Changed the way upgrades on robots are rendered, now using an interface on items instead of item renderer. Closes #1038. More flexible and should also work in MC1.8... --- src/main/java/li/cil/oc/api/API.java | 2 +- .../li/cil/oc/api/component/Keyboard.java | 4 +- .../li/cil/oc/api/component/TextBuffer.java | 2 +- .../oc/api/driver/item/UpgradeRenderer.java | 43 +++++++ .../client/renderer/item/ItemRenderer.scala | 109 +----------------- .../renderer/item/UpgradeRenderer.scala | 109 ++++++++++++++++++ .../renderer/tileentity/RobotRenderer.scala | 37 +++--- .../li/cil/oc/common/item/Delegator.scala | 11 +- 8 files changed, 185 insertions(+), 132 deletions(-) create mode 100644 src/main/java/li/cil/oc/api/driver/item/UpgradeRenderer.java create mode 100644 src/main/scala/li/cil/oc/client/renderer/item/UpgradeRenderer.scala diff --git a/src/main/java/li/cil/oc/api/API.java b/src/main/java/li/cil/oc/api/API.java index d3c61206c..c0981dc2b 100644 --- a/src/main/java/li/cil/oc/api/API.java +++ b/src/main/java/li/cil/oc/api/API.java @@ -16,7 +16,7 @@ import li.cil.oc.api.detail.NetworkAPI; */ public class API { public static final String ID_OWNER = "OpenComputers|Core"; - public static final String VERSION = "5.2.0"; + public static final String VERSION = "5.2.1"; public static DriverAPI driver = null; public static FileSystemAPI fileSystem = null; diff --git a/src/main/java/li/cil/oc/api/component/Keyboard.java b/src/main/java/li/cil/oc/api/component/Keyboard.java index 1bcbe6bab..a0407be92 100644 --- a/src/main/java/li/cil/oc/api/component/Keyboard.java +++ b/src/main/java/li/cil/oc/api/component/Keyboard.java @@ -30,11 +30,11 @@ public interface Keyboard extends Environment, Persistable { void setUsableOverride(UsabilityChecker callback); /** - * Contract interface that has to implemented for usability check overides. + * Contract interface that has to implemented for usability check overrides. * * @see #setUsableOverride(li.cil.oc.api.component.Keyboard.UsabilityChecker) */ - public static interface UsabilityChecker { + interface UsabilityChecker { /** * Whether the specified keyboard is usable by the specified player. * diff --git a/src/main/java/li/cil/oc/api/component/TextBuffer.java b/src/main/java/li/cil/oc/api/component/TextBuffer.java index 0903a7961..3104c90ae 100644 --- a/src/main/java/li/cil/oc/api/component/TextBuffer.java +++ b/src/main/java/li/cil/oc/api/component/TextBuffer.java @@ -563,7 +563,7 @@ public interface TextBuffer extends ManagedEnvironment, Persistable { /** * Used when setting a buffer's maximum color depth. */ - public static enum ColorDepth { + enum ColorDepth { /** * Monochrome color, black and white. */ diff --git a/src/main/java/li/cil/oc/api/driver/item/UpgradeRenderer.java b/src/main/java/li/cil/oc/api/driver/item/UpgradeRenderer.java new file mode 100644 index 000000000..ac93d0eb5 --- /dev/null +++ b/src/main/java/li/cil/oc/api/driver/item/UpgradeRenderer.java @@ -0,0 +1,43 @@ +package li.cil.oc.api.driver.item; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import li.cil.oc.api.event.RobotRenderEvent; +import li.cil.oc.api.internal.Robot; +import net.minecraft.item.ItemStack; + +/** + * This interface can be implemented by items to allow custom rendering of + * upgrades installed in robots. + *

+ * Upgrades installed in a robot can have an external representation. This is + * achieved by implementing this interface on an item that serves as a + * renderable upgrade. When the robot is rendered, each equipped upgrade is + * checked for this interface, and if present, the {@link #render} method + * is called. + */ +public interface UpgradeRenderer { + /** + * Render the specified upgrade on a robot. + *

+ * The GL state has not been adjusted to the mount points position, so + * that you can perform rotations without having to revert the translation. + * It is your responsibility to position the rendered model to fit the + * specified mount point. The state will be such that the origin is the + * center of the robot. This is what the offset of the mount-point is + * relative to. + *

+ * If the stack cannot be rendered, simply do nothing. This way it's fine + * to implement this on a meta item. + *

+ * You usually won't need the robot parameter, but in case you do + * need some contextual information, this should provide you with anything + * you could need. + * + * @param stack the item stack of the upgrade to render. + * @param mountPoint the mount-point to render the upgrade at. + * @param robot the robot the upgrade is rendered on. + */ + @SideOnly(Side.CLIENT) + void render(ItemStack stack, RobotRenderEvent.MountPoint mountPoint, Robot robot); +} diff --git a/src/main/scala/li/cil/oc/client/renderer/item/ItemRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/item/ItemRenderer.scala index d20c17123..a70b86c93 100644 --- a/src/main/scala/li/cil/oc/client/renderer/item/ItemRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/item/ItemRenderer.scala @@ -5,11 +5,9 @@ import li.cil.oc.Settings import li.cil.oc.api import li.cil.oc.api.detail.ItemInfo import li.cil.oc.client.KeyBindings -import li.cil.oc.client.Textures import li.cil.oc.client.renderer.block.Print import li.cil.oc.client.renderer.entity.DroneRenderer import li.cil.oc.common.item.data.PrintData -import li.cil.oc.integration.opencomputers.Item import li.cil.oc.util.Color import li.cil.oc.util.ExtendedAABB import li.cil.oc.util.RenderState @@ -19,7 +17,6 @@ import net.minecraft.client.renderer.entity.RenderItem import net.minecraft.client.renderer.entity.RenderManager import net.minecraft.client.renderer.texture.TextureMap import net.minecraft.item.ItemStack -import net.minecraft.util.AxisAlignedBB import net.minecraft.util.EnumChatFormatting import net.minecraftforge.client.IItemRenderer import net.minecraftforge.client.IItemRenderer.ItemRenderType @@ -32,9 +29,6 @@ object ItemRenderer extends IItemRenderer { val renderItem = new RenderItem() renderItem.setRenderManager(RenderManager.instance) - lazy val craftingUpgrade = api.Items.get(Constants.ItemName.CraftingUpgrade) - lazy val generatorUpgrade = api.Items.get(Constants.ItemName.GeneratorUpgrade) - lazy val inventoryUpgrade = api.Items.get(Constants.ItemName.InventoryUpgrade) lazy val drone = api.Items.get(Constants.ItemName.Drone) lazy val floppy = api.Items.get(Constants.ItemName.Floppy) @@ -43,21 +37,11 @@ object ItemRenderer extends IItemRenderer { lazy val nullShape = new PrintData.Shape(ExtendedAABB.unitBounds, Settings.resourceDomain + ":White", Some(Color.Lime)) - def bounds = AxisAlignedBB.getBoundingBox(-0.1, -0.1, -0.1, 0.1, 0.1, 0.1) - - def isUpgrade(descriptor: ItemInfo) = - descriptor == craftingUpgrade || - descriptor == generatorUpgrade || - descriptor == inventoryUpgrade - - def isFloppy(descriptor: ItemInfo) = - descriptor == floppy || - descriptor == lootDisk + def isFloppy(descriptor: ItemInfo) = descriptor == floppy || descriptor == lootDisk override def handleRenderType(stack: ItemStack, renderType: ItemRenderType) = { val descriptor = api.Items.get(stack) - (renderType == ItemRenderType.EQUIPPED && isUpgrade(api.Items.get(stack))) || - (renderType == ItemRenderType.INVENTORY && isFloppy(api.Items.get(stack))) || + (renderType == ItemRenderType.INVENTORY && isFloppy(api.Items.get(stack))) || ((renderType == ItemRenderType.INVENTORY || renderType == ItemRenderType.ENTITY || renderType == ItemRenderType.EQUIPPED || renderType == ItemRenderType.EQUIPPED_FIRST_PERSON) && descriptor == drone) || ((renderType == ItemRenderType.INVENTORY || renderType == ItemRenderType.ENTITY || renderType == ItemRenderType.EQUIPPED || renderType == ItemRenderType.EQUIPPED_FIRST_PERSON) && api.Items.get(stack) == print) } @@ -75,34 +59,8 @@ object ItemRenderer extends IItemRenderer { val mc = Minecraft.getMinecraft val tm = mc.getTextureManager val descriptor = api.Items.get(stack) - if (isUpgrade(descriptor)) { - // Revert offset introduced by the render "helper". - GL11.glTranslatef(0.5f, 0.5f, 0.5f) - - if (descriptor == api.Items.get(Constants.ItemName.CraftingUpgrade)) { - tm.bindTexture(Textures.upgradeCrafting) - drawSimpleBlock() - - RenderState.checkError(getClass.getName + ".renderItem: crafting upgrade") - } - - else if (descriptor == api.Items.get(Constants.ItemName.GeneratorUpgrade)) { - tm.bindTexture(Textures.upgradeGenerator) - drawSimpleBlock(if (Item.dataTag(stack).getInteger("remainingTicks") > 0) 0.5f else 0) - - RenderState.checkError(getClass.getName + ".renderItem: generator upgrade") - } - - else if (descriptor == api.Items.get(Constants.ItemName.InventoryUpgrade)) { - tm.bindTexture(Textures.upgradeInventory) - drawSimpleBlock() - - RenderState.checkError(getClass.getName + ".renderItem: inventory upgrade") - } - } - - else if (isFloppy(descriptor)) { + if (isFloppy(descriptor)) { GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) renderItem.renderItemIntoGUI(null, tm, stack, 0, 0) val res = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight) @@ -188,67 +146,6 @@ object ItemRenderer extends IItemRenderer { RenderState.checkError("ItemRenderer.renderItem: leaving") } - private def drawSimpleBlock(frontOffset: Float = 0) { - GL11.glBegin(GL11.GL_QUADS) - - // Front. - GL11.glNormal3f(0, 0, 1) - GL11.glTexCoord2f(frontOffset, 0.5f) - GL11.glVertex3d(bounds.minX, bounds.minY, bounds.maxZ) - GL11.glTexCoord2f(frontOffset + 0.5f, 0.5f) - GL11.glVertex3d(bounds.maxX, bounds.minY, bounds.maxZ) - GL11.glTexCoord2f(frontOffset + 0.5f, 0) - GL11.glVertex3d(bounds.maxX, bounds.maxY, bounds.maxZ) - GL11.glTexCoord2f(frontOffset, 0) - GL11.glVertex3d(bounds.minX, bounds.maxY, bounds.maxZ) - - // Top. - GL11.glNormal3f(0, 1, 0) - GL11.glTexCoord2f(1, 0.5f) - GL11.glVertex3d(bounds.maxX, bounds.maxY, bounds.maxZ) - GL11.glTexCoord2f(1, 1) - GL11.glVertex3d(bounds.maxX, bounds.maxY, bounds.minZ) - GL11.glTexCoord2f(0.5f, 1) - GL11.glVertex3d(bounds.minX, bounds.maxY, bounds.minZ) - GL11.glTexCoord2f(0.5f, 0.5f) - GL11.glVertex3d(bounds.minX, bounds.maxY, bounds.maxZ) - - // Bottom. - GL11.glNormal3f(0, -1, 0) - GL11.glTexCoord2f(0.5f, 0.5f) - GL11.glVertex3d(bounds.minX, bounds.minY, bounds.maxZ) - GL11.glTexCoord2f(0.5f, 1) - GL11.glVertex3d(bounds.minX, bounds.minY, bounds.minZ) - GL11.glTexCoord2f(1, 1) - GL11.glVertex3d(bounds.maxX, bounds.minY, bounds.minZ) - GL11.glTexCoord2f(1, 0.5f) - GL11.glVertex3d(bounds.maxX, bounds.minY, bounds.maxZ) - - // Left. - GL11.glNormal3f(1, 0, 0) - GL11.glTexCoord2f(0, 0.5f) - GL11.glVertex3d(bounds.maxX, bounds.maxY, bounds.maxZ) - GL11.glTexCoord2f(0, 1) - GL11.glVertex3d(bounds.maxX, bounds.minY, bounds.maxZ) - GL11.glTexCoord2f(0.5f, 1) - GL11.glVertex3d(bounds.maxX, bounds.minY, bounds.minZ) - GL11.glTexCoord2f(0.5f, 0.5f) - GL11.glVertex3d(bounds.maxX, bounds.maxY, bounds.minZ) - - // Right. - GL11.glNormal3f(-1, 0, 0) - GL11.glTexCoord2f(0, 1) - GL11.glVertex3d(bounds.minX, bounds.minY, bounds.maxZ) - GL11.glTexCoord2f(0, 0.5f) - GL11.glVertex3d(bounds.minX, bounds.maxY, bounds.maxZ) - GL11.glTexCoord2f(0.5f, 0.5f) - GL11.glVertex3d(bounds.minX, bounds.maxY, bounds.minZ) - GL11.glTexCoord2f(0.5f, 1) - GL11.glVertex3d(bounds.minX, bounds.minY, bounds.minZ) - - GL11.glEnd() - } - private def drawShape(shape: PrintData.Shape) { val bounds = shape.bounds val texture = Print.resolveTexture(shape.texture) diff --git a/src/main/scala/li/cil/oc/client/renderer/item/UpgradeRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/item/UpgradeRenderer.scala new file mode 100644 index 000000000..b3794915e --- /dev/null +++ b/src/main/scala/li/cil/oc/client/renderer/item/UpgradeRenderer.scala @@ -0,0 +1,109 @@ +package li.cil.oc.client.renderer.item + +import li.cil.oc.Constants +import li.cil.oc.api +import li.cil.oc.api.event.RobotRenderEvent.MountPoint +import li.cil.oc.client.Textures +import li.cil.oc.integration.opencomputers.Item +import li.cil.oc.util.RenderState +import net.minecraft.client.Minecraft +import net.minecraft.item.ItemStack +import net.minecraft.util.AxisAlignedBB +import org.lwjgl.opengl.GL11 + +object UpgradeRenderer { + lazy val craftingUpgrade = api.Items.get(Constants.ItemName.CraftingUpgrade) + lazy val generatorUpgrade = api.Items.get(Constants.ItemName.GeneratorUpgrade) + lazy val inventoryUpgrade = api.Items.get(Constants.ItemName.InventoryUpgrade) + + def render(stack: ItemStack, mountPoint: MountPoint): Unit = { + val descriptor = api.Items.get(stack) + + if (descriptor == api.Items.get(Constants.ItemName.CraftingUpgrade)) { + Minecraft.getMinecraft.getTextureManager.bindTexture(Textures.upgradeCrafting) + drawSimpleBlock(mountPoint) + + RenderState.checkError(getClass.getName + ".renderItem: crafting upgrade") + } + + else if (descriptor == api.Items.get(Constants.ItemName.GeneratorUpgrade)) { + Minecraft.getMinecraft.getTextureManager.bindTexture(Textures.upgradeGenerator) + drawSimpleBlock(mountPoint, if (Item.dataTag(stack).getInteger("remainingTicks") > 0) 0.5f else 0) + + RenderState.checkError(getClass.getName + ".renderItem: generator upgrade") + } + + else if (descriptor == api.Items.get(Constants.ItemName.InventoryUpgrade)) { + Minecraft.getMinecraft.getTextureManager.bindTexture(Textures.upgradeInventory) + drawSimpleBlock(mountPoint) + + RenderState.checkError(getClass.getName + ".renderItem: inventory upgrade") + } + } + + private val bounds = AxisAlignedBB.getBoundingBox(-0.1, -0.1, -0.1, 0.1, 0.1, 0.1) + + private def drawSimpleBlock(mountPoint: MountPoint, frontOffset: Float = 0) { + GL11.glRotatef(mountPoint.rotation.getW, mountPoint.rotation.getX, mountPoint.rotation.getY, mountPoint.rotation.getZ) + GL11.glTranslatef(mountPoint.offset.getX, mountPoint.offset.getY, mountPoint.offset.getZ) + + GL11.glBegin(GL11.GL_QUADS) + + // Front. + GL11.glNormal3f(0, 0, 1) + GL11.glTexCoord2f(frontOffset, 0.5f) + GL11.glVertex3d(bounds.minX, bounds.minY, bounds.maxZ) + GL11.glTexCoord2f(frontOffset + 0.5f, 0.5f) + GL11.glVertex3d(bounds.maxX, bounds.minY, bounds.maxZ) + GL11.glTexCoord2f(frontOffset + 0.5f, 0) + GL11.glVertex3d(bounds.maxX, bounds.maxY, bounds.maxZ) + GL11.glTexCoord2f(frontOffset, 0) + GL11.glVertex3d(bounds.minX, bounds.maxY, bounds.maxZ) + + // Top. + GL11.glNormal3f(0, 1, 0) + GL11.glTexCoord2f(1, 0.5f) + GL11.glVertex3d(bounds.maxX, bounds.maxY, bounds.maxZ) + GL11.glTexCoord2f(1, 1) + GL11.glVertex3d(bounds.maxX, bounds.maxY, bounds.minZ) + GL11.glTexCoord2f(0.5f, 1) + GL11.glVertex3d(bounds.minX, bounds.maxY, bounds.minZ) + GL11.glTexCoord2f(0.5f, 0.5f) + GL11.glVertex3d(bounds.minX, bounds.maxY, bounds.maxZ) + + // Bottom. + GL11.glNormal3f(0, -1, 0) + GL11.glTexCoord2f(0.5f, 0.5f) + GL11.glVertex3d(bounds.minX, bounds.minY, bounds.maxZ) + GL11.glTexCoord2f(0.5f, 1) + GL11.glVertex3d(bounds.minX, bounds.minY, bounds.minZ) + GL11.glTexCoord2f(1, 1) + GL11.glVertex3d(bounds.maxX, bounds.minY, bounds.minZ) + GL11.glTexCoord2f(1, 0.5f) + GL11.glVertex3d(bounds.maxX, bounds.minY, bounds.maxZ) + + // Left. + GL11.glNormal3f(1, 0, 0) + GL11.glTexCoord2f(0, 0.5f) + GL11.glVertex3d(bounds.maxX, bounds.maxY, bounds.maxZ) + GL11.glTexCoord2f(0, 1) + GL11.glVertex3d(bounds.maxX, bounds.minY, bounds.maxZ) + GL11.glTexCoord2f(0.5f, 1) + GL11.glVertex3d(bounds.maxX, bounds.minY, bounds.minZ) + GL11.glTexCoord2f(0.5f, 0.5f) + GL11.glVertex3d(bounds.maxX, bounds.maxY, bounds.minZ) + + // Right. + GL11.glNormal3f(-1, 0, 0) + GL11.glTexCoord2f(0, 1) + GL11.glVertex3d(bounds.minX, bounds.minY, bounds.maxZ) + GL11.glTexCoord2f(0, 0.5f) + GL11.glVertex3d(bounds.minX, bounds.maxY, bounds.maxZ) + GL11.glTexCoord2f(0.5f, 0.5f) + GL11.glVertex3d(bounds.minX, bounds.maxY, bounds.minZ) + GL11.glTexCoord2f(0.5f, 1) + GL11.glVertex3d(bounds.minX, bounds.minY, bounds.minZ) + + GL11.glEnd() + } +} diff --git a/src/main/scala/li/cil/oc/client/renderer/tileentity/RobotRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/tileentity/RobotRenderer.scala index 922495a4f..ca0c0832b 100644 --- a/src/main/scala/li/cil/oc/client/renderer/tileentity/RobotRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/tileentity/RobotRenderer.scala @@ -3,6 +3,7 @@ package li.cil.oc.client.renderer.tileentity import com.google.common.base.Strings import li.cil.oc.OpenComputers import li.cil.oc.Settings +import li.cil.oc.api.driver.item.UpgradeRenderer import li.cil.oc.api.event.RobotRenderEvent import li.cil.oc.client.Textures import li.cil.oc.common.EventHandler @@ -21,7 +22,6 @@ import net.minecraft.item.ItemBlock import net.minecraft.tileentity.TileEntity import net.minecraft.util.EnumChatFormatting import net.minecraft.util.Vec3 -import net.minecraftforge.client.IItemRenderer.ItemRenderType import net.minecraftforge.client.IItemRenderer.ItemRenderType._ import net.minecraftforge.client.IItemRenderer.ItemRendererHelper._ import net.minecraftforge.client.MinecraftForgeClient @@ -121,7 +121,7 @@ object RobotRenderer extends TileEntitySpecialRenderer { // Back. mountPoints(0).offset.setX(0) - mountPoints(0).offset.setY(-0.2f) + mountPoints(0).offset.setY(-0.2f - offset) mountPoints(0).offset.setZ(0.24f) mountPoints(0).rotation.setX(0) mountPoints(0).rotation.setY(1) @@ -129,7 +129,7 @@ object RobotRenderer extends TileEntitySpecialRenderer { mountPoints(0).rotation.setW(180) mountPoints(1).offset.setX(0) - mountPoints(1).offset.setY(0.2f + offset) + mountPoints(1).offset.setY(0.2f) mountPoints(1).offset.setZ(0.24f) mountPoints(1).rotation.setX(0) mountPoints(1).rotation.setY(1) @@ -138,7 +138,7 @@ object RobotRenderer extends TileEntitySpecialRenderer { // Front. mountPoints(2).offset.setX(0) - mountPoints(2).offset.setY(-0.2f) + mountPoints(2).offset.setY(-0.2f - offset) mountPoints(2).offset.setZ(0.24f) mountPoints(2).rotation.setX(0) mountPoints(2).rotation.setY(1) @@ -147,7 +147,7 @@ object RobotRenderer extends TileEntitySpecialRenderer { // Left. mountPoints(3).offset.setX(0) - mountPoints(3).offset.setY(-0.2f) + mountPoints(3).offset.setY(-0.2f - offset) mountPoints(3).offset.setZ(0.24f) mountPoints(3).rotation.setX(0) mountPoints(3).rotation.setY(1) @@ -155,7 +155,7 @@ object RobotRenderer extends TileEntitySpecialRenderer { mountPoints(3).rotation.setW(90) mountPoints(4).offset.setX(0) - mountPoints(4).offset.setY(0.2f + offset) + mountPoints(4).offset.setY(0.2f) mountPoints(4).offset.setZ(0.24f) mountPoints(4).rotation.setX(0) mountPoints(4).rotation.setY(1) @@ -164,7 +164,7 @@ object RobotRenderer extends TileEntitySpecialRenderer { // Right. mountPoints(5).offset.setX(0) - mountPoints(5).offset.setY(-0.2f) + mountPoints(5).offset.setY(-0.2f - offset) mountPoints(5).offset.setZ(0.24f) mountPoints(5).rotation.setX(0) mountPoints(5).rotation.setY(1) @@ -172,7 +172,7 @@ object RobotRenderer extends TileEntitySpecialRenderer { mountPoints(5).rotation.setW(-90) mountPoints(6).offset.setX(0) - mountPoints(6).offset.setY(0.2f + offset) + mountPoints(6).offset.setY(0.2f) mountPoints(6).offset.setZ(0.24f) mountPoints(6).rotation.setX(0) mountPoints(6).rotation.setY(1) @@ -401,22 +401,17 @@ object RobotRenderer extends TileEntitySpecialRenderer { case _ => } - val stacks = (robot.componentSlots ++ robot.containerSlots).map(robot.getStackInSlot).filter(stack => stack != null && MinecraftForgeClient.getItemRenderer(stack, ItemRenderType.EQUIPPED) != null).padTo(mountPoints.length, null).take(mountPoints.length) - for ((stack, mountPoint) <- stacks.zip(mountPoints)) { - try { - if (stack != null && (stack.getItem.requiresMultipleRenderPasses() || MinecraftForgeClient.getRenderPass == 0)) { - val tint = stack.getItem.getColorFromItemStack(stack, MinecraftForgeClient.getRenderPass) - val r = ((tint >> 16) & 0xFF) / 255f - val g = ((tint >> 8) & 0xFF) / 255f - val b = ((tint >> 0) & 0xFF) / 255f - GL11.glColor4f(r, g, b, 1) + if (MinecraftForgeClient.getRenderPass == 0) { + val stacks = (robot.componentSlots ++ robot.containerSlots).map(robot.getStackInSlot). + filter(stack => stack != null && stack.getItem.isInstanceOf[UpgradeRenderer]). + take(mountPoints.length) + for ((stack, mountPoint) <- stacks.zip(mountPoints.take(stacks.length))) try stack.getItem match { + case renderer: UpgradeRenderer => GL11.glPushMatrix() GL11.glTranslatef(0.5f, 0.5f, 0.5f) - GL11.glRotatef(mountPoint.rotation.getW, mountPoint.rotation.getX, mountPoint.rotation.getY, mountPoint.rotation.getZ) - GL11.glTranslatef(mountPoint.offset.getX, mountPoint.offset.getY, mountPoint.offset.getZ) - RenderManager.instance.itemRenderer.renderItem(Minecraft.getMinecraft.thePlayer, stack, MinecraftForgeClient.getRenderPass) + renderer.render(stack, mountPoint, robot) GL11.glPopMatrix() - } + case _ => } catch { case e: Throwable => diff --git a/src/main/scala/li/cil/oc/common/item/Delegator.scala b/src/main/scala/li/cil/oc/common/item/Delegator.scala index 39b699dcb..d73782134 100644 --- a/src/main/scala/li/cil/oc/common/item/Delegator.scala +++ b/src/main/scala/li/cil/oc/common/item/Delegator.scala @@ -8,6 +8,10 @@ import cpw.mods.fml.relauncher.SideOnly import li.cil.oc.CreativeTab import li.cil.oc.OpenComputers import li.cil.oc.Settings +import li.cil.oc.api.driver +import li.cil.oc.api.event.RobotRenderEvent.MountPoint +import li.cil.oc.api.internal.Robot +import li.cil.oc.client.renderer.item.UpgradeRenderer import li.cil.oc.common.tileentity import li.cil.oc.util.BlockPosition import net.minecraft.client.renderer.texture.IIconRegister @@ -34,7 +38,7 @@ object Delegator { else None } -class Delegator extends Item { +class Delegator extends Item with driver.item.UpgradeRenderer { setHasSubtypes(true) setCreativeTab(CreativeTab) setUnlocalizedName("oc.multi") @@ -247,4 +251,9 @@ class Delegator extends Item { } override def toString = getUnlocalizedName + + // ----------------------------------------------------------------------- // + + @SideOnly(Side.CLIENT) + def render(stack: ItemStack, mountPoint: MountPoint, robot: Robot): Unit = UpgradeRenderer.render(stack, mountPoint) }