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

Conflicts:
	src/main/scala/li/cil/oc/common/event/NanomachinesHandler.scala
	src/main/scala/li/cil/oc/common/nanomachines/provider/DisintegrationProvider.scala
	src/main/scala/li/cil/oc/common/nanomachines/provider/MagnetProvider.scala
	src/main/scala/li/cil/oc/common/nanomachines/provider/ParticleProvider.scala
This commit is contained in:
Florian Nücke 2015-09-18 14:52:25 +02:00
commit 2d56a45b7d
24 changed files with 352 additions and 118 deletions

View File

@ -12,7 +12,7 @@ import li.cil.oc.api.detail.*;
*/ */
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.5.5"; public static final String VERSION = "5.6.0";
public static DriverAPI driver = null; public static DriverAPI driver = null;
public static FileSystemAPI fileSystem = null; public static FileSystemAPI fileSystem = null;

View File

@ -40,8 +40,10 @@ public interface Behavior {
* Called when this behavior becomes inactive. * Called when this behavior becomes inactive.
* <p/> * <p/>
* Use this to remove permanent effects. * Use this to remove permanent effects.
*
* @param reason the reason the behavior is being disabled.
*/ */
void onDisable(); void onDisable(DisableReason reason);
/** /**
* Called each tick while this behavior is active. * Called each tick while this behavior is active.

View File

@ -0,0 +1,23 @@
package li.cil.oc.api.nanomachines;
/**
* Enum with reasons why a nanomachine behavior was disabled.
* <p/>
* This allows some more context specific behavior in a more stable fashion.
*/
public enum DisableReason {
/**
* This covers things like players logging off or the controller being reset.
*/
Default,
/**
* Input state changed, leading to a behavior being disabled.
*/
InputChanged,
/**
* System has run out of energy and is powering down.
*/
OutOfEnergy
}

View File

@ -0,0 +1,52 @@
package li.cil.oc.api.prefab;
import li.cil.oc.api.nanomachines.Behavior;
import li.cil.oc.api.nanomachines.DisableReason;
import net.minecraft.entity.player.EntityPlayer;
/**
* Base class for behaviors, mostly useful to have less cluttered classes when
* you only need one or two of the methods in the interface.
* <p/>
* This implementation will also store the player the behavior was created for.
*/
public abstract class AbstractBehavior implements Behavior {
/**
* The player this behavior was created for.
*/
public final EntityPlayer player;
/**
* Pass along the player the behavior was created for here to have it stored
* for later use.
*
* @param player the player the behavior was created for.
*/
protected AbstractBehavior(EntityPlayer player) {
this.player = player;
}
/**
* Use this if you do not need the player reference in your implementation.
*/
protected AbstractBehavior() {
this(null);
}
@Override
public String getNameHint() {
return null;
}
@Override
public void onEnable() {
}
@Override
public void onDisable(DisableReason reason) {
}
@Override
public void update() {
}
}

View File

@ -0,0 +1,74 @@
package li.cil.oc.api.prefab;
import li.cil.oc.api.nanomachines.Behavior;
import li.cil.oc.api.nanomachines.BehaviorProvider;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
/**
* Example base implementation of nanomachine behavior provider.
* <p/>
* This class takes care of handling the unique identifier used to tell
* if a behavior is its own when loading from NBT.
*/
public abstract class AbstractProvider implements BehaviorProvider {
/**
* Unique identifier used to tell if a behavior is ours when asked to load it.
*/
protected final String id;
/**
* For the ID passed in here, it is suggested to use a one-time generated
* UUID that is hard-coded into your provider implementation. Take care to
* use a different one for each provider you create!
*
* @param id the unique identifier for this provider.
*/
protected AbstractProvider(String id) {
if (id == null) throw new NullPointerException("id must not be null");
this.id = id;
}
/**
* Called when saving a behavior created using this behavior to NBT.
* <p/>
* The ID will already have been written, don't overwrite it. Store
* any additional data you need to restore the behavior here, if any.
*
* @param behavior the behavior to persist.
* @param nbt the NBT tag to persist it to.
*/
protected void writeBehaviorToNBT(Behavior behavior, NBTTagCompound nbt) {
}
/**
* Called when loading a behavior from NBT.
* <p/>
* Use the data written in {@link #writeBehaviorToNBT} to restore the behavior
* to its previous state, then return it.
*
* @param player the player to restore the behavior for.
* @param nbt the NBT tag to load restore the behavior from.
* @return the restored behavior.
*/
protected abstract Behavior readBehaviorFromNBT(EntityPlayer player, NBTTagCompound nbt);
// ----------------------------------------------------------------------- //
@Override
public NBTTagCompound writeToNBT(Behavior behavior) {
NBTTagCompound nbt = new NBTTagCompound();
nbt.setString("provider", id);
writeBehaviorToNBT(behavior, nbt);
return nbt;
}
@Override
public Behavior readFromNBT(EntityPlayer player, NBTTagCompound nbt) {
if (id.equals(nbt.getString("provider"))) {
return readBehaviorFromNBT(player, nbt);
} else {
return null;
}
}
}

View File

@ -1023,16 +1023,40 @@ opencomputers {
# Radius in blocks of the disintegration behavior for each active input. # Radius in blocks of the disintegration behavior for each active input.
disintegrationRange: 1 disintegrationRange: 1
# Blacklisted potions, i.e. potions that won't be used for the potion # Whitelisted potions, i.e. potions that will be used for the potion
# behaviors nanomachines may trigger. This can contain strings or numbers. # behaviors nanomachines may trigger. This can contain strings or numbers.
# In the case of strings, it has to be the internal name of the potion, # In the case of strings, it has to be the internal name of the potion,
# in case of a number it has to be the potion ID. # in case of a number it has to be the potion ID. Add any potion effects
potionBlacklist: [ # to make use of here, since they will all be disabled by default.
"potion.heal", potionWhitelist: [
"potion.regeneration", "potion.moveSpeed",
"potion.invisibility", "potion.digSpeed",
"potion.saturation" "potion.damageBoost",
"potion.jump",
"potion.resistance",
"potion.fireResistance",
"potion.waterBreathing",
"potion.nightVision",
"potion.absorption",
"potion.blindness",
"potion.confusion",
"potion.digSlowDown",
"potion.harm",
"potion.hunger",
"potion.moveSlowdown",
"potion.poison",
"potion.weakness",
"potion.wither"
] ]
# How much damage the hungry behavior should deal to the player when the
# nanomachine controller runs out of energy.
hungryDamage: 5
# How much energy the hungry behavior should restore when damaging the
# player.
hungryEnergyRestored: 50
} }
# 3D printer related stuff. # 3D printer related stuff.

