Merge branch 'mfu' of https://github.com/Vexatos/OpenComputers into master-MC1.7.10

This commit is contained in:
Florian Nücke 2017-02-03 22:15:37 +01:00
commit a9615de2f3
12 changed files with 398 additions and 0 deletions

View File

@ -807,6 +807,10 @@ opencomputers {
# Energy consumed when reconfiguring nanomachines.
nanomachinesReconfigure: 5000
# Energy consumed by a MFU per tick while connected.
# Similarly to `wirelessCostPerRange`, this is multiplied with the distance to the bound block.
mfuRelay: 1
}
# The rate at which different blocks accept external power. All of these
@ -1345,6 +1349,9 @@ opencomputers {
# The maximum range between the drone/robot and a villager for a trade to
# be performed by the trading upgrade
tradingRange: 8.0
# Radius the MFU is able to operate in
mfuRange: 3
}
# Settings for mod integration (the mod previously known as OpenComponents).

View File

@ -144,6 +144,7 @@ item.oc.UpgradeHover1.name=Hover Upgrade (Tier 2)
item.oc.UpgradeInventory.name=Inventory Upgrade
item.oc.UpgradeInventoryController.name=Inventory Controller Upgrade
item.oc.UpgradeLeash.name=Leash Upgrade
item.oc.UpgradeMF.name=MFU
item.oc.UpgradeNavigation.name=Navigation Upgrade
item.oc.UpgradePiston.name=Piston Upgrade
item.oc.UpgradeSign.name=Sign I/O Upgrade
@ -370,6 +371,9 @@ oc:tooltip.UpgradeGenerator=Can be used to generate energy from fuel on the go.
oc:tooltip.UpgradeHover=This upgrade allows robots to fly higher above the ground without having to climb walls.[nl] Maximum height: §f%s§7
oc:tooltip.UpgradeInventory=This upgrade provides inventory space to a robot or drone. Without one of these, they will not be able to store items internally.
oc:tooltip.UpgradeInventoryController=This upgrade allows robots and drones more control in how it interacts with external inventories, and allows robots to swap their equipped tool with an item in their inventory.
oc:tooltip.UpgradeMF=TODO really, do this
oc:tooltip.UpgradeMF.Linked=§fConnection established§7
oc:tooltip.UpgradeMF.Unlinked=§fNo connection§7
oc:tooltip.UpgradeLeash=Allows some devices, such as drones, to bind Isaa- excuse me... *chatter* My apologies. I'm just being told this is actually used to put animals on a leash. Multiple animals, even. Odd.
oc:tooltip.UpgradeNavigation=Can be used to determine the position and orientation of a device. The position is relative to the center of the map that was used to craft this upgrade.
oc:tooltip.UpgradePiston=This upgrade is very pushy. It allows moving blocks, similar to when using a piston. It does §lnot§7 move entities, however.

View File

