Merge branch 'master-MC1.7.10' of github.com:MightyPirates/OpenComputers into master-MC1.8

Conflicts:
	src/main/scala/li/cil/oc/client/renderer/item/ItemRenderer.scala
	src/main/scala/li/cil/oc/client/renderer/tileentity/RobotRenderer.scala
	src/main/scala/li/cil/oc/common/item/Delegator.scala
	src/main/scala/li/cil/oc/common/recipe/Recipes.scala
	src/main/scala/li/cil/oc/integration/opencomputers/DriverFileSystem.scala
	src/main/scala/li/cil/oc/server/fs/FileSystem.scala
This commit is contained in:
Florian Nücke 2015-04-22 18:06:37 +02:00
commit 7a0a7e9b3e
23 changed files with 736 additions and 215 deletions

View File

@ -16,7 +16,7 @@ import li.cil.oc.api.detail.NetworkAPI;
*/ */
public class API { public class API {
public static final String ID_OWNER = "OpenComputers|Core"; public static final String ID_OWNER = "OpenComputers|Core";
public static final String VERSION = "5.1.1"; public static final String VERSION = "5.2.1";
public static DriverAPI driver = null; public static DriverAPI driver = null;
public static FileSystemAPI fileSystem = null; public static FileSystemAPI fileSystem = null;

View File

@ -123,6 +123,63 @@ public final class FileSystem {
* access sounds. * access sounds.
* <p/> * <p/>
* The container may be <tt>null</tt>, if no such context can be provided. * The container may be <tt>null</tt>, if no such context can be provided.
* <p/>
* 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 <tt>null</tt> to create a silent file system.
* <p/>
* 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.
* <tt>opencomputers:floppy_access</tt>.
* @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.
* <p/>
* 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.
* <tt>opencomputers:floppy_access</tt>.
* @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.
* <p/>
* 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 fileSystem the file system to wrap.
* @param label the label of the file system. * @param label the label of the file system.
@ -134,14 +191,15 @@ public final class FileSystem {
* @return the network node wrapping 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, final EnvironmentHost host, final String accessSound) { 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 asManagedEnvironment(fileSystem, label, host, accessSound, 1);
return API.fileSystem.asManagedEnvironment(fileSystem, label, host, accessSound);
return null;
} }
/** /**
* Like {@link #asManagedEnvironment(li.cil.oc.api.fs.FileSystem, Label, li.cil.oc.api.driver.EnvironmentHost, String)}, * Creates a network node that makes the specified file system available via
* but creates a read-only label initialized to the specified value. * the common file system driver.
* <p/>
* 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 fileSystem the file system to wrap.
* @param label the read-only label of the file system. * @param label the read-only label of the file system.
@ -153,51 +211,52 @@ public final class FileSystem {
* @return the network node wrapping 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, final EnvironmentHost host, final String accessSound) { 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 asManagedEnvironment(fileSystem, label, host, accessSound, 1);
return API.fileSystem.asManagedEnvironment(fileSystem, label, host, accessSound);
return null;
} }
/** /**
* Like {@link #asManagedEnvironment(li.cil.oc.api.fs.FileSystem, Label, li.cil.oc.api.driver.EnvironmentHost, String)}, * Creates a network node that makes the specified file system available via
* but does not provide a container. * the common file system driver.
* <p/>
* 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 fileSystem the file system to wrap.
* @param label the label of the file system. * @param label the label of the file system.
* @return the network node wrapping 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) { public static ManagedEnvironment asManagedEnvironment(final li.cil.oc.api.fs.FileSystem fileSystem, final Label label) {
if (API.fileSystem != null) return asManagedEnvironment(fileSystem, label, null, null, 1);
return API.fileSystem.asManagedEnvironment(fileSystem, label);
return null;
} }
/** /**
* Like {@link #asManagedEnvironment(li.cil.oc.api.fs.FileSystem, Label)}, * Creates a network node that makes the specified file system available via
* but creates a read-only label initialized to the specified value. * the common file system driver.
* <p/>
* 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 fileSystem the file system to wrap.
* @param label the read-only label of the file system. * @param label the read-only label of the file system.
* @return the network node wrapping 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) { public static ManagedEnvironment asManagedEnvironment(final li.cil.oc.api.fs.FileSystem fileSystem, final String label) {
if (API.fileSystem != null) return asManagedEnvironment(fileSystem, label, null, null, 1);
return API.fileSystem.asManagedEnvironment(fileSystem, label);
return null;
} }
/** /**
* Like {@link #asManagedEnvironment(li.cil.oc.api.fs.FileSystem, Label)}, * Creates a network node that makes the specified file system available via
* but creates an unlabeled file system (i.e. the label can neither be read * the common file system driver.
* nor written). * <p/>
* 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. * @param fileSystem the file system to wrap.
* @return the network node wrapping the file system. * @return the network node wrapping the file system.
*/ */
public static ManagedEnvironment asManagedEnvironment(final li.cil.oc.api.fs.FileSystem fileSystem) { public static ManagedEnvironment asManagedEnvironment(final li.cil.oc.api.fs.FileSystem fileSystem) {
if (API.fileSystem != null) return asManagedEnvironment(fileSystem, (Label) null, null, null, 1);
return API.fileSystem.asManagedEnvironment(fileSystem);
return null;
} }
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //

View File

@ -30,11 +30,11 @@ public interface Keyboard extends Environment, Persistable {
void setUsableOverride(UsabilityChecker callback); 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) * @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. * Whether the specified keyboard is usable by the specified player.
* *

View File

@ -563,7 +563,7 @@ public interface TextBuffer extends ManagedEnvironment, Persistable {
/** /**
* Used when setting a buffer's maximum color depth. * Used when setting a buffer's maximum color depth.
*/ */
public static enum ColorDepth { enum ColorDepth {
/** /**
* Monochrome color, black and white. * Monochrome color, black and white.
*/ */

View File

@ -83,56 +83,76 @@ public interface FileSystemAPI {
* access sounds. * access sounds.
* <p/> * <p/>
* The container may be <tt>null</tt>, if no such context can be provided. * The container may be <tt>null</tt>, if no such context can be provided.
* <p/>
* 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 <tt>null</tt> to create a silent file system.
* <p/>
* 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 fileSystem the file system to wrap.
* @param label the label of the file system. * @param label the label of the file system.
* @param host the tile entity containing 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 * @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.
* <tt>opencomputers:floppy_access</tt>.
* @param speed the speed multiplier for this file system.
* @return the network node wrapping the 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)}, * Creates a network node that makes the specified file system available via
* but creates a read-only label initialized to the specified value. * the common file system driver.
* <p/>
* 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 fileSystem the file system to wrap.
* @param label the read-only label of the file system. * @param label the read-only label of the file system.
* @param host the tile entity containing 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 * @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.
* <tt>opencomputers:floppy_access</tt>.
* @param speed the speed multiplier for this file system.
* @return the network node wrapping the 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); 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)}, * @deprecated Don't use this directly, use the wrapper in {@link li.cil.oc.api.FileSystem}.
* 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
ManagedEnvironment asManagedEnvironment(FileSystem fileSystem, Label label); ManagedEnvironment asManagedEnvironment(FileSystem fileSystem, Label label);
/** /**
* Like {@link #asManagedEnvironment(li.cil.oc.api.fs.FileSystem, Label)}, * @deprecated Don't use this directly, use the wrapper in {@link li.cil.oc.api.FileSystem}.
* 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
ManagedEnvironment asManagedEnvironment(FileSystem fileSystem, String label); ManagedEnvironment asManagedEnvironment(FileSystem fileSystem, String label);
/** /**
* Like {@link #asManagedEnvironment(li.cil.oc.api.fs.FileSystem, Label)}, * @deprecated Don't use this directly, use the wrapper in {@link li.cil.oc.api.FileSystem}.
* 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
ManagedEnvironment asManagedEnvironment(FileSystem fileSystem); ManagedEnvironment asManagedEnvironment(FileSystem fileSystem);
} }

View File

@ -0,0 +1,43 @@
package li.cil.oc.api.driver.item;
import li.cil.oc.api.event.RobotRenderEvent;
import li.cil.oc.api.internal.Robot;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
/**
* This interface can be implemented by items to allow custom rendering of
* upgrades installed in robots.
* <p/>
* 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.
* <p/>
* 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.
* <p/>
* If the stack cannot be rendered, simply do nothing. This way it's fine
* to implement this on a meta item.
* <p/>
* You usually won't need the robot parameter, but in case you <em>do</em>
* 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);
}

View File

@ -5,7 +5,7 @@ import li.cil.oc.api.Persistable;
/** /**
* Used by file system components to get and set the file system's label. * 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 { public interface Label extends Persistable {
/** /**

View File

@ -1,6 +1,34 @@
# Do not change this file, it is rewritten each time you start the game. # 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. # 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") include file("hardmode.recipes")
analyzer { analyzer {

View File

@ -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)) {
Textures.bind(Textures.Model.UpgradeCrafting)
drawSimpleBlock(mountPoint)
RenderState.checkError(getClass.getName + ".renderItem: crafting upgrade")
}
else if (descriptor == api.Items.get(Constants.ItemName.GeneratorUpgrade)) {
Textures.bind(Textures.Model.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)) {
Textures.bind(Textures.Model.UpgradeInventory)
drawSimpleBlock(mountPoint)
RenderState.checkError(getClass.getName + ".renderItem: inventory upgrade")
}
}
private val bounds = AxisAlignedBB.fromBounds(-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()
}
}

View File

@ -3,6 +3,7 @@ package li.cil.oc.client.renderer.tileentity
import com.google.common.base.Strings import com.google.common.base.Strings
import li.cil.oc.OpenComputers import li.cil.oc.OpenComputers
import li.cil.oc.Settings import li.cil.oc.Settings
import li.cil.oc.api.driver.item.UpgradeRenderer
import li.cil.oc.api.event.RobotRenderEvent import li.cil.oc.api.event.RobotRenderEvent
import li.cil.oc.client.Textures import li.cil.oc.client.Textures
import li.cil.oc.common.EventHandler import li.cil.oc.common.EventHandler
@ -22,7 +23,6 @@ import net.minecraft.tileentity.TileEntity
import net.minecraft.util.EnumChatFormatting import net.minecraft.util.EnumChatFormatting
import net.minecraft.util.EnumFacing import net.minecraft.util.EnumFacing
import net.minecraft.util.Vec3 import net.minecraft.util.Vec3
import net.minecraftforge.client.IItemRenderer.ItemRenderType
import net.minecraftforge.client.MinecraftForgeClient import net.minecraftforge.client.MinecraftForgeClient
import net.minecraftforge.common.MinecraftForge import net.minecraftforge.common.MinecraftForge
import org.lwjgl.opengl.GL11 import org.lwjgl.opengl.GL11
@ -123,7 +123,7 @@ object RobotRenderer extends TileEntitySpecialRenderer {
// Back. // Back.
mountPoints(0).offset.setX(0) 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).offset.setZ(0.24f)
mountPoints(0).rotation.setX(0) mountPoints(0).rotation.setX(0)
mountPoints(0).rotation.setY(1) mountPoints(0).rotation.setY(1)
@ -131,7 +131,7 @@ object RobotRenderer extends TileEntitySpecialRenderer {
mountPoints(0).rotation.setW(180) mountPoints(0).rotation.setW(180)
mountPoints(1).offset.setX(0) 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).offset.setZ(0.24f)
mountPoints(1).rotation.setX(0) mountPoints(1).rotation.setX(0)
mountPoints(1).rotation.setY(1) mountPoints(1).rotation.setY(1)
@ -140,7 +140,7 @@ object RobotRenderer extends TileEntitySpecialRenderer {
// Front. // Front.
mountPoints(2).offset.setX(0) 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).offset.setZ(0.24f)
mountPoints(2).rotation.setX(0) mountPoints(2).rotation.setX(0)
mountPoints(2).rotation.setY(1) mountPoints(2).rotation.setY(1)
@ -149,7 +149,7 @@ object RobotRenderer extends TileEntitySpecialRenderer {
// Left. // Left.
mountPoints(3).offset.setX(0) 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).offset.setZ(0.24f)
mountPoints(3).rotation.setX(0) mountPoints(3).rotation.setX(0)
mountPoints(3).rotation.setY(1) mountPoints(3).rotation.setY(1)
@ -157,7 +157,7 @@ object RobotRenderer extends TileEntitySpecialRenderer {
mountPoints(3).rotation.setW(90) mountPoints(3).rotation.setW(90)
mountPoints(4).offset.setX(0) 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).offset.setZ(0.24f)
mountPoints(4).rotation.setX(0) mountPoints(4).rotation.setX(0)
mountPoints(4).rotation.setY(1) mountPoints(4).rotation.setY(1)
@ -166,7 +166,7 @@ object RobotRenderer extends TileEntitySpecialRenderer {
// Right. // Right.
mountPoints(5).offset.setX(0) 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).offset.setZ(0.24f)
mountPoints(5).rotation.setX(0) mountPoints(5).rotation.setX(0)
mountPoints(5).rotation.setY(1) mountPoints(5).rotation.setY(1)
@ -174,7 +174,7 @@ object RobotRenderer extends TileEntitySpecialRenderer {
mountPoints(5).rotation.setW(-90) mountPoints(5).rotation.setW(-90)
mountPoints(6).offset.setX(0) 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).offset.setZ(0.24f)
mountPoints(6).rotation.setX(0) mountPoints(6).rotation.setX(0)
mountPoints(6).rotation.setY(1) mountPoints(6).rotation.setY(1)
@ -378,22 +378,17 @@ object RobotRenderer extends TileEntitySpecialRenderer {
case _ => 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) if (MinecraftForgeClient.getRenderPass == 0) {
for ((stack, mountPoint) <- stacks.zip(mountPoints)) { val stacks = (robot.componentSlots ++ robot.containerSlots).map(robot.getStackInSlot).
try { filter(stack => stack != null && stack.getItem.isInstanceOf[UpgradeRenderer]).
if (stack != null /* && (stack.getItem.requiresMultipleRenderPasses() || MinecraftForgeClient.getRenderPass == 0) TODO remove? */ ) { take(mountPoints.length)
val tint = stack.getItem.getColorFromItemStack(stack, MinecraftForgeClient.getRenderPass) for ((stack, mountPoint) <- stacks.zip(mountPoints.take(stacks.length))) try stack.getItem match {
val r = ((tint >> 16) & 0xFF) / 255f case renderer: UpgradeRenderer =>
val g = ((tint >> 8) & 0xFF) / 255f
val b = ((tint >> 0) & 0xFF) / 255f
RenderState.color(r, g, b, 1)
RenderState.pushMatrix() RenderState.pushMatrix()
GL11.glTranslatef(0.5f, 0.5f, 0.5f) GL11.glTranslatef(0.5f, 0.5f, 0.5f)
GL11.glRotatef(mountPoint.rotation.getW, mountPoint.rotation.getX, mountPoint.rotation.getY, mountPoint.rotation.getZ) renderer.render(stack, mountPoint, robot)
GL11.glTranslatef(mountPoint.offset.getX, mountPoint.offset.getY, mountPoint.offset.getZ)
itemRenderer.renderItem(Minecraft.getMinecraft.thePlayer, stack, TransformType.NONE)
RenderState.popMatrix() RenderState.popMatrix()
} case _ =>
} }
catch { catch {
case e: Throwable => case e: Throwable =>

View File

@ -82,13 +82,15 @@ class Proxy {
OpenComputers.channel.register(server.PacketHandler) OpenComputers.channel.register(server.PacketHandler)
Loot.init() Loot.init()
Recipes.init()
Achievement.init() Achievement.init()
EntityRegistry.registerModEntity(classOf[Drone], "Drone", 0, OpenComputers, 80, 1, true) EntityRegistry.registerModEntity(classOf[Drone], "Drone", 0, OpenComputers, 80, 1, true)
OpenComputers.log.info("Initializing mod integration.") OpenComputers.log.info("Initializing mod integration.")
Mods.init() Mods.init()
OpenComputers.log.info("Initializing recipes.")
Recipes.init()
} }
def postInit(e: FMLPostInitializationEvent) { def postInit(e: FMLPostInitializationEvent) {

View File

@ -5,6 +5,10 @@ import java.util.Random
import li.cil.oc.CreativeTab import li.cil.oc.CreativeTab
import li.cil.oc.OpenComputers import li.cil.oc.OpenComputers
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.common.tileentity
import li.cil.oc.util.BlockPosition import li.cil.oc.util.BlockPosition
import net.minecraft.client.resources.model.ModelResourceLocation import net.minecraft.client.resources.model.ModelResourceLocation
@ -34,7 +38,7 @@ object Delegator {
else None else None
} }
class Delegator extends Item { class Delegator extends Item with driver.item.UpgradeRenderer {
setHasSubtypes(true) setHasSubtypes(true)
setCreativeTab(CreativeTab) setCreativeTab(CreativeTab)
@ -210,4 +214,9 @@ class Delegator extends Item {
} }
override def toString = getUnlocalizedName override def toString = getUnlocalizedName
// ----------------------------------------------------------------------- //
@SideOnly(Side.CLIENT)
def render(stack: ItemStack, mountPoint: MountPoint, robot: Robot): Unit = UpgradeRenderer.render(stack, mountPoint)
} }

View File

@ -126,7 +126,8 @@ object ExtendedRecipe {
new ItemStack(net.minecraft.init.Blocks.diamond_block) 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) { for (stack <- inputs) {
if (beaconBlocks.exists(_.isItemEqual(stack))) { if (beaconBlocks.exists(_.isItemEqual(stack))) {
if (data.isBeaconBase) { if (data.isBeaconBase) {
@ -135,13 +136,20 @@ object ExtendedRecipe {
} }
data.isBeaconBase = true data.isBeaconBase = true
} }
if (glowstone.isItemEqual(stack)) { if (glowstoneDust.isItemEqual(stack)) {
if (data.lightLevel == 15) { if (data.lightLevel == 15) {
// Crafting wouldn't change anything, prevent accidental resource loss. // Crafting wouldn't change anything, prevent accidental resource loss.
return null return null
} }
data.lightLevel = math.min(15, data.lightLevel + 1) 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. // Finally apply modified data.

View File

@ -17,9 +17,10 @@ import net.minecraft.block.Block
import net.minecraft.item.Item import net.minecraft.item.Item
import net.minecraft.item.ItemBlock import net.minecraft.item.ItemBlock
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.item.crafting.FurnaceRecipes
import net.minecraft.nbt.NBTTagCompound import net.minecraft.nbt.NBTTagCompound
import net.minecraft.util.RegistryNamespaced import net.minecraft.util.RegistryNamespaced
import net.minecraftforge.fluids.FluidRegistry
import net.minecraftforge.fluids.FluidStack
import net.minecraftforge.fml.common.Loader import net.minecraftforge.fml.common.Loader
import net.minecraftforge.fml.common.registry.GameRegistry import net.minecraftforge.fml.common.registry.GameRegistry
import net.minecraftforge.oredict.OreDictionary import net.minecraftforge.oredict.OreDictionary
@ -34,6 +35,11 @@ object Recipes {
val list = mutable.LinkedHashMap.empty[ItemStack, String] val list = mutable.LinkedHashMap.empty[ItemStack, String]
val oreDictEntries = mutable.LinkedHashMap.empty[String, ItemStack] val oreDictEntries = mutable.LinkedHashMap.empty[String, ItemStack]
var hadErrors = false var hadErrors = false
val recipeHandlers = mutable.LinkedHashMap.empty[String, (ItemStack, Config) => Unit]
def registerRecipeHandler(name: String, recipe: (ItemStack, Config) => Unit): Unit = {
recipeHandlers += name -> recipe
}
def addBlock(instance: Block, name: String, oreDict: String*) = { def addBlock(instance: Block, name: String, oreDict: String*) = {
Items.registerBlock(instance, name) Items.registerBlock(instance, name)
@ -284,6 +290,16 @@ object Recipes {
GameRegistry.addRecipe(new ExtendedShapelessOreRecipe( GameRegistry.addRecipe(new ExtendedShapelessOreRecipe(
lightPrint, lightPrint,
print.createItemStack(1), new ItemStack(net.minecraft.init.Items.glowstone_dust))) 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 { catch {
case e: Throwable => OpenComputers.log.error("Error parsing recipes, you may not be able to craft any items from this mod!", e) case e: Throwable => OpenComputers.log.error("Error parsing recipes, you may not be able to craft any items from this mod!", e)
@ -293,134 +309,22 @@ object Recipes {
private def addRecipe(output: ItemStack, recipe: Config, name: String) = try { private def addRecipe(output: ItemStack, recipe: Config, name: String) = try {
val recipeType = tryGetType(recipe) val recipeType = tryGetType(recipe)
try { recipeHandlers.get(recipeType) match {
recipeType match { case Some(recipeHandler) => recipeHandler(output, recipe)
case "shaped" => addShapedRecipe(output, recipe) case _ =>
case "shapeless" => addShapelessRecipe(output, recipe) 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'.")
case "furnace" => addFurnaceRecipe(output, recipe)
/* TODO GregTech
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
}
}
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 hadErrors = true
} }
} }
catch { catch {
case e: Throwable => case e: RecipeException =>
OpenComputers.log.error(s"Failed adding recipe for $name, you will not be able to craft this item.", e) OpenComputers.log.error(s"Failed adding recipe for $name, you will not be able to craft this item.", e)
hadErrors = true hadErrors = true
} }
private def addShapedRecipe(output: ItemStack, recipe: Config) { def tryGetCount(recipe: Config) = if (recipe.hasPath("output")) recipe.getInt("output") else 1
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 def parseIngredient(entry: AnyRef) = entry match {
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: _*))
}
}
/* TODO GregTech
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.instance.addSmeltingRecipe(stack, output, 0)
case name: String =>
for (stack <- OreDictionary.getOres(name)) {
FurnaceRecipes.instance.addSmeltingRecipe(stack, output, 0)
}
case _ =>
}
}
private def parseIngredient(entry: AnyRef) = entry match {
case map: java.util.Map[AnyRef, AnyRef]@unchecked => case map: java.util.Map[AnyRef, AnyRef]@unchecked =>
if (map.contains("oreDict")) { if (map.contains("oreDict")) {
map.get("oreDict") match { map.get("oreDict") match {
@ -467,6 +371,14 @@ object Recipes {
case other => throw new RecipeException(s"Invalid ingredient type (not a map or string): $other") 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 { private def findItem(name: String) = getObjectWithoutFallback(Item.itemRegistry, name).orElse(Item.itemRegistry.find {
case item: Item => item.getUnlocalizedName == name || item.getUnlocalizedName == "item." + name || Item.itemRegistry.getNameForObject(item).toString == name case item: Item => item.getUnlocalizedName == name || item.getUnlocalizedName == "item." + name || Item.itemRegistry.getNameForObject(item).toString == name
case _ => false case _ => false
@ -483,8 +395,6 @@ object Recipes {
private def tryGetType(recipe: Config) = if (recipe.hasPath("type")) recipe.getString("type") else "shaped" 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
private def tryGetId(ingredient: java.util.Map[AnyRef, AnyRef]): Int = private def tryGetId(ingredient: java.util.Map[AnyRef, AnyRef]): Int =
if (ingredient.contains("subID")) ingredient.get("subID") match { if (ingredient.contains("subID")) ingredient.get("subID") match {
case id: Number => id.intValue case id: Number => id.intValue
@ -529,6 +439,6 @@ object Recipes {
} }
} }
private class RecipeException(message: String) extends RuntimeException(message) class RecipeException(message: String) extends RuntimeException(message)
} }

View File

@ -82,7 +82,7 @@ class Raid extends traits.Environment with traits.Inventory with traits.Rotatabl
filesystem.foreach(fs => if (fs.node != null) fs.node.remove()) filesystem.foreach(fs => if (fs.node != null) fs.node.remove())
val fs = api.FileSystem.asManagedEnvironment( val fs = api.FileSystem.asManagedEnvironment(
api.FileSystem.fromSaveDirectory(id, wipeDisksAndComputeSpace, Settings.get.bufferChanges), api.FileSystem.fromSaveDirectory(id, wipeDisksAndComputeSpace, Settings.get.bufferChanges),
label, this, Settings.resourceDomain + ":hdd_access"). label, this, Settings.resourceDomain + ":hdd_access", 6).
asInstanceOf[FileSystem] asInstanceOf[FileSystem]
val nbtToSetAddress = new NBTTagCompound() val nbtToSetAddress = new NBTTagCompound()
nbtToSetAddress.setString("address", id) nbtToSetAddress.setString("address", id)

View File

@ -15,5 +15,7 @@ object ModGregtech extends ModProxy {
MinecraftForge.EVENT_BUS.register(EventHandlerGregTech) MinecraftForge.EVENT_BUS.register(EventHandlerGregTech)
Driver.add(new DriverEnergyContainer) Driver.add(new DriverEnergyContainer)
RecipeHandler.init()
} }
} }

View File

@ -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.")
}
}

View File

@ -24,8 +24,8 @@ object DriverFileSystem extends Item {
override def createEnvironment(stack: ItemStack, host: EnvironmentHost) = override def createEnvironment(stack: ItemStack, host: EnvironmentHost) =
Delegator.subItem(stack) match { Delegator.subItem(stack) match {
case Some(hdd: HardDiskDrive) => createEnvironment(stack, hdd.kiloBytes * 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) case Some(disk: FloppyDisk) => createEnvironment(stack, Settings.get.floppySize * 1024, host, 1)
case _ => null case _ => null
} }
@ -42,14 +42,14 @@ object DriverFileSystem extends Item {
case _ => 0 case _ => 0
} }
private def createEnvironment(stack: ItemStack, capacity: Int, host: EnvironmentHost) = if (DimensionManager.getWorld(0) != null) { private def createEnvironment(stack: ItemStack, capacity: Int, host: EnvironmentHost, speed: Int) = if (DimensionManager.getWorld(0) != null) {
// We have a bit of a chicken-egg problem here, because we want to use the // 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, // node's address as the folder name... so we generate the address here,
// if necessary. No one will know, right? Right!? // if necessary. No one will know, right? Right!?
val address = addressFromTag(dataTag(stack)) val address = addressFromTag(dataTag(stack))
val isFloppy = api.Items.get(stack) == api.Items.get(Constants.ItemName.Floppy) val isFloppy = api.Items.get(stack) == api.Items.get(Constants.ItemName.Floppy)
val fs = oc.api.FileSystem.fromSaveDirectory(address, capacity, Settings.get.bufferChanges) 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) { if (environment != null && environment.node != null) {
environment.node.asInstanceOf[oc.server.network.Node].address = address environment.node.asInstanceOf[oc.server.network.Node].address = address
} }

View File

@ -34,5 +34,7 @@ object ModVanilla extends ModProxy {
Driver.add(ConverterNBT) Driver.add(ConverterNBT)
Driver.add(ConverterWorld) Driver.add(ConverterWorld)
Driver.add(ConverterWorldProvider) Driver.add(ConverterWorldProvider)
RecipeHandler.init()
} }
} }

View File

@ -0,0 +1,77 @@
package li.cil.oc.integration.vanilla
import com.typesafe.config.Config
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 net.minecraft.item.ItemStack
import net.minecraft.item.crafting.FurnaceRecipes
import net.minecraftforge.fml.common.registry.GameRegistry
import net.minecraftforge.oredict.OreDictionary
import scala.collection.convert.WrapAsScala._
import scala.collection.mutable
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 {
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, Iterable.empty[AnyRef]))((acc, ingredient) => {
val (pattern, ingredients) = acc
ingredient match {
case _@(_: ItemStack | _: String) =>
number += 1
(pattern.append(('a' + number).toChar), ingredients ++ Iterable(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.instance.addSmeltingRecipe(stack, output, 0)
case name: String =>
for (stack <- OreDictionary.getOres(name)) {
FurnaceRecipes.instance.addSmeltingRecipe(stack, output, 0)
}
case _ =>
}
}
}

View File

@ -23,7 +23,7 @@ import net.minecraftforge.common.util.Constants.NBT
import scala.collection.mutable 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). override val node = Network.newNode(this, Visibility.Network).
withComponent("filesystem", Visibility.Neighbors). withComponent("filesystem", Visibility.Neighbors).
withConnector(). withConnector().
@ -151,7 +151,6 @@ class FileSystem(val fileSystem: IFileSystem, var label: Label, val host: Option
result(handle) 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 { def read(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized {
val handle = args.checkInteger(0) val handle = args.checkInteger(0)
val n = math.min(Settings.get.maxReadBuffer, math.max(0, args.checkInteger(1))) 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 { def seek(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized {
val handle = args.checkInteger(0) val handle = args.checkInteger(0)
val whence = args.checkString(1) 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 { def write(context: Context, args: Arguments): Array[AnyRef] = fileSystem.synchronized {
val handle = args.checkInteger(0) val handle = args.checkInteger(0)
val value = args.checkByteArray(1) 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)
}
}
}

View File

@ -96,20 +96,26 @@ object FileSystem extends api.detail.FileSystemAPI {
def fromMemory(capacity: Long): api.fs.FileSystem = new RamFileSystem(capacity) def fromMemory(capacity: Long): api.fs.FileSystem = new RamFileSystem(capacity)
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) = 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) = 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) = 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) = 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) = 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 abstract class ItemLabel(val stack: ItemStack) extends Label

View File

@ -53,7 +53,7 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach
val tmp = if (Settings.get.tmpSize > 0) { val tmp = if (Settings.get.tmpSize > 0) {
Option(FileSystem.asManagedEnvironment(FileSystem. Option(FileSystem.asManagedEnvironment(FileSystem.
fromMemory(Settings.get.tmpSize * 1024), "tmpfs")) fromMemory(Settings.get.tmpSize * 1024), "tmpfs", null, null, 5))
} else None } else None
var architecture: Architecture = _ var architecture: Architecture = _