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

# Conflicts:
#	build.gradle
#	build.properties
#	src/main/java/li/cil/oc/api/Driver.java
#	src/main/java/li/cil/oc/api/detail/DriverAPI.java
#	src/main/scala/li/cil/oc/client/Textures.scala
#	src/main/scala/li/cil/oc/client/renderer/PetRenderer.scala
#	src/main/scala/li/cil/oc/client/renderer/item/HoverBootRenderer.scala
#	src/main/scala/li/cil/oc/common/item/HoverBoots.scala
#	src/main/scala/li/cil/oc/integration/Mods.scala
#	src/main/scala/li/cil/oc/server/driver/CompoundBlockDriver.scala
#	src/main/scala/li/cil/oc/server/driver/Registry.scala
This commit is contained in:
Florian Nücke 2016-02-27 13:38:18 +01:00
commit 338666235b
31 changed files with 620 additions and 67 deletions

View File

@ -164,6 +164,10 @@ repositories {
name 'ExtraCells'
artifactPattern "http://addons-origin.cursecdn.com/files/${config.ec.cf}/[module]-[revision].[ext]"
}
ivy {
name 'ThaumicEnergistics'
artifactPattern "http://addons-origin.cursecdn.com/files/${config.thaumicenergistics.cf}/[module]-[revision].[ext]"
}
*/
}
@ -214,6 +218,7 @@ dependencies {
provided name: 'Railcraft', version: config.rc.version, ext: 'jar'
provided name: 'BloodMagic', version: config.bloodmagic.version, ext: 'jar'
provided name: 'ExtraCells', version: config.ec.version, ext: 'jar'
provided name: 'ThaumicEnergistics', version: config.thaumicenergistics.version, ext: 'jar'
provided "cyano.poweradvantage:PowerAdvantage-API:${config.poweradvantage.version}"
*/

View File

@ -43,6 +43,8 @@ rc.cf=2219/321
rc.version=1.7.10-9.4.0.0
redlogic.version=59.0.3
rotc.version=V5c
thaumicenergistics.cf=2277/520
thaumicenergistics.version=1.0.0.1-RV2
tis3d.version=MC1.8.9-0.8.0.2
tmech.version=75.0afb56c
re.version=3.0.0.342

View File

@ -5,11 +5,13 @@ import li.cil.oc.api.driver.Converter;
import li.cil.oc.api.driver.EnvironmentProvider;
import li.cil.oc.api.driver.InventoryProvider;
import li.cil.oc.api.driver.Item;
import li.cil.oc.api.driver.SidedBlock;
import li.cil.oc.api.network.EnvironmentHost;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.util.BlockPos;
import net.minecraft.util.EnumFacing;
import net.minecraft.world.World;
import java.util.Collection;
@ -28,7 +30,7 @@ import java.util.Collection;
* at that time. Only start calling these methods in the init phase or later.
*
* @see Network
* @see Block
* @see SidedBlock
* @see Item
*/
public final class Driver {
@ -43,12 +45,31 @@ public final class Driver {
* phases.
*
* @param driver the driver to register.
* @deprecated Use {@link SidedBlock} instead.
*/
@Deprecated // TODO Remove in OC 1.7
public static void add(final Block driver) {
if (API.driver != null)
API.driver.add(driver);
}
/**
* Registers a new side-aware block driver.
* <p/>
* Whenever the neighboring blocks of an Adapter block change, it checks if
* there exists a driver for the changed block, and if it is configured to
* interface that block type connects it to the component network.
* <p/>
* This must be called in the init phase, <em>not</em> the pre- or post-init
* phases.
*
* @param driver the driver to register.
*/
public static void add(final SidedBlock driver) {
if (API.driver != null)
API.driver.add(driver);
}
/**
* Registers a new item driver.
* <p/>
@ -121,13 +142,35 @@ public final class Driver {
* @param world the world containing the block.
* @param pos the position of the block.
* @return a driver for the block, or <tt>null</tt> if there is none.
* @deprecated Use {@link #driverFor(World, BlockPos, EnumFacing)},
* passing <tt>null</tt> if the side is to be ignored.
*/
@Deprecated // TODO Remove in OC 1.7
public static Block driverFor(World world, BlockPos pos) {
if (API.driver != null)
return API.driver.driverFor(world, pos);
return null;
}
/**
* Looks up a driver for the block at the specified position in the
* specified world.
* <p/>
* Note that several drivers for a single block can exist. Because of this
* block drivers are always encapsulated in a 'compound' driver, which is
* what will be returned here. In other words, you should will <em>not</em>
* get actual instances of drivers registered via {@link #add(li.cil.oc.api.driver.Block)}.
*
* @param world the world containing the block.
* @param pos the position of the block.
* @return a driver for the block, or <tt>null</tt> if there is none.
*/
public static SidedBlock driverFor(World world, BlockPos pos, EnumFacing side) {
if (API.driver != null)
return API.driver.driverFor(world, pos, side);
return null;
}
/**
* Looks up a driver for the specified item stack.
* <p/>

View File

@ -5,11 +5,13 @@ import li.cil.oc.api.driver.Converter;
import li.cil.oc.api.driver.EnvironmentProvider;
import li.cil.oc.api.driver.InventoryProvider;
import li.cil.oc.api.driver.Item;
import li.cil.oc.api.driver.SidedBlock;
import li.cil.oc.api.network.EnvironmentHost;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.util.BlockPos;
import net.minecraft.util.EnumFacing;
import net.minecraft.world.World;
import java.util.Collection;
@ -26,9 +28,25 @@ public interface DriverAPI {
* phases.
*
* @param driver the driver for a block component.
* @deprecated Use {@link SidedBlock} instead.
*/
@Deprecated // TODO Remove in OC 1.7
void add(Block driver);
/**
* Registers a new side-aware block driver.
* <p/>
* Whenever the neighboring blocks of an Adapter block change, it checks if
* there exists a driver for the changed block, and if it is configured to
* interface that block type connects it to the component network.
* <p/>
* This must be called in the init phase, <em>not</em> the pre- or post-init
* phases.
*
* @param driver the driver to register.
*/
void add(SidedBlock driver);
/**
* Registers a new driver for an item component.
* <p/>
@ -89,9 +107,28 @@ public interface DriverAPI {
* @param world the world containing the block.
* @param pos the position of the block.
* @return a driver for the block, or <tt>null</tt> if there is none.
* @deprecated Use {@link #driverFor(World, BlockPos, EnumFacing)},
* passing <tt>null</tt> if the side is to be ignored.
*/
@Deprecated // TODO Remove in OC 1.7
Block driverFor(World world, BlockPos pos);
/**
* Looks up a driver for the block at the specified position in the
* specified world.
* <p/>
* Note that several drivers for a single block can exist. Because of this
* block drivers are always encapsulated in a 'compound' driver, which is
* what will be returned here. In other words, you should will <em>not</em>
* get actual instances of drivers registered via {@link #add(li.cil.oc.api.driver.Block)}.
*
* @param world the world containing the block.
* @param pos the position of the block.
* @param side the side of the block.
* @return a driver for the block, or <tt>null</tt> if there is none.
*/
SidedBlock driverFor(World world, BlockPos pos, EnumFacing side);
/**
* Looks up a driver for the specified item stack.
* <p/>

View File

@ -21,7 +21,11 @@ import net.minecraft.world.World;
* Note that it is possible to write one driver that supports as many different
* blocks as you wish. I'd recommend writing one per device (type), though, to
* keep things modular.
*
* @deprecated Use {@link SidedBlock} instead, ignoring the side argument if
* the side doesn't matter.
*/
@Deprecated // TODO Remove in OC 1.7
public interface Block {
/**
* Used to determine the block types this driver handles.

View File

@ -0,0 +1,71 @@
package li.cil.oc.api.driver;
import li.cil.oc.api.network.ManagedEnvironment;
import net.minecraft.util.BlockPos;
import net.minecraft.util.EnumFacing;
import net.minecraft.world.World;
/**
* Interface for side-aware block component drivers.
* <p/>
* This driver type is used for components that are blocks, i.e. that can be
* placed in the world, but cannot be modified to or don't want to have their
* {@link net.minecraft.tileentity.TileEntity} implement one of the interfaces
* for environments ({@link li.cil.oc.api.network.Environment} or
* {@link li.cil.oc.api.network.SidedEnvironment}).
* <p/>
* A block driver is used by <tt>Adapter</tt> blocks to check its neighbors and
* whether those neighbors should be treated as components or not. If a driver
* is present, it will be used to create a {@link ManagedEnvironment} that is
* managed by the adapter.
* <p/>
* Note that it is possible to write one driver that supports as many different
* blocks as you wish. I'd recommend writing one per device (type), though, to
* keep things modular.
* </p>
* Note that side-aware block drivers are queried before regular block drivers,
* because they are more specific.
*/
public interface SidedBlock {
/**
* Used to determine the block types this driver handles.
* <p/>
* This is used to determine which driver to use for a block placed next to
* an <tt>Adapter</tt> block. Note that the return value should not change
* over time; if it does, though, an already installed component will not
* be removed, since this value is only checked when scanning blocks. You
* can force this by sending a neighbor block change notification.
* <p/>
* The side is relative to the block, i.e. "south" is the side of the block
* facing south.
*
* @param world the world in which the block to check lives.
* @param pos the position coordinate of the block to check.
* @param side the side of the block to check.
* @return <tt>true</tt> if the block is supported; <tt>false</tt> otherwise.
*/
boolean worksWith(World world, BlockPos pos, EnumFacing side);
/**
* Create a new managed environment interfacing the specified block.
* <p/>
* This is used to connect the component to the component network when it
* is detected next to an <tt>Adapter</tt>. Components that are not part of
* the component network probably don't make much sense (can't think of any
* uses at this time), but you may still opt to not implement this - i.e.
* it is safe to return <tt>null</tt> here.
* <p/>
* This is expected to return a <em>new instance</em> each time it is
* called. The created instance's life cycle is managed by the
* <tt>Adapter</tt> block that caused its creation.
* <p/>
* The side is relative to the block, i.e. "south" is the side of the block
* facing south.
*
* @param world the world containing the block to get the environment for.
* @param pos the position coordinate of the block to check.
* @param side the side of the block to check.
* @return the environment for the block at that location.
*/
ManagedEnvironment createEnvironment(World world, BlockPos pos, EnumFacing side);
}

View File

@ -1337,7 +1337,8 @@ opencomputers {
# computers (such as magic related mods, which is why Thaumcraft is on this
# list by default.)
modBlacklist: [
"Thaumcraft"
"Thaumcraft",
"thaumicenergistics"
]
# A list of tile entities by class name that should NOT be accessible via

View File

@ -9,3 +9,5 @@ Either way, these boots have a few useful properties: as long as they have power
Additionally, due to always being in kind of a hovering state anyway, they allow you to seamlessly walk up steps of up to one block height. This is particularly handy when sprinting up a mountain, for example, a very commonplace fitness routine amongst Minecrafters. Or so I hear.
The boots can be recharged in an OpenComputers [charger](../block/charger.md) or any other such device, like the Applied Energistics 2 charger, an IndustrialCraft 2 battery box, or the Energetic Infuser from Thermal Expansion.
You can change the boots' color by crafting them with any type of dye. Akin to leather armor, it is possible to apply multiple dyes at once or in succession to create a large variety of colors. The dye can be removed again either by crafting the boots with a bucket of water or by tossing them into a cauldron.

View File

@ -59,6 +59,11 @@ local function areEqual(path1, path2)
return result
end
local mounts = {}
for dev,path in fs.mounts() do
mounts[fs.canonical(path)] = dev
end
local function recurse(fromPath, toPath, origin)
status(fromPath, toPath)
if fs.isDirectory(fromPath) then
@ -66,17 +71,17 @@ local function recurse(fromPath, toPath, origin)
io.write("omitting directory `" .. fromPath .. "'\n")
return true
end
if fs.canonical(fs.path(toPath)):find(fs.canonical(fromPath),1,true) then
return nil, "cannot copy a directory, `" .. fromPath .. "', into itself, `" .. toPath .. "'"
end
if fs.exists(toPath) and not fs.isDirectory(toPath) then
-- my real cp always does this, even with -f, -n or -i.
return nil, "cannot overwrite non-directory `" .. toPath .. "' with directory `" .. fromPath .. "'"
end
fs.makeDirectory(toPath)
if options.x and origin and fs.get(fromPath) ~= origin then
if options.x and origin and mounts[fs.canonical(fromPath)] then
return true
end
if fs.get(fromPath) == fs.get(toPath) and fs.canonical(fs.path(toPath)):find(fs.canonical(fromPath),1,true) then
return nil, "cannot copy a directory, `" .. fromPath .. "', into itself, `" .. toPath .. "'"
end
fs.makeDirectory(toPath)
for file in fs.list(fromPath) do
local result, reason = recurse(fs.concat(fromPath, file), fs.concat(toPath, file), origin or fs.get(fromPath))
if not result then

View File

@ -60,7 +60,7 @@ io.write("Installing " .. name .." to device " .. (choice.getLabel() or choice.a
os.sleep(0.25)
local cpPath = filesystem.concat(findMount(filesystem.get(os.getenv("_")).address), "bin/cp")
local cpOptions = "-vrx" .. (options.u and "ui " or "")
local cpSource = filesystem.concat(findMount(fromAddress), options.fromDir or "/", "*")
local cpSource = filesystem.concat(findMount(fromAddress), options.fromDir or "/")
local cpDest = findMount(choice.address) .. "/"
local result, reason = os.execute(cpPath .. " " .. cpOptions .. " " .. cpSource .. " " .. cpDest)
if not result then

View File

@ -118,31 +118,42 @@ function text.removeEscapes(txt)
end
-------------------------------------------------------------------------------
function --[[@delayloaded-start@]] text.split(input, delimiters, dropDelims)
function --[[@delayloaded-start@]] text.split(input, delimiters, dropDelims, di)
checkArg(1, input, "string")
checkArg(2, delimiters, "table")
checkArg(3, dropDelims, "boolean", "nil")
checkArg(4, di, "number", "nil")
local input_table = text.internal.table_view(input)
local delim_table = tx.select(delimiters, function(e,i,t)
return text.internal.table_view(e)
end)
local parts = tx.partition(input_table, function(e,i,t)
local ns, ne = tx.first(t,delim_table,i)
if not ns or dropDelims or ns == i then
return ns, ne
else -- not droping delims and ns>i
return i, ns-1
if #input == 0 then return {} end
di = di or 1
local result = {input}
if di > #delimiters then return result end
local function add(part, index, r, s, e)
local sub = part:sub(s,e)
if #sub == 0 then return index end
local subs = r and text.split(sub,delimiters,dropDelims,r) or {sub}
for i=1,#subs do
table.insert(result, index+i-1, subs[i])
end
end, dropDelims)
return tx.select(parts, function(e,i,t)
local inner = ''
tx.foreach(e, function(ee,ii,tt)
inner = inner..ee
end)
return inner
end)
return index+#subs
end
local i,d=1,delimiters[di]
while true do
local next = table.remove(result,i)
if not next then break end
local si,ei = next:find(d)
if si and ei and ei~=0 then -- delim found
i=add(next, i, di+1, 1, si-1)
i=dropDelims and i or add(next, i, false, si, ei)
i=add(next, i, di, ei+1)
else
i=add(next, i, di+1, 1, #next)
end
end
return result
end --[[@delayloaded-end@]]
-----------------------------------------------------------------------------

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 461 B

After

Width:  |  Height:  |  Size: 420 B

View File

@ -8,7 +8,6 @@ import li.cil.oc.api.event.RobotRenderEvent
import li.cil.oc.client.renderer.tileentity.RobotRenderer
import li.cil.oc.util.RenderState
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.inventory.GuiContainer
import net.minecraft.client.renderer.GlStateManager
import net.minecraft.entity.Entity
import net.minecraftforge.client.event.RenderPlayerEvent
@ -26,16 +25,16 @@ object PetRenderer {
// http://goo.gl/frLWYR
private val entitledPlayers = Map(
"Sangar" ->(0.3, 0.9, 0.6),
"Jodarion" ->(1.0, 0.0, 0.0),
"DaKaTotal" ->(0.5, 0.7, 1.0),
"MichiRavencroft" ->(1.0, 0.0, 0.0),
"Vexatos" ->(0.18, 0.95, 0.922),
"StoneNomad" ->(0.8, 0.77, 0.75),
"LizzyTheSiren" ->(0.3, 0.3, 1.0),
"vifino" ->(0.2, 1.0, 0.1),
"Izaya" ->(0.0, 0.2, 0.6),
"Wobbo" ->(0.098, 0.471, 0.784)
"9f1f262f-0d68-4e13-9161-9eeaf4a0a1a8" ->(0.3, 0.9, 0.6), // Sangar
"18f8bed4-f027-44af-8947-6a3a2317645a" ->(1.0, 0.0, 0.0), // Jodarion
"36123742-2cf6-4cfc-8b65-278581b3caeb" ->(0.5, 0.7, 1.0), // DaKaTotal
"2c0c214b-96f4-4565-b513-de90d5fbc977" ->(1.0, 0.0, 0.0), // MichiRavencroft
"f3ba6ec8-c280-4950-bb08-1fcb2eab3a9c" ->(0.18, 0.95, 0.922), // Vexatos
"9d636bdd-b9f4-4b80-b9ce-586ca04bd4f3" ->(0.8, 0.77, 0.75), // StoneNomad
"23c7ed71-fb13-4abe-abe7-f355e1de6e62" ->(0.3, 0.3, 1.0), // LizzyTheSiren
"076541f1-f10a-46de-a127-dfab8adfbb75" ->(0.2, 1.0, 0.1), // vifino
"e7e90198-0ccf-4662-a827-192ec8f4419d" ->(0.0, 0.2, 0.6), // Izaya
"f514ee69-7bbb-4e46-9e94-d8176324cec2" ->(0.098, 0.471, 0.784) // Wobbo
)
private val petLocations = com.google.common.cache.CacheBuilder.newBuilder().
@ -47,9 +46,9 @@ object PetRenderer {
@SubscribeEvent
def onPlayerRender(e: RenderPlayerEvent.Pre) {
val name = e.entityPlayer.getName
if (hidden.contains(name) || !entitledPlayers.contains(name)) return
rendering = Some(entitledPlayers(name))
val uuid = e.entityPlayer.getUniqueID.toString
if (hidden.contains(uuid) || !entitledPlayers.contains(uuid)) return
rendering = Some(entitledPlayers(uuid))
val worldTime = e.entityPlayer.getEntityWorld.getTotalWorldTime
val timeJitter = e.entityPlayer.hashCode ^ 0xFF
@ -144,8 +143,7 @@ object PetRenderer {
GlStateManager.translate(0.3, -0.1, -0.2)
}
// Someone please tell me a cleaner solution than this...
private def isForInventory = new Exception().getStackTrace.exists(_.getClassName == classOf[GuiContainer].getName)
private def isForInventory = Minecraft.getMinecraft.currentScreen != null && owner == Minecraft.getMinecraft.thePlayer
}
@SubscribeEvent

View File

@ -91,6 +91,8 @@ object HoverBootRenderer extends ModelBiped {
bipedRightArm.isHidden = true
bipedLeftArm.isHidden = true
var lightColor = 0x66DD55
override def render(entity: Entity, f0: Float, f1: Float, f2: Float, f3: Float, f4: Float, f5: Float): Unit = {
// Because Forge is being a dummy...
isSneak = entity.isSneaking
@ -103,10 +105,12 @@ object HoverBootRenderer extends ModelBiped {
override def render(dt: Float): Unit = {
GlStateManager.pushAttrib()
GlStateManager.disableLighting()
RenderHelper.disableStandardItemLighting()
GlStateManager.depthFunc(GL11.GL_LEQUAL)
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE)
GlStateManager.color(0x66 / 255f, 0xDD / 255f, 0x55 / 255f)
val r = ((lightColor >>> 16) & 0xFF) / 255f
val g = ((lightColor >>> 8) & 0xFF) / 255f
val b = ((lightColor >>> 0) & 0xFF) / 255f
GlStateManager.color(r, g, b)
super.render(dt)

View File

@ -3,10 +3,14 @@ package li.cil.oc.common.item
import li.cil.oc.Settings
import li.cil.oc.client.renderer.item.HoverBootRenderer
import li.cil.oc.common.item.data.HoverBootsData
import li.cil.oc.util.ItemColorizer
import net.minecraft.block.BlockCauldron
import net.minecraft.client.model.ModelBiped
import net.minecraft.entity.Entity
import net.minecraft.entity.EntityLivingBase
import net.minecraft.entity.item.EntityItem
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.init.Blocks
import net.minecraft.item.EnumRarity
import net.minecraft.item.ItemArmor
import net.minecraft.item.ItemStack
@ -56,7 +60,10 @@ class HoverBoots extends ItemArmor(ItemArmor.ArmorMaterial.DIAMOND, 0, 3) with t
@SideOnly(Side.CLIENT)
override def getArmorModel(entityLiving: EntityLivingBase, itemStack: ItemStack, armorSlot: Int): ModelBiped = {
if (armorSlot == 4 - armorType) HoverBootRenderer
if (armorSlot == 4 - armorType) {
HoverBootRenderer.lightColor = if (ItemColorizer.hasColor(itemStack)) ItemColorizer.getColor(itemStack) else 0x66DD55
HoverBootRenderer
}
else super.getArmorModel(entityLiving, itemStack, armorSlot)
}
@ -77,6 +84,29 @@ class HoverBoots extends ItemArmor(ItemArmor.ArmorMaterial.DIAMOND, 0, 3) with t
}
}
override def onEntityItemUpdate(entity: EntityItem): Boolean = {
if (entity != null && entity.worldObj != null && !entity.worldObj.isRemote && ItemColorizer.hasColor(entity.getEntityItem)) {
val pos = entity.getPosition
val state = entity.worldObj.getBlockState(pos)
if (state.getBlock == Blocks.cauldron) {
val level = state.getValue(BlockCauldron.LEVEL).toInt
if (level > 0) {
ItemColorizer.removeColor(entity.getEntityItem)
entity.worldObj.setBlockState(pos, state.withProperty(BlockCauldron.LEVEL, Int.box(level - 1)), 3)
return true
}
}
}
super.onEntityItemUpdate(entity)
}
override def getColorFromItemStack(itemStack: ItemStack, pass: Int): Int = {
if (pass == 1) {
return if (ItemColorizer.hasColor(itemStack)) ItemColorizer.getColor(itemStack) else 0x66DD55
}
super.getColorFromItemStack(itemStack, pass)
}
override def showDurabilityBar(stack: ItemStack): Boolean = true
override def getDurabilityForDisplay(stack: ItemStack): Double = {

View File

@ -0,0 +1,86 @@
package li.cil.oc.common.recipe
import li.cil.oc.util.Color
import li.cil.oc.util.ItemColorizer
import net.minecraft.entity.passive.EntitySheep
import net.minecraft.inventory.InventoryCrafting
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.world.World
/**
* @author asie, Vexatos
*/
class ColorizeRecipe(target: Item, source: Array[Item] = null) extends ContainerItemAwareRecipe {
val targetItem = target
val sourceItems = if (source != null) source else Array(targetItem)
override def matches(crafting: InventoryCrafting, world: World): Boolean = {
val stacks = (0 until crafting.getSizeInventory).flatMap(i => Option(crafting.getStackInSlot(i)))
val targets = stacks.filter(stack => sourceItems.contains(stack.getItem) || stack.getItem == targetItem)
val other = stacks.filterNot(targets.contains)
targets.size == 1 && other.nonEmpty && other.forall(Color.isDye)
}
override def getCraftingResult(crafting: InventoryCrafting): ItemStack = {
var targetStack: ItemStack = null
val color = Array[Int](0, 0, 0)
var colorCount = 0
var maximum = 0
(0 until crafting.getSizeInventory).flatMap(i => Option(crafting.getStackInSlot(i))).foreach { stack =>
if (sourceItems.contains(stack.getItem)
|| stack.getItem == targetItem) {
targetStack = stack.copy()
targetStack.stackSize = 1
} else {
val dye = Color.findDye(stack)
if (dye.isEmpty)
return null
val itemColor = EntitySheep.func_175513_a(Color.byOreName(dye.get))
val red = (itemColor(0) * 255.0F).toInt
val green = (itemColor(1) * 255.0F).toInt
val blue = (itemColor(2) * 255.0F).toInt
maximum += Math.max(red, Math.max(green, blue))
color(0) += red
color(1) += green
color(2) += blue
colorCount = colorCount + 1
}
}
if (targetStack == null) return null
if (targetItem == targetStack.getItem) {
if (ItemColorizer.hasColor(targetStack)) {
val itemColor = ItemColorizer.getColor(targetStack)
val red = (itemColor >> 16 & 255).toFloat / 255.0F
val green = (itemColor >> 8 & 255).toFloat / 255.0F
val blue = (itemColor & 255).toFloat / 255.0F
maximum = (maximum.toFloat + Math.max(red, Math.max(green, blue)) * 255.0F).toInt
color(0) = (color(0).toFloat + red * 255.0F).toInt
color(1) = (color(1).toFloat + green * 255.0F).toInt
color(2) = (color(2).toFloat + blue * 255.0F).toInt
colorCount = colorCount + 1
}
} else if (sourceItems.contains(targetStack.getItem)) {
targetStack = new ItemStack(targetItem, targetStack.stackSize, targetStack.getItemDamage)
}
var red = color(0) / colorCount
var green = color(1) / colorCount
var blue = color(2) / colorCount
val max = maximum.toFloat / colorCount.toFloat
val div = Math.max(red, Math.max(green, blue)).toFloat
red = (red.toFloat * max / div).toInt
green = (green.toFloat * max / div).toInt
blue = (blue.toFloat * max / div).toInt
ItemColorizer.setColor(targetStack, (red << 16) | (green << 8) | blue)
targetStack
}
override def getRecipeSize = 10
override def getRecipeOutput = null
}

View File

@ -0,0 +1,13 @@
package li.cil.oc.common.recipe
import net.minecraft.inventory.InventoryCrafting
import net.minecraft.item.crafting.IRecipe
trait ContainerItemAwareRecipe extends IRecipe {
override def getRemainingItems(inv: InventoryCrafting) =
(0 until inv.getSizeInventory).
map(inv.getStackInSlot).
map(net.minecraftforge.common.ForgeHooks.getContainerItem).
filter(_ != null).
toArray
}

View File

@ -0,0 +1,44 @@
package li.cil.oc.common.recipe
import li.cil.oc.util.ItemColorizer
import net.minecraft.init.Items
import net.minecraft.inventory.InventoryCrafting
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.world.World
/**
* @author Vexatos
*/
class DecolorizeRecipe(target: Item) extends ContainerItemAwareRecipe {
val targetItem = target
override def matches(crafting: InventoryCrafting, world: World): Boolean = {
val stacks = (0 until crafting.getSizeInventory).flatMap(i => Option(crafting.getStackInSlot(i)))
val targets = stacks.filter(stack => stack.getItem == targetItem)
val other = stacks.filterNot(targets.contains)
targets.size == 1 && other.size == 1 && other.forall(_.getItem == Items.water_bucket)
}
override def getCraftingResult(crafting: InventoryCrafting): ItemStack = {
var targetStack: ItemStack = null
(0 until crafting.getSizeInventory).flatMap(i => Option(crafting.getStackInSlot(i))).foreach { stack =>
if (stack.getItem == targetItem) {
targetStack = stack.copy()
targetStack.stackSize = 1
} else if (stack.getItem != Items.water_bucket) {
return null
}
}
if (targetStack == null) return null
ItemColorizer.removeColor(targetStack)
targetStack
}
override def getRecipeSize = 10
override def getRecipeOutput = null
}

View File

@ -102,6 +102,8 @@ object Recipes {
def init() {
RecipeSorter.register(Settings.namespace + "extshaped", classOf[ExtendedShapedOreRecipe], Category.SHAPED, "after:forge:shapedore")
RecipeSorter.register(Settings.namespace + "extshapeless", classOf[ExtendedShapelessOreRecipe], Category.SHAPELESS, "after:forge:shapelessore")
RecipeSorter.register(Settings.namespace + "colorizer", classOf[ColorizeRecipe], Category.SHAPELESS, "after:forge:shapelessore")
RecipeSorter.register(Settings.namespace + "decolorizer", classOf[DecolorizeRecipe], Category.SHAPELESS, "after:oc:colorizer")
for ((name, stack) <- oreDictEntries) {
if (!OreDictionary.getOres(name).contains(stack)) {
@ -333,6 +335,10 @@ object Recipes {
api.Items.get(Constants.BlockName.AccessPoint).createItemStack(1))
GameRegistry.addShapelessRecipe(api.Items.get(Constants.BlockName.Relay).createItemStack(1),
api.Items.get(Constants.BlockName.Switch).createItemStack(1))
// Hover Boot dyeing
GameRegistry.addRecipe(new ColorizeRecipe(api.Items.get(Constants.ItemName.HoverBoots).item()))
GameRegistry.addRecipe(new DecolorizeRecipe(api.Items.get(Constants.ItemName.HoverBoots).item()))
}
catch {
case e: Throwable => OpenComputers.log.error("Error parsing recipes, you may not be able to craft any items from this mod!", e)

View File

@ -78,6 +78,7 @@ object Mods {
override def isModAvailable: Boolean = isModAvailable_
}
val Thaumcraft = new SimpleMod(IDs.Thaumcraft)
val ThaumicEnergistics = new SimpleMod(IDs.ThaumicEnergistics)
val ThermalExpansion = new SimpleMod(IDs.ThermalExpansion, providesPower = true)
val TinkersConstruct = new SimpleMod(IDs.TinkersConstruct)
val TIS3D = new SimpleMod(IDs.TIS3D, version = "@[0.7,)")
@ -125,6 +126,7 @@ object Mods {
// integration.rotarycraft.ModRotaryCraft,
// integration.stargatetech2.ModStargateTech2,
// integration.thaumcraft.ModThaumcraft,
// integration.thaumicenergistics.ModThaumicEnergistics,
// integration.thermalexpansion.ModThermalExpansion,
integration.tis3d.ModTIS3D,
// integration.tcon.ModTinkersConstruct,
@ -219,6 +221,7 @@ object Mods {
final val RotaryCraft = "RotaryCraft"
final val StargateTech2 = "StargateTech2"
final val Thaumcraft = "Thaumcraft"
final val ThaumicEnergistics = "thaumicenergistics"
final val ThermalExpansion = "ThermalExpansion"
final val TinkersConstruct = "TConstruct"
final val TIS3D = "tis3d"

View File

@ -0,0 +1,27 @@
package li.cil.oc.integration.thaumicenergistics
import appeng.tile.misc.TileInterface
import li.cil.oc.api.driver.EnvironmentProvider
import li.cil.oc.api.network.ManagedEnvironment
import li.cil.oc.api.prefab.DriverTileEntity
import li.cil.oc.integration.ManagedTileEntityEnvironment
import li.cil.oc.integration.appeng.AEUtil
import net.minecraft.item.ItemStack
import net.minecraft.world.World
object DriverBlockInterface extends DriverTileEntity {
def getTileEntityClass: Class[_] = classOf[TileInterface]
def createEnvironment(world: World, x: Int, y: Int, z: Int): ManagedEnvironment =
new Environment(world.getTileEntity(x, y, z).asInstanceOf[TileInterface])
final class Environment(val tile: TileInterface) extends ManagedTileEntityEnvironment[TileInterface](tile, "me_interface") with NetworkControl[TileInterface]
object Provider extends EnvironmentProvider {
override def getEnvironment(stack: ItemStack): Class[_] =
if (AEUtil.isBlockInterface(stack))
classOf[Environment]
else null
}
}

View File

@ -0,0 +1,33 @@
package li.cil.oc.integration.thaumicenergistics
import appeng.api.networking.security.IActionHost
import appeng.me.helpers.IGridProxyable
import li.cil.oc.api.driver.EnvironmentProvider
import li.cil.oc.api.network.ManagedEnvironment
import li.cil.oc.api.prefab.DriverTileEntity
import li.cil.oc.integration.ManagedTileEntityEnvironment
import li.cil.oc.integration.appeng.AEUtil
import net.minecraft.item.ItemStack
import net.minecraft.tileentity.TileEntity
import net.minecraft.world.World
import scala.language.existentials
object DriverController extends DriverTileEntity {
private type TileController = TileEntity with IGridProxyable with IActionHost
def getTileEntityClass = AEUtil.controllerClass
def createEnvironment(world: World, x: Int, y: Int, z: Int): ManagedEnvironment =
new Environment(world.getTileEntity(x, y, z).asInstanceOf[TileController])
final class Environment(val tile: TileController) extends ManagedTileEntityEnvironment[TileController](tile, "me_controller") with NetworkControl[TileController]
object Provider extends EnvironmentProvider {
override def getEnvironment(stack: ItemStack): Class[_] =
if (AEUtil.isController(stack))
classOf[Environment]
else null
}
}

View File

@ -0,0 +1,18 @@
package li.cil.oc.integration.thaumicenergistics
import li.cil.oc.api.Driver
import li.cil.oc.integration.Mod
import li.cil.oc.integration.ModProxy
import li.cil.oc.integration.Mods
object ModThaumicEnergistics extends ModProxy {
override def getMod: Mod = Mods.ThaumicEnergistics
override def initialize(): Unit = {
Driver.add(DriverController)
Driver.add(DriverBlockInterface)
Driver.add(DriverController.Provider)
Driver.add(DriverBlockInterface.Provider)
}
}

View File

@ -0,0 +1,23 @@
package li.cil.oc.integration.thaumicenergistics
import appeng.api.networking.security.IActionHost
import appeng.me.helpers.IGridProxyable
import li.cil.oc.api.machine.Arguments
import li.cil.oc.api.machine.Callback
import li.cil.oc.api.machine.Context
import li.cil.oc.util.ResultWrapper._
import net.minecraft.tileentity.TileEntity
import thaumicenergistics.api.IThEEssentiaGas
import scala.collection.convert.WrapAsScala._
// Note to self: this class is used by ExtraCells (and potentially others), do not rename / drastically change it.
trait NetworkControl[AETile >: Null <: TileEntity with IGridProxyable with IActionHost] {
def tile: AETile
@Callback(doc = "function():table -- Get a list of the stored essentia in the network.")
def getEssentiaInNetwork(context: Context, args: Arguments): Array[AnyRef] =
result(tile.getProxy.getStorage.getFluidInventory.getStorageList.filter(stack =>
stack.getFluid != null && stack.getFluid.isInstanceOf[IThEEssentiaGas]).
map(ThaumicEnergisticsUtils.getAspect).toArray)
}

View File

@ -0,0 +1,11 @@
package li.cil.oc.integration.thaumicenergistics
import appeng.api.storage.data.IAEFluidStack
object ThaumicEnergisticsUtils {
def getAspect(fluid: IAEFluidStack) = {
val aspect = fluid.getFluidStack.copy()
aspect.amount = (fluid.getStackSize / 128).toInt
aspect
}
}

View File

@ -27,7 +27,7 @@ class UpgradeCrafting(val host: EnvironmentHost with internal.Robot) extends pre
@Callback(doc = """function([count:number]):number -- Tries to craft the specified number of items in the top left area of the inventory.""")
def craft(context: Context, args: Arguments): Array[AnyRef] = {
val count = args.optInteger(0, Int.MaxValue)
val count = args.optInteger(0, 64) max 0 min 64
result(CraftingInventory.craft(count): _*)
}

View File

@ -9,13 +9,20 @@ import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.tileentity.TileEntity
import net.minecraft.util.BlockPos
import net.minecraft.util.EnumFacing
import net.minecraft.world.World
class CompoundBlockDriver(val blocks: driver.Block*) extends driver.Block {
override def createEnvironment(world: World, pos: BlockPos) = {
val list = blocks.map {
// TODO Remove blocks in OC 1.7.
class CompoundBlockDriver(val sidedBlocks: Array[driver.SidedBlock], val blocks: Array[driver.Block]) extends driver.SidedBlock {
override def createEnvironment(world: World, pos: BlockPos, side: EnumFacing) = {
val list = sidedBlocks.map {
driver => Option(driver.createEnvironment(world, pos, side)) match {
case Some(environment) => (driver.getClass.getName, environment)
case _ => null
}
} ++ blocks.map {
driver => Option(driver.createEnvironment(world, pos)) match {
case Some(environment) => (driver, environment)
case Some(environment) => (driver.getClass.getName, environment)
case _ => null
}
} filter (_ != null)
@ -23,10 +30,10 @@ class CompoundBlockDriver(val blocks: driver.Block*) extends driver.Block {
else new CompoundBlockEnvironment(cleanName(tryGetName(world, pos, list.map(_._2))), list: _*)
}
override def worksWith(world: World, pos: BlockPos) = blocks.forall(_.worksWith(world, pos))
override def worksWith(world: World, pos: BlockPos, side: EnumFacing) = sidedBlocks.forall(_.worksWith(world, pos, side)) && blocks.forall(_.worksWith(world, pos))
override def equals(obj: Any) = obj match {
case multi: CompoundBlockDriver if multi.blocks.length == blocks.length => blocks.intersect(multi.blocks).length == blocks.length
case multi: CompoundBlockDriver if multi.sidedBlocks.length == sidedBlocks.length && multi.blocks.length == blocks.length => sidedBlocks.intersect(multi.sidedBlocks).length == sidedBlocks.length && blocks.intersect(multi.blocks).length == blocks.length
case _ => false
}

View File

@ -5,12 +5,12 @@ import java.nio.charset.Charset
import com.google.common.hash.Hashing
import li.cil.oc.OpenComputers
import li.cil.oc.api
import li.cil.oc.api.driver
import li.cil.oc.api.network._
import li.cil.oc.util.ExtendedNBT._
import net.minecraft.nbt.NBTTagCompound
class CompoundBlockEnvironment(val name: String, val environments: (driver.Block, ManagedEnvironment)*) extends ManagedEnvironment {
// TODO Remove block in OC 1.7.
class CompoundBlockEnvironment(val name: String, val environments: (String, ManagedEnvironment)*) extends ManagedEnvironment {
// Block drivers with visibility < network usually won't make much sense,
// but let's play it safe and use the least possible visibility based on
// the drivers we encapsulate.
@ -58,12 +58,11 @@ class CompoundBlockEnvironment(val name: String, val environments: (driver.Block
if (nbt.hasKey("typeHash") && nbt.getLong("typeHash") != typeHash) return
node.load(nbt)
for ((driver, environment) <- environments) {
val name = driver.getClass.getName
if (nbt.hasKey(name)) {
if (nbt.hasKey(driver)) {
try {
environment.load(nbt.getCompoundTag(name))
environment.load(nbt.getCompoundTag(driver))
} catch {
case e: Throwable => OpenComputers.log.warn(s"A block component of type '${environment.getClass.getName}' (provided by driver '$name') threw an error while loading.", e)
case e: Throwable => OpenComputers.log.warn(s"A block component of type '${environment.getClass.getName}' (provided by driver '$driver') threw an error while loading.", e)
}
}
}
@ -73,11 +72,10 @@ class CompoundBlockEnvironment(val name: String, val environments: (driver.Block
nbt.setLong("typeHash", typeHash)
node.save(nbt)
for ((driver, environment) <- environments) {
val name = driver.getClass.getName
try {
nbt.setNewCompoundTag(name, environment.save)
nbt.setNewCompoundTag(driver, environment.save)
} catch {
case e: Throwable => OpenComputers.log.warn(s"A block component of type '${environment.getClass.getName}' (provided by driver '$name') threw an error while saving.", e)
case e: Throwable => OpenComputers.log.warn(s"A block component of type '${environment.getClass.getName}' (provided by driver '$driver') threw an error while saving.", e)
}
}
}

View File

@ -10,10 +10,12 @@ import li.cil.oc.api.driver.InventoryProvider
import li.cil.oc.api.driver.item.HostAware
import li.cil.oc.api.machine.Value
import li.cil.oc.api.network.EnvironmentHost
import li.cil.oc.api.network.ManagedEnvironment
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.inventory.IInventory
import net.minecraft.item.ItemStack
import net.minecraft.util.BlockPos
import net.minecraft.util.EnumFacing
import net.minecraft.world.World
import scala.collection.convert.WrapAsJava._
@ -38,6 +40,8 @@ import scala.math.ScalaNumber
private[oc] object Registry extends api.detail.DriverAPI {
val blocks = mutable.ArrayBuffer.empty[api.driver.Block]
val sidedBlocks = mutable.ArrayBuffer.empty[api.driver.SidedBlock]
val items = mutable.ArrayBuffer.empty[api.driver.Item]
val converters = mutable.ArrayBuffer.empty[api.driver.Converter]
@ -59,9 +63,17 @@ private[oc] object Registry extends api.detail.DriverAPI {
}
}
override def add(driver: api.driver.SidedBlock) {
if (locked) throw new IllegalStateException("Please register all drivers in the init phase.")
if (!sidedBlocks.contains(driver)) {
OpenComputers.log.debug(s"Registering block driver ${driver.getClass.getName}.")
sidedBlocks += driver
}
}
override def add(driver: api.driver.Item) {
if (locked) throw new IllegalStateException("Please register all drivers in the init phase.")
if (!blocks.contains(driver)) {
if (!items.contains(driver)) {
OpenComputers.log.debug(s"Registering item driver ${driver.getClass.getName}.")
items += driver
}
@ -91,9 +103,21 @@ private[oc] object Registry extends api.detail.DriverAPI {
}
}
override def driverFor(world: World, pos: BlockPos) =
blocks.filter(_.worksWith(world, pos)) match {
case drivers if drivers.nonEmpty => new CompoundBlockDriver(drivers: _*)
// TODO Remove in OC 1.7
override def driverFor(world: World, pos: BlockPos) = {
driverFor(world, pos, null) match {
case driver: api.driver.SidedBlock => new api.driver.Block {
override def worksWith(world: World, pos: BlockPos): Boolean = driver.worksWith(world, pos, null)
override def createEnvironment(world: World, pos: BlockPos): ManagedEnvironment = driver.createEnvironment(world, pos, null)
}
case _ => null
}
}
override def driverFor(world: World, pos: BlockPos, side: EnumFacing): api.driver.SidedBlock =
(sidedBlocks.filter(_.worksWith(world, pos, side)), blocks.filter(_.worksWith(world, pos))) match {
case (sidedDrivers, drivers) if sidedDrivers.nonEmpty || drivers.nonEmpty => new CompoundBlockDriver(sidedDrivers.toArray, drivers.toArray)
case _ => null
}

View File

@ -0,0 +1,47 @@
package li.cil.oc.util
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
/**
* @author asie, Vexatos
*/
object ItemColorizer {
/**
* Return whether the specified armor ItemStack has a color.
*/
def hasColor(stack: ItemStack): Boolean = stack.hasTagCompound && stack.getTagCompound.hasKey("display") && stack.getTagCompound.getCompoundTag("display").hasKey("color")
/**
* Return the color for the specified armor ItemStack.
*/
def getColor(stack: ItemStack): Int = {
val tag = stack.getTagCompound
if (tag != null) {
val displayTag = tag.getCompoundTag("display")
if (displayTag == null) -1 else if (displayTag.hasKey("color")) displayTag.getInteger("color") else -1
}
else -1
}
def removeColor(stack: ItemStack) {
val tag = stack.getTagCompound
if (tag != null) {
val displayTag = tag.getCompoundTag("display")
if (displayTag.hasKey("color")) displayTag.removeTag("color")
}
}
def setColor(stack: ItemStack, color: Int) {
var tag = stack.getTagCompound
if (tag == null) {
tag = new NBTTagCompound
stack.setTagCompound(tag)
}
val displayTag = tag.getCompoundTag("display")
if (!tag.hasKey("display")) {
tag.setTag("display", displayTag)
}
displayTag.setInteger("color", color)
}
}