@ -295,6 +295,11 @@ inventoryControllerUpgrade {
[dropper, "oc:circuitChip2", craftingPiston]
[ingotGold, "oc:materialCircuitBoardPrinted", ingotGold]]
}
mfu {
input: [["oc:chamelium", gemLapis, "oc:chamelium"]
["oc:linkedCard", "oc:adapter", "oc:linkedCard"]
["oc:chamelium", gemLapis, "oc:chamelium"]]
}
leashUpgrade {
input: [[ingotIron, lead, ingotIron]
[lead, "oc:materialCU", lead]

View File

@ -118,6 +118,7 @@ object Constants {
final val LinkedCard = "linkedCard"
final val LootDisk = "lootDisk"
final val LuaBios = "luaBios"
final val MFU = "mfu"
final val Manual = "manual"
final val MicrocontrollerCaseCreative = "microcontrollerCaseCreative"
final val MicrocontrollerCaseTier1 = "microcontrollerCase1"
@ -174,6 +175,7 @@ object Constants {
object DeviceInfo {
final val DefaultVendor = "MightyPirates GmbH & Co. KG"
final val Scummtech = "Scummtech, Inc."
}

View File

@ -170,6 +170,8 @@ object Localization {
def PrintLightValue(level: Int) = localizeImmediately("tooltip.Print.LightValue", level.toString)
def PrintRedstoneLevel(level: Int) = localizeImmediately("tooltip.Print.RedstoneLevel", level.toString)
def MFULinked(isLinked: Boolean) = localizeImmediately(if (isLinked) "tooltip.UpgradeMF.Linked" else "tooltip.UpgradeMF.Unlinked")
}
}

View File

@ -222,6 +222,7 @@ class Settings(val config: Config) {
val transposerCost = config.getDouble("power.cost.transposer") max 0
val nanomachineCost = config.getDouble("power.cost.nanomachineInput") max 0
val nanomachineReconfigureCost = config.getDouble("power.cost.nanomachinesReconfigure") max 0
val mfuCost = config.getDouble("power.cost.mfuRelay") max 0
// power.rate
val accessPointRate = config.getDouble("power.rate.accessPoint") max 0
@ -357,6 +358,7 @@ class Settings(val config: Config) {
val serverRackSwitchTier = (config.getInt("misc.serverRackSwitchTier") - 1) max Tier.None min Tier.Three
val redstoneDelay = config.getDouble("misc.redstoneDelay") max 0
val tradingRange = config.getDouble("misc.tradingRange") max 0
val mfuRange = config.getInt("misc.mfuRange") max 0 min 128
// ----------------------------------------------------------------------- //
// nanomachines

View File

@ -0,0 +1,71 @@
package li.cil.oc.common.event
import cpw.mods.fml.common.eventhandler.SubscribeEvent
import li.cil.oc.common.EventHandler
import li.cil.oc.util.BlockPosition
import net.minecraft.entity.Entity
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.world.{IWorldAccess, World}
import net.minecraftforge.event.world.WorldEvent
import scala.collection.mutable
/**
* @author Vexatos
*/
object BlockChangeHandler {
def addListener(listener: ChangeListener, coord: BlockPosition) = {
EventHandler.scheduleServer(() => changeListeners.put(listener, coord))
}
def removeListener(listener: ChangeListener) = {
EventHandler.scheduleServer(() => changeListeners.remove(listener))
}
private val changeListeners = mutable.WeakHashMap.empty[ChangeListener, BlockPosition]
@SubscribeEvent
def onWorldLoad(e: WorldEvent.Load) {
e.world.addWorldAccess(new Listener(e.world))
}
trait ChangeListener {
def onBlockChanged()
}
private class Listener(world: World) extends IWorldAccess {
override def markBlockForUpdate(x: Int, y: Int, z: Int): Unit = {
val current = BlockPosition(x, y, z, world)
for ((listener, coord) <- changeListeners) if (coord.equals(current)) {
listener.onBlockChanged()
}
}
override def playRecord(recordName: String, x: Int, y: Int, z: Int) {}
override def playAuxSFX(player: EntityPlayer, sfxType: Int, x: Int, y: Int, z: Int, data: Int) {}
override def onEntityDestroy(entity: Entity) {}
override def destroyBlockPartially(breakerId: Int, x: Int, y: Int, z: Int, progress: Int) {}
override def markBlockForRenderUpdate(x: Int, y: Int, z: Int) {}
override def spawnParticle(particleType: String, x: Double, y: Double, z: Double, velX: Double, velY: Double, velZ: Double) {}
override def playSound(soundName: String, x: Double, y: Double, z: Double, volume: Float, pitch: Float) {}
override def broadcastSound(soundID: Int, x: Int, y: Int, z: Int, data: Int) {}
override def playSoundToNearExcept(player: EntityPlayer, soundName: String, x: Double, y: Double, z: Double, volume: Float, pitch: Float) {}
override def markBlockRangeForRenderUpdate(x1: Int, y1: Int, z1: Int, x2: Int, y2: Int, z2: Int) {}
override def onEntityCreate(entity: Entity) {}
override def onStaticEntitiesChanged() {}
}
}

View File

@ -538,6 +538,7 @@ object Items extends ItemAPI {
Recipes.addSubItem(new item.DiskDriveMountable(multi), Constants.ItemName.DiskDriveMountable, "oc:diskDriveMountable")
Recipes.addSubItem(new item.UpgradeTrading(multi), Constants.ItemName.TradingUpgrade, "oc:tradingUpgrade")
registerItem(new item.DiamondChip(multi), Constants.ItemName.DiamondChip)
Recipes.addSubItem(new item.UpgradeMF(multi), Constants.ItemName.MFU, "oc:mfu")
// Register aliases.
for ((k, v) <- aliases) {

View File

@ -0,0 +1,31 @@
package li.cil.oc.common.item
import java.util
import li.cil.oc.util.BlockPosition
import li.cil.oc.{Localization, Settings}
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
class UpgradeMF(val parent: Delegator) extends traits.Delegate with traits.ItemTier {
override def onItemUseFirst(stack: ItemStack, player: EntityPlayer, position: BlockPosition, side: Int, hitX: Float, hitY: Float, hitZ: Float): Boolean = {
if (!player.worldObj.isRemote && player.isSneaking) {
if (!stack.hasTagCompound) {
stack.setTagCompound(new NBTTagCompound())
}
val data = stack.getTagCompound
data.setIntArray(Settings.namespace + "coord", Array(position.x, position.y, position.z, player.worldObj.provider.dimensionId, side))
return true
}
super.onItemUseFirst(stack, player, position, side, hitX, hitY, hitZ)
}
override protected def tooltipExtended(stack: ItemStack, tooltip: util.List[String]) {
tooltip.add(Localization.Tooltip.MFULinked(stack.getTagCompound match {
case data: NBTTagCompound => data.hasKey(Settings.namespace +"coord")
case _ => false
}))
}
}

View File

@ -0,0 +1,52 @@
package li.cil.oc.integration.opencomputers
import li.cil.oc.api.driver.EnvironmentProvider
import li.cil.oc.api.driver.item.HostAware
import li.cil.oc.api.network.{EnvironmentHost, ManagedEnvironment}
import li.cil.oc.common.{Slot, Tier}
import li.cil.oc.server.component
import li.cil.oc.util.BlockPosition
import li.cil.oc.{Constants, Settings, api}
import net.minecraft.item.ItemStack
import net.minecraftforge.common.DimensionManager
import net.minecraftforge.common.util.ForgeDirection
/**
*
* @author Vexatos
*/
object DriverUpgradeMF extends Item with HostAware {
override def worksWith(stack: ItemStack): Boolean = isOneOf(stack,
api.Items.get(Constants.ItemName.MFU))
override def worksWith(stack: ItemStack, host: Class[_ <: EnvironmentHost]): Boolean =
worksWith(stack) && isAdapter(host)
override def slot(stack: ItemStack): String = Slot.Upgrade
override def tier(stack: ItemStack) = Tier.Three
override def createEnvironment(stack: ItemStack, host: EnvironmentHost): ManagedEnvironment = {
if (host.world != null && !host.world.isRemote) {
if (stack.hasTagCompound) {
stack.getTagCompound.getIntArray(Settings.namespace + "coord") match {
case Array(x, y, z, dim, side) =>
Option(DimensionManager.getWorld(dim)) match {
case Some(world) => return new component.UpgradeMF(host, BlockPosition(x, y, z, world), ForgeDirection.getOrientation(side))
case _ => // Invalid dimension ID
}
case _ => // Invalid tag
}
}
}
null
}
object Provider extends EnvironmentProvider {
override def getEnvironment(stack: ItemStack): Class[_] =
if (worksWith(stack))
classOf[component.UpgradeMF]
else null
}
}

View File

@ -98,6 +98,7 @@ object ModOpenComputers extends ModProxy {
MinecraftForge.EVENT_BUS.register(Analyzer)
MinecraftForge.EVENT_BUS.register(AngelUpgradeHandler)
MinecraftForge.EVENT_BUS.register(BlockChangeHandler)
MinecraftForge.EVENT_BUS.register(ChunkloaderUpgradeHandler)
MinecraftForge.EVENT_BUS.register(EventHandler)
MinecraftForge.EVENT_BUS.register(ExperienceUpgradeHandler)
@ -166,6 +167,7 @@ object ModOpenComputers extends ModProxy {
api.Driver.add(DriverUpgradeTankController)
api.Driver.add(DriverUpgradeTractorBeam)
api.Driver.add(DriverUpgradeTrading)
api.Driver.add(DriverUpgradeMF)
api.Driver.add(DriverAPU.Provider)
api.Driver.add(DriverDataCard.Provider)
@ -193,6 +195,7 @@ object ModOpenComputers extends ModProxy {
api.Driver.add(DriverUpgradeSign.Provider)
api.Driver.add(DriverUpgradeTankController.Provider)
api.Driver.add(DriverUpgradeTractorBeam.Provider)
api.Driver.add(DriverUpgradeMF.Provider)
api.Driver.add(EnvironmentProviderBlocks)

View File

@ -0,0 +1,218 @@
package li.cil.oc.server.component
import java.util
import li.cil.oc.Constants
import li.cil.oc.api.driver.DeviceInfo
import li.cil.oc.api.driver.DeviceInfo.DeviceAttribute
import li.cil.oc.api.driver.DeviceInfo.DeviceClass
import li.cil.oc.api.network._
import li.cil.oc.api.prefab
import li.cil.oc.common.event.BlockChangeHandler
import li.cil.oc.common.event.BlockChangeHandler.ChangeListener
import li.cil.oc.server.network
import li.cil.oc.util.BlockPosition
import li.cil.oc.util.ExtendedWorld._
import li.cil.oc.Settings
import li.cil.oc.api
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.tileentity.TileEntity
import net.minecraft.util.Vec3
import net.minecraftforge.common.util.ForgeDirection
import scala.collection.convert.WrapAsJava._
/**
* Mostly stolen from li.cil.oc.common.tileentity.Adapter
*
* @author Sangar, Vexatos
*/
class UpgradeMF(val host: EnvironmentHost, val coord: BlockPosition, val dir: ForgeDirection) extends prefab.ManagedEnvironment with ChangeListener with DeviceInfo {
override val node = api.Network.newNode(this, Visibility.None).
withConnector().
create()
private var otherEnv: Option[api.network.Environment] = None
private var otherDrv: Option[(ManagedEnvironment, api.driver.SidedBlock)] = None
private var blockData: Option[BlockData] = None
override val canUpdate = true
private final lazy val deviceInfo = Map(
DeviceAttribute.Class -> DeviceClass.Bus,
DeviceAttribute.Description -> "Remote Adapter",
DeviceAttribute.Vendor -> Constants.DeviceInfo.Scummtech,
DeviceAttribute.Product -> "ERR NAME NOT FOUND"
)
override def getDeviceInfo: util.Map[String, String] = deviceInfo
private def otherNode(tile: TileEntity, f: (Node) => Unit) {
network.Network.getNetworkNode(tile, dir) match {
case Some(otherNode) => f(otherNode)
case _ => // Nothing to do here
}
}
private def updateBoundState() {
if (node != null && node.network != null && coord.world.exists(_.provider.dimensionId == host.world.provider.dimensionId)
&& coord.toVec3.distanceTo(Vec3.createVectorHelper(host.xPosition, host.yPosition, host.zPosition)) <= Settings.get.mfuRange) {
host.world.getTileEntity(coord) match {
case env: TileEntity with api.network.Environment =>
otherEnv match {
case Some(environment: TileEntity) =>
otherNode(environment, node.disconnect)
otherEnv = None
case _ => // Nothing to do here.
}
otherEnv = Some(env)
// Remove any driver that might be there.
otherDrv match {
case Some((environment, driver)) =>
node.disconnect(environment.node)
environment.save(blockData.get.data)
Option(environment.node).foreach(_.remove())
otherDrv = None
case _ => // Nothing to do here.
}
otherNode(env, node.connect)
case _ =>
// Remove any environment that might have been there.
otherEnv match {
case Some(environment: TileEntity) =>
otherNode(environment, node.disconnect)
otherEnv = None
case _ => // Nothing to do here.
}
val (world, x, y, z) = (coord.world.get, coord.x, coord.y, coord.z)
Option(api.Driver.driverFor(world, coord.x, coord.y, coord.z, dir)) match {
case Some(newDriver) =>
otherDrv match {
case Some((oldEnvironment, driver)) =>
if (newDriver != driver) {
// This is... odd. Maybe moved by some other mod? First, clean up.
otherDrv = None
blockData = None
node.disconnect(oldEnvironment.node)
// Then rebuild - if we have something.
val environment = newDriver.createEnvironment(world, x, y, z, dir)
if (environment != null) {
otherDrv = Some((environment, newDriver))
blockData = Some(new BlockData(environment.getClass.getName, new NBTTagCompound()))
node.connect(environment.node)
}
} // else: the more things change, the more they stay the same.
case _ =>
// A challenger appears. Maybe.
val environment = newDriver.createEnvironment(world, x, y, z, dir)
if (environment != null) {
otherDrv = Some((environment, newDriver))
blockData match {
case Some(data) if data.name == environment.getClass.getName =>
environment.load(data.data)
case _ =>
}
blockData = Some(new BlockData(environment.getClass.getName, new NBTTagCompound()))
node.connect(environment.node)
}
}
case _ => otherDrv match {
case Some((environment, driver)) =>
// We had something there, but it's gone now...
node.disconnect(environment.node)
environment.save(blockData.get.data)
Option(environment.node).foreach(_.remove())
otherDrv = None
case _ => // Nothing before, nothing now.
}
}
}
}
}
private def disconnect() {
otherEnv match {
case Some(environment: TileEntity) =>
otherNode(environment, node.disconnect)
otherEnv = None
case _ => // Nothing to do here.
}
otherDrv match {
case Some((environment, driver)) =>
node.disconnect(environment.node)
environment.save(blockData.get.data)
Option(environment.node).foreach(_.remove())
otherDrv = None
case _ => // Nothing to do here.
}
}
override def onBlockChanged() = updateBoundState()
override def update() {
super.update()
otherDrv match {
case Some((env, drv)) if env.canUpdate => env.update()
case _ => // No driver
}
if (host.world.getTotalWorldTime % Settings.get.tickFrequency == 0) {
if (!node.tryChangeBuffer(-Settings.get.mfuCost * Settings.get.tickFrequency
* coord.toVec3.distanceTo(Vec3.createVectorHelper(host.xPosition, host.yPosition, host.zPosition)))) {
disconnect()
}
}
}
override def onConnect(node: Node) {
super.onConnect(node)
if (node == this.node) {
// Not checking for range yet because host may be a moving adapter, who knows?
BlockChangeHandler.addListener(this, coord)
updateBoundState()
}
}
override def onDisconnect(node: Node) {
super.onDisconnect(node)
otherEnv match {
case Some(env: TileEntity) => otherNode(env, (otherNode) => if (node == otherNode) otherEnv = None)
case _ => // No environment
}
otherDrv match {
case Some((env, drv)) if node == env.node => otherDrv = None
case _ => // No driver
}
if (node == this.node) {
BlockChangeHandler.removeListener(this)
}
}
override def load(nbt: NBTTagCompound) {
super.load(nbt)
Option(nbt.getCompoundTag(Settings.namespace + "adapter.block")) match {
case Some(blockNbt: NBTTagCompound) =>
if (blockNbt.hasKey("name") && blockNbt.hasKey("data")) {
blockData = Some(new BlockData(blockNbt.getString("name"), blockNbt.getCompoundTag("data")))
}
case _ => // Invalid tag
}
}
override def save(nbt: NBTTagCompound) {
super.save(nbt)
val blockNbt = new NBTTagCompound()
blockData.foreach({ data =>
otherDrv.foreach(_._1.save(data.data))
blockNbt.setString("name", data.name)
blockNbt.setTag("data", data.data)
})
nbt.setTag(Settings.namespace + "adapter.block", blockNbt)
}
// ----------------------------------------------------------------------- //
private class BlockData(val name: String, val data: NBTTagCompound)
}