View File

@ -451,6 +451,15 @@ achievement.oc.transistor.desc=Create a Transistor to get started. Then listen t
achievement.oc.wirelessNetworkCard=Signals achievement.oc.wirelessNetworkCard=Signals
achievement.oc.wirelessNetworkCard.desc=Time to go where no packet has gone before. achievement.oc.wirelessNetworkCard.desc=Time to go where no packet has gone before.
# Death messages. Note that the number of entries here must match the number
# set in the actual damage source in code.
death.attack.oc.nanomachinesOverload.1=%s got too greedy.
death.attack.oc.nanomachinesOverload.2=%s had a nervous breakdown.
death.attack.oc.nanomachinesOverload.3=%s's nanomachines went out of control.
death.attack.oc.nanomachinesHungry.1=%s was eaten by nanomachines.
death.attack.oc.nanomachinesHungry.2=%s didn't keep their nanomachines fed.
death.attack.oc.nanomachinesHungry.3=%s has been digested.
# NEI Integration # NEI Integration
nei.options.inventory.oredict=Show OreDictionary names nei.options.inventory.oredict=Show OreDictionary names
nei.options.inventory.oredict.true=True nei.options.inventory.oredict.true=True

View File

@ -361,6 +361,9 @@ class Settings(val config: Config) {
val nanomachineMagnetRange = config.getDouble("nanomachines.magnetRange") max 0 val nanomachineMagnetRange = config.getDouble("nanomachines.magnetRange") max 0
val nanomachineDisintegrationRange = config.getInt("nanomachines.disintegrationRange") max 0 val nanomachineDisintegrationRange = config.getInt("nanomachines.disintegrationRange") max 0
val nanomachinePotionBlacklist = config.getAnyRefList("nanomachines.potionBlacklist") val nanomachinePotionBlacklist = config.getAnyRefList("nanomachines.potionBlacklist")
val nanomachinePotionWhitelist = config.getAnyRefList("nanomachines.potionWhitelist")
val nanomachinesHungryDamage = config.getDouble("nanomachines.hungryDamage").toFloat max 0
val nanomachinesHungryEnergyRestored = config.getDouble("nanomachines.hungryEnergyRestored") max 0
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
// printer // printer

View File

@ -13,7 +13,7 @@ import li.cil.oc.client.renderer.entity.DroneRenderer
import li.cil.oc.client.renderer.tileentity._ import li.cil.oc.client.renderer.tileentity._
import li.cil.oc.common.component.TextBuffer import li.cil.oc.common.component.TextBuffer
import li.cil.oc.common.entity.Drone import li.cil.oc.common.entity.Drone
import li.cil.oc.common.event.NanomachinesEventHandler import li.cil.oc.common.event.NanomachinesHandler
import li.cil.oc.common.init.Items import li.cil.oc.common.init.Items
import li.cil.oc.common.item.traits.Delegate import li.cil.oc.common.item.traits.Delegate
import li.cil.oc.common.tileentity import li.cil.oc.common.tileentity
@ -81,7 +81,7 @@ private[oc] class Proxy extends CommonProxy {
ClientRegistry.registerKeyBinding(KeyBindings.clipboardPaste) ClientRegistry.registerKeyBinding(KeyBindings.clipboardPaste)
MinecraftForge.EVENT_BUS.register(HighlightRenderer) MinecraftForge.EVENT_BUS.register(HighlightRenderer)
MinecraftForge.EVENT_BUS.register(NanomachinesEventHandler.Client) MinecraftForge.EVENT_BUS.register(NanomachinesHandler.Client)
MinecraftForge.EVENT_BUS.register(PetRenderer) MinecraftForge.EVENT_BUS.register(PetRenderer)
MinecraftForge.EVENT_BUS.register(ServerRack) MinecraftForge.EVENT_BUS.register(ServerRack)
MinecraftForge.EVENT_BUS.register(Sound) MinecraftForge.EVENT_BUS.register(Sound)

View File

@ -8,6 +8,7 @@ import li.cil.oc.Settings
import li.cil.oc.api import li.cil.oc.api
import li.cil.oc.api.nanomachines.Controller import li.cil.oc.api.nanomachines.Controller
import li.cil.oc.client.Textures import li.cil.oc.client.Textures
import li.cil.oc.common.EventHandler
import li.cil.oc.common.nanomachines.ControllerImpl import li.cil.oc.common.nanomachines.ControllerImpl
import net.minecraft.client.Minecraft import net.minecraft.client.Minecraft
import net.minecraft.client.gui.ScaledResolution import net.minecraft.client.gui.ScaledResolution
@ -19,8 +20,9 @@ import net.minecraftforge.client.event.RenderGameOverlayEvent
import net.minecraftforge.event.entity.living.LivingEvent import net.minecraftforge.event.entity.living.LivingEvent
import net.minecraftforge.event.entity.player.PlayerEvent import net.minecraftforge.event.entity.player.PlayerEvent
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedOutEvent
object NanomachinesEventHandler { object NanomachinesHandler {
object Client { object Client {
@SubscribeEvent @SubscribeEvent
@ -141,6 +143,16 @@ object NanomachinesEventHandler {
} }
} }
} }
@SubscribeEvent
def onPlayerDisconnect(e: PlayerLoggedOutEvent): Unit = {
api.Nanomachines.getController(e.player) match {
case controller: ControllerImpl =>
// Wait a tick because saving is done after this event.
EventHandler.schedule(() => api.Nanomachines.uninstallController(e.player))
case _ => // Not a player with nanomachines.
}
}
} }
} }

