From e0d223df334d1c206c41f5799feb9e485197d47c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Fri, 18 Sep 2015 11:28:48 +0200 Subject: [PATCH 1/5] `onDisable` should now properly be called when running out of power, and when player disconnects. --- src/main/scala/li/cil/oc/client/Proxy.scala | 4 ++-- ...ventHandler.scala => NanomachinesHandler.scala} | 14 +++++++++++++- .../scala/li/cil/oc/common/item/Nanomachines.scala | 3 +++ .../oc/common/nanomachines/ControllerImpl.scala | 8 ++++++-- .../cil/oc/common/nanomachines/Nanomachines.scala | 8 ++++++-- .../opencomputers/ModOpenComputers.scala | 3 ++- 6 files changed, 32 insertions(+), 8 deletions(-) rename src/main/scala/li/cil/oc/common/event/{NanomachinesEventHandler.scala => NanomachinesHandler.scala} (90%) diff --git a/src/main/scala/li/cil/oc/client/Proxy.scala b/src/main/scala/li/cil/oc/client/Proxy.scala index cfb750795..d3c704625 100644 --- a/src/main/scala/li/cil/oc/client/Proxy.scala +++ b/src/main/scala/li/cil/oc/client/Proxy.scala @@ -21,7 +21,7 @@ import li.cil.oc.client.renderer.item.ItemRenderer import li.cil.oc.client.renderer.tileentity._ import li.cil.oc.common.component.TextBuffer 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.tileentity import li.cil.oc.common.tileentity.ServerRack @@ -81,7 +81,7 @@ private[oc] class Proxy extends CommonProxy { ClientRegistry.registerKeyBinding(KeyBindings.clipboardPaste) 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(ServerRack) MinecraftForge.EVENT_BUS.register(Sound) diff --git a/src/main/scala/li/cil/oc/common/event/NanomachinesEventHandler.scala b/src/main/scala/li/cil/oc/common/event/NanomachinesHandler.scala similarity index 90% rename from src/main/scala/li/cil/oc/common/event/NanomachinesEventHandler.scala rename to src/main/scala/li/cil/oc/common/event/NanomachinesHandler.scala index c55f24225..6135e8126 100644 --- a/src/main/scala/li/cil/oc/common/event/NanomachinesEventHandler.scala +++ b/src/main/scala/li/cil/oc/common/event/NanomachinesHandler.scala @@ -4,11 +4,13 @@ import java.io.FileInputStream import java.io.FileOutputStream import cpw.mods.fml.common.eventhandler.SubscribeEvent +import cpw.mods.fml.common.gameevent.PlayerEvent.PlayerLoggedOutEvent import li.cil.oc.OpenComputers import li.cil.oc.Settings import li.cil.oc.api import li.cil.oc.api.nanomachines.Controller import li.cil.oc.client.Textures +import li.cil.oc.common.EventHandler import li.cil.oc.common.nanomachines.ControllerImpl import net.minecraft.client.Minecraft import net.minecraft.client.gui.ScaledResolution @@ -20,7 +22,7 @@ import net.minecraftforge.client.event.RenderGameOverlayEvent import net.minecraftforge.event.entity.living.LivingEvent import net.minecraftforge.event.entity.player.PlayerEvent -object NanomachinesEventHandler { +object NanomachinesHandler { object Client { @SubscribeEvent @@ -140,6 +142,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. + } + } } } diff --git a/src/main/scala/li/cil/oc/common/item/Nanomachines.scala b/src/main/scala/li/cil/oc/common/item/Nanomachines.scala index afd8020d6..0a0193042 100644 --- a/src/main/scala/li/cil/oc/common/item/Nanomachines.scala +++ b/src/main/scala/li/cil/oc/common/item/Nanomachines.scala @@ -3,10 +3,13 @@ package li.cil.oc.common.item import li.cil.oc.api import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.EnumAction +import net.minecraft.item.EnumRarity import net.minecraft.item.ItemStack import net.minecraft.world.World 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 = { if (!api.Nanomachines.hasController(player)) { player.setItemInUse(stack, getMaxItemUseDuration(stack)) diff --git a/src/main/scala/li/cil/oc/common/nanomachines/ControllerImpl.scala b/src/main/scala/li/cil/oc/common/nanomachines/ControllerImpl.scala index 25a0da508..695a3ecbd 100644 --- a/src/main/scala/li/cil/oc/common/nanomachines/ControllerImpl.scala +++ b/src/main/scala/li/cil/oc/common/nanomachines/ControllerImpl.scala @@ -51,7 +51,7 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE override def z: Int = BlockPosition(player).z 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 dSquared = dx * dx + dy * dy + dz * dz if (dSquared < MaxSenderDistance * MaxSenderDistance) packet.data.headOption match { @@ -179,6 +179,10 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE // ----------------------------------------------------------------------- // def update(): Unit = { + if (player.isDead) { + return + } + if (isServer) { api.Network.updateWirelessNetwork(this) } @@ -245,6 +249,7 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE configuration.triggers(index).isActive = false activeBehaviorsDirty = true } + cleanActiveBehaviors() } } @@ -252,7 +257,6 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE reset() if (isServer) { api.Network.leaveWirelessNetwork(this) - PacketSender.sendNanomachineConfiguration(player) } } diff --git a/src/main/scala/li/cil/oc/common/nanomachines/Nanomachines.scala b/src/main/scala/li/cil/oc/common/nanomachines/Nanomachines.scala index afaf3433a..bfd68536c 100644 --- a/src/main/scala/li/cil/oc/common/nanomachines/Nanomachines.scala +++ b/src/main/scala/li/cil/oc/common/nanomachines/Nanomachines.scala @@ -4,6 +4,7 @@ import li.cil.oc.Settings import li.cil.oc.api import li.cil.oc.api.nanomachines.BehaviorProvider import li.cil.oc.api.nanomachines.Controller +import li.cil.oc.server.PacketSender import li.cil.oc.util.PlayerUtils import net.minecraft.entity.player.EntityPlayer @@ -41,9 +42,12 @@ object Nanomachines extends api.detail.NanomachinesAPI { override def uninstallController(player: EntityPlayer): Unit = { getController(player) match { case controller: ControllerImpl => - PlayerUtils.persistedData(player).removeTag(Settings.namespace + "hasNanomachines") - controllers(player) -= player 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. } } diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala b/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala index 579c6cb52..6eadc5d2c 100644 --- a/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala +++ b/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala @@ -71,6 +71,7 @@ object ModOpenComputers extends ModProxy { ForgeChunkManager.setForcedChunkLoadingCallback(OpenComputers, ChunkloaderUpgradeHandler) FMLCommonHandler.instance.bus.register(EventHandler) + FMLCommonHandler.instance.bus.register(NanomachinesHandler.Common) FMLCommonHandler.instance.bus.register(SimpleComponentTickHandler.Instance) FMLCommonHandler.instance.bus.register(Tablet) @@ -83,7 +84,7 @@ object ModOpenComputers extends ModProxy { MinecraftForge.EVENT_BUS.register(GeolyzerHandler) MinecraftForge.EVENT_BUS.register(HoverBootsHandler) 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(SaveHandler) MinecraftForge.EVENT_BUS.register(Tablet) From 10dd699e6ed05d9de7f3227e996611583957df8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Fri, 18 Sep 2015 12:07:23 +0200 Subject: [PATCH 2/5] Moved simple base classes for behavior and provider to api.prefab. --- src/main/java/li/cil/oc/api/API.java | 2 +- .../cil/oc/api/prefab/AbstractBehavior.java | 51 +++++++++++++ .../cil/oc/api/prefab/AbstractProvider.java | 74 +++++++++++++++++++ .../provider/DisintegrationProvider.scala | 13 ++-- .../provider/MagnetProvider.scala | 13 ++-- .../provider/ParticleProvider.scala | 13 ++-- .../provider/PotionProvider.scala | 13 ++-- .../nanomachines/provider/ScalaProvider.scala | 13 ++++ .../provider/SimpleBehavior.scala | 14 ---- .../provider/SimpleProvider.scala | 35 --------- 10 files changed, 162 insertions(+), 79 deletions(-) create mode 100644 src/main/java/li/cil/oc/api/prefab/AbstractBehavior.java create mode 100644 src/main/java/li/cil/oc/api/prefab/AbstractProvider.java create mode 100644 src/main/scala/li/cil/oc/common/nanomachines/provider/ScalaProvider.scala delete mode 100644 src/main/scala/li/cil/oc/common/nanomachines/provider/SimpleBehavior.scala delete mode 100644 src/main/scala/li/cil/oc/common/nanomachines/provider/SimpleProvider.scala diff --git a/src/main/java/li/cil/oc/api/API.java b/src/main/java/li/cil/oc/api/API.java index d25a42825..1b0e5ad0e 100644 --- a/src/main/java/li/cil/oc/api/API.java +++ b/src/main/java/li/cil/oc/api/API.java @@ -12,7 +12,7 @@ import li.cil.oc.api.detail.*; */ public class API { public static final String ID_OWNER = "OpenComputers|Core"; - public static final String VERSION = "5.5.5"; + public static final String VERSION = "5.5.6"; public static DriverAPI driver = null; public static FileSystemAPI fileSystem = null; diff --git a/src/main/java/li/cil/oc/api/prefab/AbstractBehavior.java b/src/main/java/li/cil/oc/api/prefab/AbstractBehavior.java new file mode 100644 index 000000000..a1d0ed199 --- /dev/null +++ b/src/main/java/li/cil/oc/api/prefab/AbstractBehavior.java @@ -0,0 +1,51 @@ +package li.cil.oc.api.prefab; + +import li.cil.oc.api.nanomachines.Behavior; +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. + *

+ * 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() { + } + + @Override + public void update() { + } +} diff --git a/src/main/java/li/cil/oc/api/prefab/AbstractProvider.java b/src/main/java/li/cil/oc/api/prefab/AbstractProvider.java new file mode 100644 index 000000000..9f0393835 --- /dev/null +++ b/src/main/java/li/cil/oc/api/prefab/AbstractProvider.java @@ -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. + *

+ * 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. + *

+ * 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. + *

+ * 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; + } + } +} diff --git a/src/main/scala/li/cil/oc/common/nanomachines/provider/DisintegrationProvider.scala b/src/main/scala/li/cil/oc/common/nanomachines/provider/DisintegrationProvider.scala index c470b058d..31043d234 100644 --- a/src/main/scala/li/cil/oc/common/nanomachines/provider/DisintegrationProvider.scala +++ b/src/main/scala/li/cil/oc/common/nanomachines/provider/DisintegrationProvider.scala @@ -1,8 +1,9 @@ package li.cil.oc.common.nanomachines.provider import cpw.mods.fml.common.eventhandler.Event -import li.cil.oc.api import li.cil.oc.Settings +import li.cil.oc.api +import li.cil.oc.api.prefab.AbstractBehavior import li.cil.oc.util.BlockPosition import li.cil.oc.util.ExtendedWorld._ import net.minecraft.block.Block @@ -16,14 +17,12 @@ import net.minecraftforge.event.entity.player.PlayerInteractEvent.Action import scala.collection.mutable -object DisintegrationProvider extends SimpleProvider { - final val Id = "c4e7e3c2-8069-4fbb-b08e-74b1bddcdfe7" +object DisintegrationProvider extends ScalaProvider("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 SimpleBehavior(player) { + class DisintegrationBehavior(player: EntityPlayer) extends AbstractBehavior(player) { var breakingMap = mutable.Map.empty[BlockPosition, SlowBreakInfo] var breakingMapNew = mutable.Map.empty[BlockPosition, SlowBreakInfo] diff --git a/src/main/scala/li/cil/oc/common/nanomachines/provider/MagnetProvider.scala b/src/main/scala/li/cil/oc/common/nanomachines/provider/MagnetProvider.scala index 72adcd9c0..7c6a0659f 100644 --- a/src/main/scala/li/cil/oc/common/nanomachines/provider/MagnetProvider.scala +++ b/src/main/scala/li/cil/oc/common/nanomachines/provider/MagnetProvider.scala @@ -2,7 +2,7 @@ package li.cil.oc.common.nanomachines.provider import li.cil.oc.Settings import li.cil.oc.api - +import li.cil.oc.api.prefab.AbstractBehavior import net.minecraft.entity.item.EntityItem import net.minecraft.entity.player.EntityPlayer import net.minecraft.nbt.NBTTagCompound @@ -10,15 +10,12 @@ import net.minecraft.util.Vec3 import scala.collection.convert.WrapAsScala._ -object MagnetProvider extends SimpleProvider { - // One-time generated UUID to identify our behaviors. - final val Id = "9324d5ec-71f1-41c2-b51c-406e527668fc" +object MagnetProvider extends ScalaProvider("9324d5ec-71f1-41c2-b51c-406e527668fc") { + override def createScalaBehaviors(player: EntityPlayer) = Iterable(new MagnetBehavior(player)) - 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 SimpleBehavior(player) { + class MagnetBehavior(player: EntityPlayer) extends AbstractBehavior(player) { override def getNameHint = "magnet" override def update(): Unit = { diff --git a/src/main/scala/li/cil/oc/common/nanomachines/provider/ParticleProvider.scala b/src/main/scala/li/cil/oc/common/nanomachines/provider/ParticleProvider.scala index 75c4a2fd4..95822bed3 100644 --- a/src/main/scala/li/cil/oc/common/nanomachines/provider/ParticleProvider.scala +++ b/src/main/scala/li/cil/oc/common/nanomachines/provider/ParticleProvider.scala @@ -2,13 +2,12 @@ package li.cil.oc.common.nanomachines.provider import li.cil.oc.api import li.cil.oc.api.nanomachines.Behavior +import li.cil.oc.api.prefab.AbstractBehavior import li.cil.oc.util.PlayerUtils import net.minecraft.entity.player.EntityPlayer import net.minecraft.nbt.NBTTagCompound -object ParticleProvider extends SimpleProvider { - final val Id = "b48c4bbd-51bb-4915-9367-16cff3220e4b" - +object ParticleProvider extends ScalaProvider("b48c4bbd-51bb-4915-9367-16cff3220e4b") { final val ParticleNames = Array( "fireworksSpark", "townaura", @@ -25,9 +24,9 @@ object ParticleProvider extends SimpleProvider { "happyVillager" ) - override def doCreateBehaviors(player: EntityPlayer): Iterable[Behavior] = ParticleNames.map(new ParticleBehavior(_, player)) + override def createScalaBehaviors(player: EntityPlayer): Iterable[Behavior] = ParticleNames.map(new ParticleBehavior(_, player)) - override def doWriteToNBT(behavior: Behavior, nbt: NBTTagCompound): Unit = { + override def writeBehaviorToNBT(behavior: Behavior, nbt: NBTTagCompound): Unit = { behavior match { case particles: ParticleBehavior => nbt.setString("effectName", particles.effectName) @@ -35,12 +34,12 @@ object ParticleProvider extends SimpleProvider { } } - override def doReadFromNBT(player: EntityPlayer, nbt: NBTTagCompound): Behavior = { + override def readBehaviorFromNBT(player: EntityPlayer, nbt: NBTTagCompound): Behavior = { val effectName = nbt.getString("effectName") new ParticleBehavior(effectName, player) } - class ParticleBehavior(var effectName: String, player: EntityPlayer) extends SimpleBehavior(player) { + class ParticleBehavior(var effectName: String, player: EntityPlayer) extends AbstractBehavior(player) { override def getNameHint = "particles" override def update(): Unit = { diff --git a/src/main/scala/li/cil/oc/common/nanomachines/provider/PotionProvider.scala b/src/main/scala/li/cil/oc/common/nanomachines/provider/PotionProvider.scala index b26db07b3..2ed346914 100644 --- a/src/main/scala/li/cil/oc/common/nanomachines/provider/PotionProvider.scala +++ b/src/main/scala/li/cil/oc/common/nanomachines/provider/PotionProvider.scala @@ -3,6 +3,7 @@ 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.prefab.AbstractBehavior import net.minecraft.entity.player.EntityPlayer import net.minecraft.nbt.NBTTagCompound import net.minecraft.potion.Potion @@ -10,9 +11,7 @@ import net.minecraft.potion.PotionEffect import scala.collection.convert.WrapAsScala._ -object PotionProvider extends SimpleProvider { - final val Id = "c29e4eec-5a46-479a-9b3d-ad0f06da784a" - +object PotionProvider extends ScalaProvider("c29e4eec-5a46-479a-9b3d-ad0f06da784a") { // Lazy to give other mods a chance to register their potions. lazy val PotionBlacklist = Settings.get.nanomachinePotionBlacklist.map { case name: String => Potion.potionTypes.find(p => p != null && p.getName == name) @@ -22,11 +21,11 @@ object PotionProvider extends SimpleProvider { case Some(potion) => potion }.toSet - override def doCreateBehaviors(player: EntityPlayer) = { + override def createScalaBehaviors(player: EntityPlayer) = { Potion.potionTypes.filter(_ != null).filterNot(PotionBlacklist.contains).map(new PotionBehavior(_, player)) } - override def doWriteToNBT(behavior: Behavior, nbt: NBTTagCompound): Unit = { + override def writeBehaviorToNBT(behavior: Behavior, nbt: NBTTagCompound): Unit = { behavior match { case potionBehavior: PotionBehavior => nbt.setInteger("potionId", potionBehavior.potion.id) @@ -34,12 +33,12 @@ object PotionProvider extends SimpleProvider { } } - override def doReadFromNBT(player: EntityPlayer, nbt: NBTTagCompound) = { + override def readBehaviorFromNBT(player: EntityPlayer, nbt: NBTTagCompound) = { val potionId = nbt.getInteger("potionId") 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 def amplifier(player: EntityPlayer) = api.Nanomachines.getController(player).getInputCount(this) - 1 diff --git a/src/main/scala/li/cil/oc/common/nanomachines/provider/ScalaProvider.scala b/src/main/scala/li/cil/oc/common/nanomachines/provider/ScalaProvider.scala new file mode 100644 index 000000000..93285282a --- /dev/null +++ b/src/main/scala/li/cil/oc/common/nanomachines/provider/ScalaProvider.scala @@ -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)) +} diff --git a/src/main/scala/li/cil/oc/common/nanomachines/provider/SimpleBehavior.scala b/src/main/scala/li/cil/oc/common/nanomachines/provider/SimpleBehavior.scala deleted file mode 100644 index 25bc0d9a7..000000000 --- a/src/main/scala/li/cil/oc/common/nanomachines/provider/SimpleBehavior.scala +++ /dev/null @@ -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 = {} -} diff --git a/src/main/scala/li/cil/oc/common/nanomachines/provider/SimpleProvider.scala b/src/main/scala/li/cil/oc/common/nanomachines/provider/SimpleProvider.scala deleted file mode 100644 index 40f8ce6b3..000000000 --- a/src/main/scala/li/cil/oc/common/nanomachines/provider/SimpleProvider.scala +++ /dev/null @@ -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 - } -} From 6d46cfa4784399b145168bbab9f834b2ed6bafe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Fri, 18 Sep 2015 12:21:45 +0200 Subject: [PATCH 3/5] Added potion whitelist. All bad effects are allowed by default and have to be blacklisted; all good ones have to be whitelisted. --- src/main/resources/application.conf | 22 ++++++++++++++---- src/main/scala/li/cil/oc/Settings.scala | 1 + .../provider/PotionProvider.scala | 23 ++++++++++++------- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index 005ced3a2..a2cddd7cc 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -1025,12 +1025,24 @@ opencomputers { # Blacklisted potions, i.e. potions that won't be used for the potion # 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 case of a number it has to be the potion ID. + # in case of a number it has to be the potion ID. Use this to disable + # *bad* potion effects, since they will all be enabled by default. potionBlacklist: [ - "potion.heal", - "potion.regeneration", - "potion.invisibility", - "potion.saturation" + ] + + # Whitelisted potions, see potionBlacklist. Add *good* potion effects + # to make use of here, since they will all be disabled by default. + potionWhitelist: [ + "potion.moveSpeed", + "potion.digSpeed", + "potion.damageBoost", + "potion.jump", + "potion.resistance", + "potion.fireResistance", + "potion.waterBreathing", + "potion.nightVision", + "potion.healthBoost", + "potion.absorption" ] } diff --git a/src/main/scala/li/cil/oc/Settings.scala b/src/main/scala/li/cil/oc/Settings.scala index 35b9b02ae..648dcfaf5 100644 --- a/src/main/scala/li/cil/oc/Settings.scala +++ b/src/main/scala/li/cil/oc/Settings.scala @@ -359,6 +359,7 @@ class Settings(val config: Config) { val nanomachineMagnetRange = config.getDouble("nanomachines.magnetRange") max 0 val nanomachineDisintegrationRange = config.getInt("nanomachines.disintegrationRange") max 0 val nanomachinePotionBlacklist = config.getAnyRefList("nanomachines.potionBlacklist") + val nanomachinePotionWhitelist = config.getAnyRefList("nanomachines.potionWhitelist") // ----------------------------------------------------------------------- // // printer diff --git a/src/main/scala/li/cil/oc/common/nanomachines/provider/PotionProvider.scala b/src/main/scala/li/cil/oc/common/nanomachines/provider/PotionProvider.scala index 2ed346914..452ba552c 100644 --- a/src/main/scala/li/cil/oc/common/nanomachines/provider/PotionProvider.scala +++ b/src/main/scala/li/cil/oc/common/nanomachines/provider/PotionProvider.scala @@ -13,16 +13,23 @@ import scala.collection.convert.WrapAsScala._ object PotionProvider extends ScalaProvider("c29e4eec-5a46-479a-9b3d-ad0f06da784a") { // Lazy to give other mods a chance to register their potions. - lazy val PotionBlacklist = Settings.get.nanomachinePotionBlacklist.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 + lazy val PotionWhitelist = filterPotions(Settings.get.nanomachinePotionWhitelist) + lazy val PotionBlacklist = filterPotions(Settings.get.nanomachinePotionBlacklist) + + def filterPotions[T](list: Iterable[T]) = { + 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 + } + + def isPotionEligible(potion: Potion) = potion != null && (if (potion.isBadEffect) !PotionBlacklist.contains(potion) else PotionWhitelist.contains(potion)) override def createScalaBehaviors(player: EntityPlayer) = { - Potion.potionTypes.filter(_ != null).filterNot(PotionBlacklist.contains).map(new PotionBehavior(_, player)) + Potion.potionTypes.filter(isPotionEligible).map(new PotionBehavior(_, player)) } override def writeBehaviorToNBT(behavior: Behavior, nbt: NBTTagCompound): Unit = { From 155bf0702c3e81da71fe10b7c7bcf107da03d5d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Fri, 18 Sep 2015 13:02:34 +0200 Subject: [PATCH 4/5] FUCK YOU MINECRAFT. Because *obviously* Potion.isBadEffect is client side only FOR NO FUCKING REASON. [/rant] So yeah, whitelist only it is. --- src/main/resources/application.conf | 21 ++++++++++++------- .../provider/PotionProvider.scala | 3 +-- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index a2cddd7cc..d95a00f06 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -1022,15 +1022,10 @@ opencomputers { # Radius in blocks of the disintegration behavior for each active input. 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. # 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. Use this to disable - # *bad* potion effects, since they will all be enabled by default. - potionBlacklist: [ - ] - - # Whitelisted potions, see potionBlacklist. Add *good* potion effects + # in case of a number it has to be the potion ID. Add any potion effects # to make use of here, since they will all be disabled by default. potionWhitelist: [ "potion.moveSpeed", @@ -1042,7 +1037,17 @@ opencomputers { "potion.waterBreathing", "potion.nightVision", "potion.healthBoost", - "potion.absorption" + "potion.absorption", + + "potion.blindness", + "potion.confusion", + "potion.digSlowDown", + "potion.harm", + "potion.hunger", + "potion.moveSlowdown", + "potion.poison", + "potion.weakness", + "potion.wither" ] } diff --git a/src/main/scala/li/cil/oc/common/nanomachines/provider/PotionProvider.scala b/src/main/scala/li/cil/oc/common/nanomachines/provider/PotionProvider.scala index 452ba552c..45affc130 100644 --- a/src/main/scala/li/cil/oc/common/nanomachines/provider/PotionProvider.scala +++ b/src/main/scala/li/cil/oc/common/nanomachines/provider/PotionProvider.scala @@ -14,7 +14,6 @@ import scala.collection.convert.WrapAsScala._ object PotionProvider extends ScalaProvider("c29e4eec-5a46-479a-9b3d-ad0f06da784a") { // Lazy to give other mods a chance to register their potions. lazy val PotionWhitelist = filterPotions(Settings.get.nanomachinePotionWhitelist) - lazy val PotionBlacklist = filterPotions(Settings.get.nanomachinePotionBlacklist) def filterPotions[T](list: Iterable[T]) = { list.map { @@ -26,7 +25,7 @@ object PotionProvider extends ScalaProvider("c29e4eec-5a46-479a-9b3d-ad0f06da784 }.toSet } - def isPotionEligible(potion: Potion) = potion != null && (if (potion.isBadEffect) !PotionBlacklist.contains(potion) else PotionWhitelist.contains(potion)) + def isPotionEligible(potion: Potion) = potion != null && PotionWhitelist.contains(potion) override def createScalaBehaviors(player: EntityPlayer) = { Potion.potionTypes.filter(isPotionEligible).map(new PotionBehavior(_, player)) From aef4165da57d5ad1f1420a37b9a77729cd36358c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Fri, 18 Sep 2015 14:47:29 +0200 Subject: [PATCH 5/5] Added a reason parameter to onDisable. Added new behavior. Using DamageSources now. --- src/main/java/li/cil/oc/api/API.java | 2 +- .../li/cil/oc/api/nanomachines/Behavior.java | 4 ++- .../oc/api/nanomachines/DisableReason.java | 23 +++++++++++++ .../cil/oc/api/prefab/AbstractBehavior.java | 3 +- src/main/resources/application.conf | 9 +++++- .../assets/opencomputers/lang/en_US.lang | 9 ++++++ src/main/scala/li/cil/oc/Settings.scala | 2 ++ .../common/nanomachines/ControllerImpl.scala | 24 +++++++++----- .../common/nanomachines/NeuralNetwork.scala | 8 ++--- .../provider/DisintegrationProvider.scala | 3 +- .../provider/HungryProvider.scala | 32 +++++++++++++++++++ .../provider/PotionProvider.scala | 5 ++- .../opencomputers/ModOpenComputers.scala | 2 ++ .../util/DamageSourceWithRandomCause.scala | 19 +++++++++++ 14 files changed, 123 insertions(+), 22 deletions(-) create mode 100644 src/main/java/li/cil/oc/api/nanomachines/DisableReason.java create mode 100644 src/main/scala/li/cil/oc/common/nanomachines/provider/HungryProvider.scala create mode 100644 src/main/scala/li/cil/oc/integration/util/DamageSourceWithRandomCause.scala diff --git a/src/main/java/li/cil/oc/api/API.java b/src/main/java/li/cil/oc/api/API.java index 1b0e5ad0e..733b13bb7 100644 --- a/src/main/java/li/cil/oc/api/API.java +++ b/src/main/java/li/cil/oc/api/API.java @@ -12,7 +12,7 @@ import li.cil.oc.api.detail.*; */ public class API { public static final String ID_OWNER = "OpenComputers|Core"; - public static final String VERSION = "5.5.6"; + public static final String VERSION = "5.6.0"; public static DriverAPI driver = null; public static FileSystemAPI fileSystem = null; diff --git a/src/main/java/li/cil/oc/api/nanomachines/Behavior.java b/src/main/java/li/cil/oc/api/nanomachines/Behavior.java index 38299b538..b532e253f 100644 --- a/src/main/java/li/cil/oc/api/nanomachines/Behavior.java +++ b/src/main/java/li/cil/oc/api/nanomachines/Behavior.java @@ -40,8 +40,10 @@ public interface Behavior { * Called when this behavior becomes inactive. *

* 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. diff --git a/src/main/java/li/cil/oc/api/nanomachines/DisableReason.java b/src/main/java/li/cil/oc/api/nanomachines/DisableReason.java new file mode 100644 index 000000000..13d806e36 --- /dev/null +++ b/src/main/java/li/cil/oc/api/nanomachines/DisableReason.java @@ -0,0 +1,23 @@ +package li.cil.oc.api.nanomachines; + +/** + * Enum with reasons why a nanomachine behavior was disabled. + *

+ * 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 +} diff --git a/src/main/java/li/cil/oc/api/prefab/AbstractBehavior.java b/src/main/java/li/cil/oc/api/prefab/AbstractBehavior.java index a1d0ed199..ea1ad4bb9 100644 --- a/src/main/java/li/cil/oc/api/prefab/AbstractBehavior.java +++ b/src/main/java/li/cil/oc/api/prefab/AbstractBehavior.java @@ -1,6 +1,7 @@ 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; /** @@ -42,7 +43,7 @@ public abstract class AbstractBehavior implements Behavior { } @Override - public void onDisable() { + public void onDisable(DisableReason reason) { } @Override diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index d95a00f06..ae36f0b62 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -1036,7 +1036,6 @@ opencomputers { "potion.fireResistance", "potion.waterBreathing", "potion.nightVision", - "potion.healthBoost", "potion.absorption", "potion.blindness", @@ -1049,6 +1048,14 @@ opencomputers { "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. diff --git a/src/main/resources/assets/opencomputers/lang/en_US.lang b/src/main/resources/assets/opencomputers/lang/en_US.lang index 64a6b2164..866a1153f 100644 --- a/src/main/resources/assets/opencomputers/lang/en_US.lang +++ b/src/main/resources/assets/opencomputers/lang/en_US.lang @@ -451,6 +451,15 @@ achievement.oc.transistor.desc=Create a Transistor to get started. Then listen t achievement.oc.wirelessNetworkCard=Signals 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.options.inventory.oredict=Show OreDictionary names nei.options.inventory.oredict.true=True diff --git a/src/main/scala/li/cil/oc/Settings.scala b/src/main/scala/li/cil/oc/Settings.scala index 648dcfaf5..84382f665 100644 --- a/src/main/scala/li/cil/oc/Settings.scala +++ b/src/main/scala/li/cil/oc/Settings.scala @@ -360,6 +360,8 @@ class Settings(val config: Config) { val nanomachineDisintegrationRange = config.getInt("nanomachines.disintegrationRange") max 0 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 diff --git a/src/main/scala/li/cil/oc/common/nanomachines/ControllerImpl.scala b/src/main/scala/li/cil/oc/common/nanomachines/ControllerImpl.scala index 695a3ecbd..0743c05e6 100644 --- a/src/main/scala/li/cil/oc/common/nanomachines/ControllerImpl.scala +++ b/src/main/scala/li/cil/oc/common/nanomachines/ControllerImpl.scala @@ -9,8 +9,10 @@ import li.cil.oc.Settings import li.cil.oc.api import li.cil.oc.api.nanomachines.Behavior 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.WirelessEndpoint +import li.cil.oc.integration.util.DamageSourceWithRandomCause import li.cil.oc.server.PacketSender import li.cil.oc.util.BlockPosition import li.cil.oc.util.ExtendedNBT._ @@ -32,6 +34,10 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE final val MaxSenderDistance = 2f final val FullSyncInterval = 20 * 60 + final val OverloadDamage = new DamageSourceWithRandomCause("oc.nanomachinesOverload", 3). + setDamageBypassesArmor(). + setDamageIsAbsolute() + var uuid = UUID.randomUUID.toString var responsePort = 0 var storedEnergy = Settings.get.bufferNanomachines * 0.25 @@ -154,7 +160,7 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE } override def getActiveBehaviors: lang.Iterable[Behavior] = configuration.synchronized { - cleanActiveBehaviors() + cleanActiveBehaviors(DisableReason.InputChanged) activeBehaviors } @@ -192,12 +198,15 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE return } - val hasPower = getLocalBuffer > 0 || Settings.get.ignorePower + var hasPower = getLocalBuffer > 0 || Settings.get.ignorePower lazy val active = getActiveBehaviors.toIterable // Wrap once. lazy val activeInputs = configuration.triggers.count(_.isActive) 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()) } @@ -212,8 +221,7 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE val overload = activeInputs - getSafeInputCount if (!player.capabilities.isCreativeMode && overload > 0 && player.getEntityWorld.getTotalWorldTime % 20 == 0) { - player.setHealth(player.getHealth - overload) - player.performHurtAnimation() + player.attackEntityFrom(OverloadDamage, overload) } } @@ -249,7 +257,7 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE configuration.triggers(index).isActive = false activeBehaviorsDirty = true } - cleanActiveBehaviors() + cleanActiveBehaviors(DisableReason.Default) } } @@ -283,7 +291,7 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE private def isServer = !isClient - private def cleanActiveBehaviors(): Unit = { + private def cleanActiveBehaviors(reason: DisableReason): Unit = { if (activeBehaviorsDirty) { configuration.synchronized(if (activeBehaviorsDirty) { val newBehaviors = configuration.behaviors.filter(_.isActive).map(_.behavior) @@ -293,7 +301,7 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE activeBehaviors ++= newBehaviors activeBehaviorsDirty = false addedBehaviors.foreach(_.onEnable()) - removedBehaviors.foreach(_.onDisable()) + removedBehaviors.foreach(_.onDisable(reason)) if (isServer) { PacketSender.sendNanomachineInputs(player) diff --git a/src/main/scala/li/cil/oc/common/nanomachines/NeuralNetwork.scala b/src/main/scala/li/cil/oc/common/nanomachines/NeuralNetwork.scala index 6d1503e1c..3731e418f 100644 --- a/src/main/scala/li/cil/oc/common/nanomachines/NeuralNetwork.scala +++ b/src/main/scala/li/cil/oc/common/nanomachines/NeuralNetwork.scala @@ -55,8 +55,8 @@ class NeuralNetwork(controller: ControllerImpl) extends Persistable { val rng = new Random(controller.player.getEntityWorld.rand.nextInt()) def connect[Sink <: ConnectorNeuron, Source <: Neuron](sinks: Iterable[Sink], sources: mutable.ArrayBuffer[Source]): Unit = { - val sinkPool = sinks.toBuffer - rng.shuffle(sinkPool) + // Shuffle sink list to give each entry the same chance. + val sinkPool = rng.shuffle(sinks.toBuffer) for (sink <- sinkPool if sources.nonEmpty) { for (n <- 0 to rng.nextInt(Settings.get.nanomachineMaxInputs) if sources.nonEmpty) { 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. val sourcePool = mutable.ArrayBuffer.fill(Settings.get.nanomachineMaxOutputs)(triggers.map(_.asInstanceOf[Neuron])).flatten connect(connectors, sourcePool) diff --git a/src/main/scala/li/cil/oc/common/nanomachines/provider/DisintegrationProvider.scala b/src/main/scala/li/cil/oc/common/nanomachines/provider/DisintegrationProvider.scala index 31043d234..d56d5fb2b 100644 --- a/src/main/scala/li/cil/oc/common/nanomachines/provider/DisintegrationProvider.scala +++ b/src/main/scala/li/cil/oc/common/nanomachines/provider/DisintegrationProvider.scala @@ -3,6 +3,7 @@ package li.cil.oc.common.nanomachines.provider import cpw.mods.fml.common.eventhandler.Event import li.cil.oc.Settings 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.ExtendedWorld._ @@ -28,7 +29,7 @@ object DisintegrationProvider extends ScalaProvider("c4e7e3c2-8069-4fbb-b08e-74b // Note: intentionally not overriding getNameHint. Gotta find this one manually! - override def onDisable(): Unit = { + override def onDisable(reason: DisableReason): Unit = { val world = player.getEntityWorld for (pos <- breakingMap.keys) { world.destroyBlockInWorldPartially(pos.hashCode(), pos, -1) diff --git a/src/main/scala/li/cil/oc/common/nanomachines/provider/HungryProvider.scala b/src/main/scala/li/cil/oc/common/nanomachines/provider/HungryProvider.scala new file mode 100644 index 000000000..bf7d52b01 --- /dev/null +++ b/src/main/scala/li/cil/oc/common/nanomachines/provider/HungryProvider.scala @@ -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) + } + } + } + +} diff --git a/src/main/scala/li/cil/oc/common/nanomachines/provider/PotionProvider.scala b/src/main/scala/li/cil/oc/common/nanomachines/provider/PotionProvider.scala index 45affc130..2b1667988 100644 --- a/src/main/scala/li/cil/oc/common/nanomachines/provider/PotionProvider.scala +++ b/src/main/scala/li/cil/oc/common/nanomachines/provider/PotionProvider.scala @@ -3,6 +3,7 @@ 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 net.minecraft.entity.player.EntityPlayer import net.minecraft.nbt.NBTTagCompound @@ -51,9 +52,7 @@ object PotionProvider extends ScalaProvider("c29e4eec-5a46-479a-9b3d-ad0f06da784 override def getNameHint: String = potion.getName.stripPrefix("potion.") - override def onEnable(): Unit = {} - - override def onDisable(): Unit = { + override def onDisable(reason: DisableReason): Unit = { player.removePotionEffect(potion.id) } diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala b/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala index 6eadc5d2c..5efc6a024 100644 --- a/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala +++ b/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala @@ -29,6 +29,7 @@ import li.cil.oc.common.item.Delegator import li.cil.oc.common.item.RedstoneCard import li.cil.oc.common.item.Tablet 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.ParticleProvider import li.cil.oc.common.nanomachines.provider.PotionProvider @@ -253,6 +254,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.Nanomachines.addProvider(DisintegrationProvider) + api.Nanomachines.addProvider(HungryProvider) api.Nanomachines.addProvider(ParticleProvider) api.Nanomachines.addProvider(PotionProvider) api.Nanomachines.addProvider(MagnetProvider) diff --git a/src/main/scala/li/cil/oc/integration/util/DamageSourceWithRandomCause.scala b/src/main/scala/li/cil/oc/integration/util/DamageSourceWithRandomCause.scala new file mode 100644 index 000000000..46349d70a --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/util/DamageSourceWithRandomCause.scala @@ -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 func_151519_b(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.func_145748_c_, damager.func_145748_c_) + else + new ChatComponentTranslation(format, damagee.func_145748_c_) + } +}