View File

@ -3,10 +3,13 @@ package li.cil.oc.common.item
import li.cil.oc.api import li.cil.oc.api
import net.minecraft.entity.player.EntityPlayer import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.EnumAction import net.minecraft.item.EnumAction
import net.minecraft.item.EnumRarity
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.world.World import net.minecraft.world.World
class Nanomachines(val parent: Delegator) extends traits.Delegate { class Nanomachines(val parent: Delegator) extends traits.Delegate {
override def rarity(stack: ItemStack): EnumRarity = EnumRarity.UNCOMMON
override def onItemRightClick(stack: ItemStack, world: World, player: EntityPlayer): ItemStack = { override def onItemRightClick(stack: ItemStack, world: World, player: EntityPlayer): ItemStack = {
if (!api.Nanomachines.hasController(player)) { if (!api.Nanomachines.hasController(player)) {
player.setItemInUse(stack, getMaxItemUseDuration(stack)) player.setItemInUse(stack, getMaxItemUseDuration(stack))

View File

@ -9,8 +9,10 @@ import li.cil.oc.Settings
import li.cil.oc.api import li.cil.oc.api
import li.cil.oc.api.nanomachines.Behavior import li.cil.oc.api.nanomachines.Behavior
import li.cil.oc.api.nanomachines.Controller import li.cil.oc.api.nanomachines.Controller
import li.cil.oc.api.nanomachines.DisableReason
import li.cil.oc.api.network.Packet import li.cil.oc.api.network.Packet
import li.cil.oc.api.network.WirelessEndpoint import li.cil.oc.api.network.WirelessEndpoint
import li.cil.oc.integration.util.DamageSourceWithRandomCause
import li.cil.oc.server.PacketSender import li.cil.oc.server.PacketSender
import li.cil.oc.util.BlockPosition import li.cil.oc.util.BlockPosition
import li.cil.oc.util.ExtendedNBT._ import li.cil.oc.util.ExtendedNBT._
@ -33,6 +35,10 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE
final val MaxSenderDistance = 2f final val MaxSenderDistance = 2f
final val FullSyncInterval = 20 * 60 final val FullSyncInterval = 20 * 60
final val OverloadDamage = new DamageSourceWithRandomCause("oc.nanomachinesOverload", 3).
setDamageBypassesArmor().
setDamageIsAbsolute()
var uuid = UUID.randomUUID.toString var uuid = UUID.randomUUID.toString
var responsePort = 0 var responsePort = 0
var storedEnergy = Settings.get.bufferNanomachines * 0.25 var storedEnergy = Settings.get.bufferNanomachines * 0.25
@ -52,7 +58,7 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE
override def z: Int = BlockPosition(player).z override def z: Int = BlockPosition(player).z
override def receivePacket(packet: Packet, sender: WirelessEndpoint): Unit = { override def receivePacket(packet: Packet, sender: WirelessEndpoint): Unit = {
if (getLocalBuffer > 0) { if (getLocalBuffer > 0 && !player.isDead) {
val (dx, dy, dz) = ((sender.x + 0.5) - player.posX, (sender.y + 0.5) - player.posY, (sender.z + 0.5) - player.posZ) val (dx, dy, dz) = ((sender.x + 0.5) - player.posX, (sender.y + 0.5) - player.posY, (sender.z + 0.5) - player.posZ)
val dSquared = dx * dx + dy * dy + dz * dz val dSquared = dx * dx + dy * dy + dz * dz
if (dSquared < MaxSenderDistance * MaxSenderDistance) packet.data.headOption match { if (dSquared < MaxSenderDistance * MaxSenderDistance) packet.data.headOption match {
@ -155,7 +161,7 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE
} }
override def getActiveBehaviors: lang.Iterable[Behavior] = configuration.synchronized { override def getActiveBehaviors: lang.Iterable[Behavior] = configuration.synchronized {
cleanActiveBehaviors() cleanActiveBehaviors(DisableReason.InputChanged)
activeBehaviors activeBehaviors
} }
@ -180,6 +186,10 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
def update(): Unit = { def update(): Unit = {
if (player.isDead) {
return
}
if (isServer) { if (isServer) {
api.Network.updateWirelessNetwork(this) api.Network.updateWirelessNetwork(this)
} }
@ -189,12 +199,15 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE
return return
} }
val hasPower = getLocalBuffer > 0 || Settings.get.ignorePower var hasPower = getLocalBuffer > 0 || Settings.get.ignorePower
lazy val active = getActiveBehaviors.toIterable // Wrap once. lazy val active = getActiveBehaviors.toIterable // Wrap once.
lazy val activeInputs = configuration.triggers.count(_.isActive) lazy val activeInputs = configuration.triggers.count(_.isActive)
if (hasPower != hadPower) { if (hasPower != hadPower) {
if (!hasPower) active.foreach(_.onDisable()) if (!hasPower) {
active.foreach(_.onDisable(DisableReason.OutOfEnergy)) // This may change our energy buffer.
hasPower = getLocalBuffer > 0 || Settings.get.ignorePower
}
else active.foreach(_.onEnable()) else active.foreach(_.onEnable())
} }
@ -209,8 +222,7 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE
val overload = activeInputs - getSafeInputCount val overload = activeInputs - getSafeInputCount
if (!player.capabilities.isCreativeMode && overload > 0 && player.getEntityWorld.getTotalWorldTime % 20 == 0) { if (!player.capabilities.isCreativeMode && overload > 0 && player.getEntityWorld.getTotalWorldTime % 20 == 0) {
player.setHealth(player.getHealth - overload) player.attackEntityFrom(OverloadDamage, overload)
player.performHurtAnimation()
} }
} }
@ -246,6 +258,7 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE
configuration.triggers(index).isActive = false configuration.triggers(index).isActive = false
activeBehaviorsDirty = true activeBehaviorsDirty = true
} }
cleanActiveBehaviors(DisableReason.Default)
} }
} }
@ -253,7 +266,6 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE
reset() reset()
if (isServer) { if (isServer) {
api.Network.leaveWirelessNetwork(this) api.Network.leaveWirelessNetwork(this)
PacketSender.sendNanomachineConfiguration(player)
} }
} }
@ -280,7 +292,7 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE
private def isServer = !isClient private def isServer = !isClient
private def cleanActiveBehaviors(): Unit = { private def cleanActiveBehaviors(reason: DisableReason): Unit = {
if (activeBehaviorsDirty) { if (activeBehaviorsDirty) {
configuration.synchronized(if (activeBehaviorsDirty) { configuration.synchronized(if (activeBehaviorsDirty) {
val newBehaviors = configuration.behaviors.filter(_.isActive).map(_.behavior) val newBehaviors = configuration.behaviors.filter(_.isActive).map(_.behavior)
@ -290,7 +302,7 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE
activeBehaviors ++= newBehaviors activeBehaviors ++= newBehaviors
activeBehaviorsDirty = false activeBehaviorsDirty = false
addedBehaviors.foreach(_.onEnable()) addedBehaviors.foreach(_.onEnable())
removedBehaviors.foreach(_.onDisable()) removedBehaviors.foreach(_.onDisable(reason))
if (isServer) { if (isServer) {
PacketSender.sendNanomachineInputs(player) PacketSender.sendNanomachineInputs(player)

View File

@ -4,6 +4,7 @@ import li.cil.oc.Settings
import li.cil.oc.api import li.cil.oc.api
import li.cil.oc.api.nanomachines.BehaviorProvider import li.cil.oc.api.nanomachines.BehaviorProvider
import li.cil.oc.api.nanomachines.Controller import li.cil.oc.api.nanomachines.Controller
import li.cil.oc.server.PacketSender
import li.cil.oc.util.PlayerUtils import li.cil.oc.util.PlayerUtils
import net.minecraft.entity.player.EntityPlayer import net.minecraft.entity.player.EntityPlayer
@ -41,9 +42,12 @@ object Nanomachines extends api.detail.NanomachinesAPI {
override def uninstallController(player: EntityPlayer): Unit = { override def uninstallController(player: EntityPlayer): Unit = {
getController(player) match { getController(player) match {
case controller: ControllerImpl => case controller: ControllerImpl =>
PlayerUtils.persistedData(player).removeTag(Settings.namespace + "hasNanomachines")
controllers(player) -= player
controller.dispose() controller.dispose()
controllers(player) -= player
PlayerUtils.persistedData(player).removeTag(Settings.namespace + "hasNanomachines")
if (!player.getEntityWorld.isRemote) {
PacketSender.sendNanomachineConfiguration(player)
}
case _ => // Doesn't have one anyway. case _ => // Doesn't have one anyway.
} }
} }

View File

@ -55,8 +55,8 @@ class NeuralNetwork(controller: ControllerImpl) extends Persistable {
val rng = new Random(controller.player.getEntityWorld.rand.nextInt()) val rng = new Random(controller.player.getEntityWorld.rand.nextInt())
def connect[Sink <: ConnectorNeuron, Source <: Neuron](sinks: Iterable[Sink], sources: mutable.ArrayBuffer[Source]): Unit = { def connect[Sink <: ConnectorNeuron, Source <: Neuron](sinks: Iterable[Sink], sources: mutable.ArrayBuffer[Source]): Unit = {
val sinkPool = sinks.toBuffer // Shuffle sink list to give each entry the same chance.
rng.shuffle(sinkPool) val sinkPool = rng.shuffle(sinks.toBuffer)
for (sink <- sinkPool if sources.nonEmpty) { for (sink <- sinkPool if sources.nonEmpty) {
for (n <- 0 to rng.nextInt(Settings.get.nanomachineMaxInputs) if sources.nonEmpty) { for (n <- 0 to rng.nextInt(Settings.get.nanomachineMaxInputs) if sources.nonEmpty) {
val sourceIndex = rng.nextInt(sources.length) val sourceIndex = rng.nextInt(sources.length)
@ -65,10 +65,6 @@ class NeuralNetwork(controller: ControllerImpl) extends Persistable {
} }
} }
// Shuffle behavior and connector list to give each entry the same chance.
rng.shuffle(connectors)
rng.shuffle(behaviors)
// Connect connectors to triggers, then behaviors to connectors and/or remaining triggers. // Connect connectors to triggers, then behaviors to connectors and/or remaining triggers.
val sourcePool = mutable.ArrayBuffer.fill(Settings.get.nanomachineMaxOutputs)(triggers.map(_.asInstanceOf[Neuron])).flatten val sourcePool = mutable.ArrayBuffer.fill(Settings.get.nanomachineMaxOutputs)(triggers.map(_.asInstanceOf[Neuron])).flatten
connect(connectors, sourcePool) connect(connectors, sourcePool)

View File

@ -1,7 +1,10 @@
package li.cil.oc.common.nanomachines.provider package li.cil.oc.common.nanomachines.provider
import li.cil.oc.Settings
import li.cil.oc.Settings import li.cil.oc.Settings
import li.cil.oc.api import li.cil.oc.api
import li.cil.oc.api.nanomachines.DisableReason
import li.cil.oc.api.prefab.AbstractBehavior
import li.cil.oc.util.BlockPosition import li.cil.oc.util.BlockPosition
import li.cil.oc.util.ExtendedWorld._ import li.cil.oc.util.ExtendedWorld._
import net.minecraft.block.Block import net.minecraft.block.Block
@ -17,20 +20,18 @@ import net.minecraftforge.fml.common.eventhandler.Event
import scala.collection.mutable import scala.collection.mutable
object DisintegrationProvider extends SimpleProvider { object DisintegrationProvider extends ScalaProvider("c4e7e3c2-8069-4fbb-b08e-74b1bddcdfe7") {
final val Id = "c4e7e3c2-8069-4fbb-b08e-74b1bddcdfe7" override def createScalaBehaviors(player: EntityPlayer) = Iterable(new DisintegrationBehavior(player))
override def doCreateBehaviors(player: EntityPlayer) = Iterable(new DisintegrationBehavior(player)) override def readBehaviorFromNBT(player: EntityPlayer, nbt: NBTTagCompound) = new DisintegrationBehavior(player)
override def doReadFromNBT(player: EntityPlayer, nbt: NBTTagCompound) = new DisintegrationBehavior(player) class DisintegrationBehavior(player: EntityPlayer) extends AbstractBehavior(player) {
class DisintegrationBehavior(player: EntityPlayer) extends SimpleBehavior(player) {
var breakingMap = mutable.Map.empty[BlockPosition, SlowBreakInfo] var breakingMap = mutable.Map.empty[BlockPosition, SlowBreakInfo]
var breakingMapNew = mutable.Map.empty[BlockPosition, SlowBreakInfo] var breakingMapNew = mutable.Map.empty[BlockPosition, SlowBreakInfo]
// Note: intentionally not overriding getNameHint. Gotta find this one manually! // Note: intentionally not overriding getNameHint. Gotta find this one manually!
override def onDisable(): Unit = { override def onDisable(reason: DisableReason): Unit = {
val world = player.getEntityWorld val world = player.getEntityWorld
for (pos <- breakingMap.keys) { for (pos <- breakingMap.keys) {
world.destroyBlockInWorldPartially(pos.hashCode(), pos, -1) world.destroyBlockInWorldPartially(pos.hashCode(), pos, -1)

View File

@ -0,0 +1,32 @@
package li.cil.oc.common.nanomachines.provider
import li.cil.oc.Settings
import li.cil.oc.api
import li.cil.oc.api.nanomachines.Behavior
import li.cil.oc.api.nanomachines.DisableReason
import li.cil.oc.api.prefab.AbstractBehavior
import li.cil.oc.integration.util.DamageSourceWithRandomCause
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.nbt.NBTTagCompound
object HungryProvider extends ScalaProvider("") {
final val FillCount = 10 // Create a bunch of these to have a higher chance of one being picked / available.
final val HungryDamage = new DamageSourceWithRandomCause("oc.nanomachinesHungry", 3).
setDamageBypassesArmor().
setDamageIsAbsolute()
override def createScalaBehaviors(player: EntityPlayer): Iterable[Behavior] = Iterable.fill(FillCount)(new HungryBehavior(player))
override protected def readBehaviorFromNBT(player: EntityPlayer, nbt: NBTTagCompound): Behavior = new HungryBehavior(player)
class HungryBehavior(player: EntityPlayer) extends AbstractBehavior(player) {
override def onDisable(reason: DisableReason): Unit = {
if (reason == DisableReason.OutOfEnergy) {
player.attackEntityFrom(HungryDamage, Settings.get.nanomachinesHungryDamage)
api.Nanomachines.getController(player).changeBuffer(Settings.get.nanomachinesHungryEnergyRestored)
}
}
}
}

View File

@ -2,6 +2,7 @@ package li.cil.oc.common.nanomachines.provider
import li.cil.oc.Settings import li.cil.oc.Settings
import li.cil.oc.api import li.cil.oc.api
import li.cil.oc.api.prefab.AbstractBehavior
import net.minecraft.entity.item.EntityItem import net.minecraft.entity.item.EntityItem
import net.minecraft.entity.player.EntityPlayer import net.minecraft.entity.player.EntityPlayer
import net.minecraft.nbt.NBTTagCompound import net.minecraft.nbt.NBTTagCompound
@ -9,15 +10,12 @@ import net.minecraft.util.Vec3
import scala.collection.convert.WrapAsScala._ import scala.collection.convert.WrapAsScala._
object MagnetProvider extends SimpleProvider { object MagnetProvider extends ScalaProvider("9324d5ec-71f1-41c2-b51c-406e527668fc") {
// One-time generated UUID to identify our behaviors. override def createScalaBehaviors(player: EntityPlayer) = Iterable(new MagnetBehavior(player))
final val Id = "9324d5ec-71f1-41c2-b51c-406e527668fc"
override def doCreateBehaviors(player: EntityPlayer) = Iterable(new MagnetBehavior(player)) override def readBehaviorFromNBT(player: EntityPlayer, nbt: NBTTagCompound) = new MagnetBehavior(player)
override def doReadFromNBT(player: EntityPlayer, nbt: NBTTagCompound) = new MagnetBehavior(player) class MagnetBehavior(player: EntityPlayer) extends AbstractBehavior(player) {
class MagnetBehavior(player: EntityPlayer) extends SimpleBehavior(player) {
override def getNameHint = "magnet" override def getNameHint = "magnet"
override def update(): Unit = { override def update(): Unit = {

View File

@ -2,14 +2,13 @@ package li.cil.oc.common.nanomachines.provider
import li.cil.oc.api import li.cil.oc.api
import li.cil.oc.api.nanomachines.Behavior import li.cil.oc.api.nanomachines.Behavior
import li.cil.oc.api.prefab.AbstractBehavior
import li.cil.oc.util.PlayerUtils import li.cil.oc.util.PlayerUtils
import net.minecraft.entity.player.EntityPlayer import net.minecraft.entity.player.EntityPlayer
import net.minecraft.nbt.NBTTagCompound import net.minecraft.nbt.NBTTagCompound
import net.minecraft.util.EnumParticleTypes import net.minecraft.util.EnumParticleTypes
object ParticleProvider extends SimpleProvider { object ParticleProvider extends ScalaProvider("b48c4bbd-51bb-4915-9367-16cff3220e4b") {
final val Id = "b48c4bbd-51bb-4915-9367-16cff3220e4b"
final val ParticleTypes = Array( final val ParticleTypes = Array(
EnumParticleTypes.FIREWORKS_SPARK, EnumParticleTypes.FIREWORKS_SPARK,
EnumParticleTypes.TOWN_AURA, EnumParticleTypes.TOWN_AURA,
@ -26,9 +25,9 @@ object ParticleProvider extends SimpleProvider {
EnumParticleTypes.VILLAGER_HAPPY EnumParticleTypes.VILLAGER_HAPPY
) )
override def doCreateBehaviors(player: EntityPlayer): Iterable[Behavior] = ParticleTypes.map(new ParticleBehavior(_, player)) override def createScalaBehaviors(player: EntityPlayer): Iterable[Behavior] = ParticleTypes.map(new ParticleBehavior(_, player))
override def doWriteToNBT(behavior: Behavior, nbt: NBTTagCompound): Unit = { override def writeBehaviorToNBT(behavior: Behavior, nbt: NBTTagCompound): Unit = {
behavior match { behavior match {
case particles: ParticleBehavior => case particles: ParticleBehavior =>
nbt.setInteger("effectName", particles.effectType.getParticleID) nbt.setInteger("effectName", particles.effectType.getParticleID)
@ -36,12 +35,12 @@ object ParticleProvider extends SimpleProvider {
} }
} }
override def doReadFromNBT(player: EntityPlayer, nbt: NBTTagCompound): Behavior = { override def readBehaviorFromNBT(player: EntityPlayer, nbt: NBTTagCompound): Behavior = {
val effectType = EnumParticleTypes.getParticleFromId(nbt.getInteger("effectName")) val effectType = EnumParticleTypes.getParticleFromId(nbt.getInteger("effectName"))
new ParticleBehavior(effectType, player) new ParticleBehavior(effectType, player)
} }
class ParticleBehavior(var effectType: EnumParticleTypes, player: EntityPlayer) extends SimpleBehavior(player) { class ParticleBehavior(var effectType: EnumParticleTypes, player: EntityPlayer) extends AbstractBehavior(player) {
override def getNameHint = "particles" override def getNameHint = "particles"
override def update(): Unit = { override def update(): Unit = {

View File

@ -3,6 +3,8 @@ package li.cil.oc.common.nanomachines.provider
import li.cil.oc.Settings import li.cil.oc.Settings
import li.cil.oc.api import li.cil.oc.api
import li.cil.oc.api.nanomachines.Behavior import li.cil.oc.api.nanomachines.Behavior
import li.cil.oc.api.nanomachines.DisableReason
import li.cil.oc.api.prefab.AbstractBehavior
import net.minecraft.entity.player.EntityPlayer import net.minecraft.entity.player.EntityPlayer
import net.minecraft.nbt.NBTTagCompound import net.minecraft.nbt.NBTTagCompound
import net.minecraft.potion.Potion import net.minecraft.potion.Potion
@ -10,23 +12,27 @@ import net.minecraft.potion.PotionEffect
import scala.collection.convert.WrapAsScala._ import scala.collection.convert.WrapAsScala._
object PotionProvider extends SimpleProvider { object PotionProvider extends ScalaProvider("c29e4eec-5a46-479a-9b3d-ad0f06da784a") {
final val Id = "c29e4eec-5a46-479a-9b3d-ad0f06da784a"
// Lazy to give other mods a chance to register their potions. // Lazy to give other mods a chance to register their potions.
lazy val PotionBlacklist = Settings.get.nanomachinePotionBlacklist.map { lazy val PotionWhitelist = filterPotions(Settings.get.nanomachinePotionWhitelist)
case name: String => Potion.potionTypes.find(p => p != null && p.getName == name)
case id: java.lang.Number if id.intValue() >= 0 && id.intValue() < Potion.potionTypes.length => Option(Potion.potionTypes(id.intValue()))
case _ => None
}.collect {
case Some(potion) => potion
}.toSet
override def doCreateBehaviors(player: EntityPlayer) = { def filterPotions[T](list: Iterable[T]) = {
Potion.potionTypes.filter(_ != null).filterNot(PotionBlacklist.contains).map(new PotionBehavior(_, player)) list.map {
case name: String => Potion.potionTypes.find(p => p != null && p.getName == name)
case id: java.lang.Number if id.intValue() >= 0 && id.intValue() < Potion.potionTypes.length => Option(Potion.potionTypes(id.intValue()))
case _ => None
}.collect {
case Some(potion) => potion
}.toSet
} }
override def doWriteToNBT(behavior: Behavior, nbt: NBTTagCompound): Unit = { def isPotionEligible(potion: Potion) = potion != null && PotionWhitelist.contains(potion)
override def createScalaBehaviors(player: EntityPlayer) = {
Potion.potionTypes.filter(isPotionEligible).map(new PotionBehavior(_, player))
}
override def writeBehaviorToNBT(behavior: Behavior, nbt: NBTTagCompound): Unit = {
behavior match { behavior match {
case potionBehavior: PotionBehavior => case potionBehavior: PotionBehavior =>
nbt.setInteger("potionId", potionBehavior.potion.id) nbt.setInteger("potionId", potionBehavior.potion.id)
@ -34,21 +40,19 @@ object PotionProvider extends SimpleProvider {
} }
} }
override def doReadFromNBT(player: EntityPlayer, nbt: NBTTagCompound) = { override def readBehaviorFromNBT(player: EntityPlayer, nbt: NBTTagCompound) = {
val potionId = nbt.getInteger("potionId") val potionId = nbt.getInteger("potionId")
new PotionBehavior(Potion.potionTypes(potionId), player) new PotionBehavior(Potion.potionTypes(potionId), player)
} }
class PotionBehavior(val potion: Potion, player: EntityPlayer) extends SimpleBehavior(player) { class PotionBehavior(val potion: Potion, player: EntityPlayer) extends AbstractBehavior(player) {
final val Duration = 600 final val Duration = 600
def amplifier(player: EntityPlayer) = api.Nanomachines.getController(player).getInputCount(this) - 1 def amplifier(player: EntityPlayer) = api.Nanomachines.getController(player).getInputCount(this) - 1
override def getNameHint: String = potion.getName.stripPrefix("potion.") override def getNameHint: String = potion.getName.stripPrefix("potion.")
override def onEnable(): Unit = {} override def onDisable(reason: DisableReason): Unit = {
override def onDisable(): Unit = {
player.removePotionEffect(potion.id) player.removePotionEffect(potion.id)
} }

View File

@ -0,0 +1,13 @@
package li.cil.oc.common.nanomachines.provider
import li.cil.oc.api.nanomachines.Behavior
import li.cil.oc.api.prefab.AbstractProvider
import net.minecraft.entity.player.EntityPlayer
import scala.collection.convert.WrapAsJava._
abstract class ScalaProvider(id: String) extends AbstractProvider(id) {
def createScalaBehaviors(player: EntityPlayer): Iterable[Behavior]
override def createBehaviors(player: EntityPlayer): java.lang.Iterable[Behavior] = asJavaIterable(createScalaBehaviors(player))
}

View File

@ -1,14 +0,0 @@
package li.cil.oc.common.nanomachines.provider
import li.cil.oc.api.nanomachines.Behavior
import net.minecraft.entity.player.EntityPlayer
class SimpleBehavior(val player: EntityPlayer) extends Behavior {
override def getNameHint: String = null
override def onEnable(): Unit = {}
override def onDisable(): Unit = {}
override def update(): Unit = {}
}

View File

@ -1,35 +0,0 @@
package li.cil.oc.common.nanomachines.provider
import li.cil.oc.api.nanomachines.Behavior
import li.cil.oc.api.nanomachines.BehaviorProvider
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.nbt.NBTTagCompound
import scala.collection.convert.WrapAsJava._
abstract class SimpleProvider extends BehaviorProvider {
// One-time generated UUID to identify our behaviors.
def Id: String
def doCreateBehaviors(player: EntityPlayer): Iterable[Behavior]
def doWriteToNBT(behavior: Behavior, nbt: NBTTagCompound): Unit = {}
def doReadFromNBT(player: EntityPlayer, nbt: NBTTagCompound): Behavior
override def createBehaviors(player: EntityPlayer): java.lang.Iterable[Behavior] = asJavaIterable(doCreateBehaviors(player))
override def writeToNBT(behavior: Behavior): NBTTagCompound = {
val nbt = new NBTTagCompound()
nbt.setString("provider", Id)
doWriteToNBT(behavior: Behavior, nbt: NBTTagCompound)
nbt
}
override def readFromNBT(player: EntityPlayer, nbt: NBTTagCompound): Behavior = {
if (nbt.getString("provider") == Id) {
doReadFromNBT(player, nbt)
}
else null
}
}

View File

@ -28,6 +28,7 @@ import li.cil.oc.common.item.Delegator
import li.cil.oc.common.item.RedstoneCard import li.cil.oc.common.item.RedstoneCard
import li.cil.oc.common.item.Tablet import li.cil.oc.common.item.Tablet
import li.cil.oc.common.nanomachines.provider.DisintegrationProvider import li.cil.oc.common.nanomachines.provider.DisintegrationProvider
import li.cil.oc.common.nanomachines.provider.HungryProvider
import li.cil.oc.common.nanomachines.provider.MagnetProvider import li.cil.oc.common.nanomachines.provider.MagnetProvider
import li.cil.oc.common.nanomachines.provider.ParticleProvider import li.cil.oc.common.nanomachines.provider.ParticleProvider
import li.cil.oc.common.nanomachines.provider.PotionProvider import li.cil.oc.common.nanomachines.provider.PotionProvider
@ -72,6 +73,7 @@ object ModOpenComputers extends ModProxy {
ForgeChunkManager.setForcedChunkLoadingCallback(OpenComputers, ChunkloaderUpgradeHandler) ForgeChunkManager.setForcedChunkLoadingCallback(OpenComputers, ChunkloaderUpgradeHandler)
FMLCommonHandler.instance.bus.register(EventHandler) FMLCommonHandler.instance.bus.register(EventHandler)
FMLCommonHandler.instance.bus.register(NanomachinesHandler.Common)
FMLCommonHandler.instance.bus.register(SimpleComponentTickHandler.Instance) FMLCommonHandler.instance.bus.register(SimpleComponentTickHandler.Instance)
FMLCommonHandler.instance.bus.register(Tablet) FMLCommonHandler.instance.bus.register(Tablet)
@ -84,7 +86,7 @@ object ModOpenComputers extends ModProxy {
MinecraftForge.EVENT_BUS.register(GeolyzerHandler) MinecraftForge.EVENT_BUS.register(GeolyzerHandler)
MinecraftForge.EVENT_BUS.register(HoverBootsHandler) MinecraftForge.EVENT_BUS.register(HoverBootsHandler)
MinecraftForge.EVENT_BUS.register(Loot) MinecraftForge.EVENT_BUS.register(Loot)
MinecraftForge.EVENT_BUS.register(NanomachinesEventHandler.Common) MinecraftForge.EVENT_BUS.register(NanomachinesHandler.Common)
MinecraftForge.EVENT_BUS.register(RobotCommonHandler) MinecraftForge.EVENT_BUS.register(RobotCommonHandler)
MinecraftForge.EVENT_BUS.register(SaveHandler) MinecraftForge.EVENT_BUS.register(SaveHandler)
MinecraftForge.EVENT_BUS.register(Tablet) MinecraftForge.EVENT_BUS.register(Tablet)
@ -253,6 +255,7 @@ object ModOpenComputers extends ModProxy {
api.Manual.addTab(new ItemStackTabIconRenderer(api.Items.get("cpu1").createItemStack(1)), "oc:gui.Manual.Items", "%LANGUAGE%/item/index.md") api.Manual.addTab(new ItemStackTabIconRenderer(api.Items.get("cpu1").createItemStack(1)), "oc:gui.Manual.Items", "%LANGUAGE%/item/index.md")
api.Nanomachines.addProvider(DisintegrationProvider) api.Nanomachines.addProvider(DisintegrationProvider)
api.Nanomachines.addProvider(HungryProvider)
api.Nanomachines.addProvider(ParticleProvider) api.Nanomachines.addProvider(ParticleProvider)
api.Nanomachines.addProvider(PotionProvider) api.Nanomachines.addProvider(PotionProvider)
api.Nanomachines.addProvider(MagnetProvider) api.Nanomachines.addProvider(MagnetProvider)

View File

@ -0,0 +1,19 @@
package li.cil.oc.integration.util
import net.minecraft.entity.EntityLivingBase
import net.minecraft.util.ChatComponentTranslation
import net.minecraft.util.DamageSource
import net.minecraft.util.IChatComponent
import net.minecraft.util.StatCollector
class DamageSourceWithRandomCause(name: String, numCauses: Int) extends DamageSource(name) {
override def getDeathMessage(damagee: EntityLivingBase): IChatComponent = {
val damager = damagee.func_94060_bK
val format = "death.attack." + damageType + "." + (damagee.worldObj.rand.nextInt(numCauses) + 1)
val withCauseFormat = format + ".player"
if (damager != null && StatCollector.canTranslate(withCauseFormat))
new ChatComponentTranslation(withCauseFormat, damagee.getDisplayName, damager.getDisplayName)
else
new ChatComponentTranslation(format, damagee.getDisplayName)
}
}