mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-13 17:28:52 -04:00
Merge branch 'master-MC1.7.10' of github.com:MightyPirates/OpenComputers into master-MC1.8
Conflicts: build.properties src/main/scala/li/cil/oc/client/Proxy.scala src/main/scala/li/cil/oc/client/Textures.scala src/main/scala/li/cil/oc/common/PacketBuilder.scala src/main/scala/li/cil/oc/common/init/Items.scala src/main/scala/li/cil/oc/common/tileentity/Charger.scala src/main/scala/li/cil/oc/server/agent/Player.scala src/main/scala/li/cil/oc/util/BlockPosition.scala src/main/scala/li/cil/oc/util/ExtendedWorld.scala
This commit is contained in:
commit
cb433d3b01
@ -25,7 +25,7 @@ This mod is [licensed under the **MIT license**](https://github.com/MightyPirate
|
||||
If you would like to contribute better textures for certain items or blocks, feel free to pull-request them. If you would like to contribute *alternative* textures, make it a resource pack, and post it on the forums, for example.
|
||||
3. **Documentation**
|
||||
Help with keeping the [wiki][] up to date would be *really* appreciated. If you notice anything amiss and know better, fix it. If you don't ask someone who does, then fix it. If you had a question answered, consider adding that information somewhere in the wiki where you would have expected to find that information.
|
||||
There are also the [files containing the ingame help][manpages], which could probably be much better than they are right now. Improvements to them, and new ones (e.g. for the libraries, such as `text` or `sides`) would help a lot. Thanks!
|
||||
There are also the files containing the ingame help [for programs][manpages] and [for blocks and items][manual], which could probably be much better than they are right now. Improvements to them, and new ones (e.g. for the libraries, such as `text` or `sides`) would help a lot. Thanks!
|
||||
4. **Robot Names**
|
||||
Robots get a random name when placed (unless set with an Anvil). The list the names are chose from [can be found here][robot names]. Feel free to pull request additional names! *However*: since the list has grown to a considerable length already, here are the two basic criteria for new names: it must either be a real or fictional robot, or an AI that at least *appears* to be self-aware.
|
||||
|
||||
@ -99,7 +99,8 @@ In the case you wish to use Eclipse rather than IntelliJ IDEA, the process is mo
|
||||
[jenkins]: http://ci.cil.li/
|
||||
[localizations]: https://github.com/MightyPirates/OpenComputers/tree/master-MC1.7.10/src/main/resources/assets/opencomputers/lang
|
||||
[loot]: https://github.com/MightyPirates/OpenComputers/tree/master-MC1.7.10/src/main/resources/assets/opencomputers/loot
|
||||
[manpages]: https://github.com/MightyPirates/OpenComputers/tree/master-MC1.7.10/src/main/resources/assets/opencomputers/lua/rom/usr/man
|
||||
[manpages]: https://github.com/MightyPirates/OpenComputers/tree/master-MC1.7.10/src/main/resources/assets/opencomputers/loot/OpenOS/usr/man
|
||||
[manual]: https://github.com/MightyPirates/OpenComputers/tree/master-MC1.7.10/src/main/resources/assets/opencomputers/doc
|
||||
[mcf]: http://www.minecraftforum.net/topic/2201440-opencomputers-v122/
|
||||
[pack.mcmeta]: https://github.com/MightyPirates/OpenComputers/blob/master-MC1.7.10/src/main/resources/pack.mcmeta
|
||||
[releases]: https://github.com/MightyPirates/OpenComputers/releases
|
||||
|
BIN
assets/items.psd
BIN
assets/items.psd
Binary file not shown.
@ -106,7 +106,7 @@ repositories {
|
||||
}
|
||||
maven {
|
||||
name = "dmodoomsirius"
|
||||
url = "http://ci.dmodoomsirius.me/maven/"
|
||||
url = "http://api.dmodoomsirius.me/"
|
||||
}
|
||||
maven {
|
||||
name = "ue"
|
||||
@ -204,7 +204,7 @@ dependencies {
|
||||
provided "mcp.mobius.waila:Waila:${config.waila.version}_${config.minecraft.version}:dev"
|
||||
provided "net.industrial-craft:industrialcraft-2:${config.ic2.version}:dev"
|
||||
provided "net.sengir.forestry:forestry_${config.minecraft.version}:${config.forestry.version}:dev"
|
||||
provided "notenoughkeys:NeK:${config.minecraft.version}-${config.nek.version}:deobf-dev"
|
||||
provided "dev.modwarriors.notenoughkeys:NotEnoughKeys:${config.minecraft.version}-${config.nek.version}:deobf-dev"
|
||||
provided "qmunity:QmunityLib:${config.qmunitylib.version}:deobf"
|
||||
provided "tmech:TMechworks:${config.minecraft.version}-${config.tmech.version}:deobf"
|
||||
provided ("mrtjp:ProjectRed:${config.projred.version}:dev") {
|
||||
|
@ -33,7 +33,7 @@ mekanism.version=7.1.2
|
||||
mfr.cf=2229/626
|
||||
mfr.version=[1.7.10]2.8.0RC8-86
|
||||
nei.version=1.0.5.82
|
||||
nek.version=1.0.0b2dev
|
||||
nek.version=2.0.0b4
|
||||
poweradvantage.version=1.2.0
|
||||
projred.version=1.7.10-4.6.2.82
|
||||
qmunitylib.version=0.1.105
|
||||
|
@ -12,13 +12,14 @@ import li.cil.oc.api.detail.*;
|
||||
*/
|
||||
public class API {
|
||||
public static final String ID_OWNER = "OpenComputers|Core";
|
||||
public static final String VERSION = "5.5.4";
|
||||
public static final String VERSION = "5.5.5";
|
||||
|
||||
public static DriverAPI driver = null;
|
||||
public static FileSystemAPI fileSystem = null;
|
||||
public static ItemAPI items = null;
|
||||
public static MachineAPI machine = null;
|
||||
public static ManualAPI manual = null;
|
||||
public static NanomachinesAPI nanomachines = null;
|
||||
public static NetworkAPI network = null;
|
||||
|
||||
public static Config config = null;
|
||||
|
100
src/main/java/li/cil/oc/api/Nanomachines.java
Normal file
100
src/main/java/li/cil/oc/api/Nanomachines.java
Normal file
@ -0,0 +1,100 @@
|
||||
package li.cil.oc.api;
|
||||
|
||||
import li.cil.oc.api.nanomachines.BehaviorProvider;
|
||||
import li.cil.oc.api.nanomachines.Controller;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* This API allows interfacing with nanomachines.
|
||||
* <p/>
|
||||
* It allows registering custom behavior providers as well as querying for all
|
||||
* presently registered providers and getting a controller for a player.
|
||||
*/
|
||||
public class Nanomachines {
|
||||
/**
|
||||
* Register a new behavior provider.
|
||||
* <p/>
|
||||
* When a controller is reconfigured it will draw behaviors from all
|
||||
* registered providers and build a new random connection graph to
|
||||
* those behaviors.
|
||||
*
|
||||
* @param provider the provider to add.
|
||||
*/
|
||||
public static void addProvider(BehaviorProvider provider) {
|
||||
if (API.nanomachines != null)
|
||||
API.nanomachines.addProvider(provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all currently registered providers.
|
||||
*
|
||||
* @return the list of all currently registered providers.
|
||||
*/
|
||||
public static Iterable<BehaviorProvider> getProviders() {
|
||||
if (API.nanomachines != null)
|
||||
return API.nanomachines.getProviders();
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a player has a nanomachine controller installed.
|
||||
*
|
||||
* @param player the player to check for.
|
||||
* @return <tt>true</tt> if the player has a controller, <tt>false</tt> otherwise.
|
||||
*/
|
||||
public static boolean hasController(EntityPlayer player) {
|
||||
if (API.nanomachines != null)
|
||||
return API.nanomachines.hasController(player);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the nanomachine controller of the specified player.
|
||||
* <p/>
|
||||
* If the player has a controller installed, this will initialize the
|
||||
* controller if it has not already been loaded. If the player has no
|
||||
* controller, this will return <tt>null</tt>.
|
||||
*
|
||||
* @param player the player to get the controller for.
|
||||
* @return the controller for the specified player.
|
||||
*/
|
||||
public static Controller getController(EntityPlayer player) {
|
||||
if (API.nanomachines != null)
|
||||
return API.nanomachines.getController(player);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Install a controller for the specified player if it doesn't already
|
||||
* have one.
|
||||
* <p/>
|
||||
* This will also initialize the controller if it has not already been
|
||||
* initialized.
|
||||
*
|
||||
* @param player the player to install a nanomachine controller for.
|
||||
*/
|
||||
public static Controller installController(EntityPlayer player) {
|
||||
if (API.nanomachines != null)
|
||||
return API.nanomachines.installController(player);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall a controller from the specified player if it has one.
|
||||
* <p/>
|
||||
* This will disable all active behaviors before disposing the controller.
|
||||
*
|
||||
* @param player the player to uninstall a nanomachine controller from.
|
||||
*/
|
||||
public static void uninstallController(EntityPlayer player) {
|
||||
if (API.nanomachines != null)
|
||||
API.nanomachines.uninstallController(player);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
private Nanomachines() {
|
||||
}
|
||||
}
|
66
src/main/java/li/cil/oc/api/detail/NanomachinesAPI.java
Normal file
66
src/main/java/li/cil/oc/api/detail/NanomachinesAPI.java
Normal file
@ -0,0 +1,66 @@
|
||||
package li.cil.oc.api.detail;
|
||||
|
||||
import li.cil.oc.api.nanomachines.BehaviorProvider;
|
||||
import li.cil.oc.api.nanomachines.Controller;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
|
||||
public interface NanomachinesAPI {
|
||||
/**
|
||||
* Register a new behavior provider.
|
||||
* <p/>
|
||||
* When a controller is reconfigured it will draw behaviors from all
|
||||
* registered providers and build a new random connection graph to
|
||||
* those behaviors.
|
||||
*
|
||||
* @param provider the provider to add.
|
||||
*/
|
||||
void addProvider(BehaviorProvider provider);
|
||||
|
||||
/**
|
||||
* Get a list of all currently registered providers.
|
||||
*
|
||||
* @return the list of all currently registered providers.
|
||||
*/
|
||||
Iterable<BehaviorProvider> getProviders();
|
||||
|
||||
/**
|
||||
* Check whether a player has a nanomachine controller installed.
|
||||
*
|
||||
* @param player the player to check for.
|
||||
* @return <tt>true</tt> if the player has a controller, <tt>false</tt> otherwise.
|
||||
*/
|
||||
boolean hasController(EntityPlayer player);
|
||||
|
||||
/**
|
||||
* Get the nanomachine controller of the specified player.
|
||||
* <p/>
|
||||
* If the player has a controller installed, this will initialize the
|
||||
* controller if it has not already been loaded. If the player has no
|
||||
* controller, this will return <tt>null</tt>.
|
||||
*
|
||||
* @param player the player to get the controller for.
|
||||
* @return the controller for the specified player.
|
||||
*/
|
||||
Controller getController(EntityPlayer player);
|
||||
|
||||
/**
|
||||
* Install a controller for the specified player if it doesn't already
|
||||
* have one.
|
||||
* <p/>
|
||||
* This will also initialize the controller if it has not already been
|
||||
* initialized.
|
||||
*
|
||||
* @param player the player to install a nanomachine controller for.
|
||||
* @return the controller for the specified player.
|
||||
*/
|
||||
Controller installController(EntityPlayer player);
|
||||
|
||||
/**
|
||||
* Uninstall a controller from the specified player if it has one.
|
||||
* <p/>
|
||||
* This will disable all active behaviors before disposing the controller.
|
||||
*
|
||||
* @param player the player to uninstall a nanomachine controller from.
|
||||
*/
|
||||
void uninstallController(EntityPlayer player);
|
||||
}
|
50
src/main/java/li/cil/oc/api/nanomachines/Behavior.java
Normal file
50
src/main/java/li/cil/oc/api/nanomachines/Behavior.java
Normal file
@ -0,0 +1,50 @@
|
||||
package li.cil.oc.api.nanomachines;
|
||||
|
||||
/**
|
||||
* Implemented by single behaviors.
|
||||
* <p/>
|
||||
* If you need a reference to the player this behavior applies to (which you'll
|
||||
* probably usually want to have), pass it along from {@link BehaviorProvider#createBehavior}.
|
||||
*/
|
||||
public interface Behavior {
|
||||
/**
|
||||
* A short name / description of this behavior.
|
||||
* <p/>
|
||||
* You can <em>not</em> use commas (<tt>,</tt>) or double quotes (<tt>"</tt>)
|
||||
* in the returned string. If you do, they'll automatically be replaced with
|
||||
* underscores.
|
||||
* <p/>
|
||||
* This is entirely optional and may even return <tt>null</tt>. It is made
|
||||
* accessible via the controller's wireless protocol, to allow better
|
||||
* automating reconfigurations / determining input mappings. In some cases
|
||||
* you may not wish to make this possible, in those cases return <tt>null</tt>
|
||||
* or a random string.
|
||||
* <p/>
|
||||
* Again, you can return whatever you like here, it's not used in mod internal
|
||||
* logic, but only provided to ingame devices as a hint to make configuring
|
||||
* nanomachines a little easier.
|
||||
*
|
||||
* @return the name to provide for this behavior, if any.
|
||||
*/
|
||||
String getNameHint();
|
||||
|
||||
/**
|
||||
* Called when this behavior becomes active because all its required inputs
|
||||
* are now satisfied.
|
||||
* <p/>
|
||||
* Use this to initialize permanent effects.
|
||||
*/
|
||||
void onEnable();
|
||||
|
||||
/**
|
||||
* Called when this behavior becomes inactive.
|
||||
* <p/>
|
||||
* Use this to remove permanent effects.
|
||||
*/
|
||||
void onDisable();
|
||||
|
||||
/**
|
||||
* Called each tick while this behavior is active.
|
||||
*/
|
||||
void update();
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package li.cil.oc.api.nanomachines;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
/**
|
||||
* Implemented by providers for behaviors.
|
||||
* <p/>
|
||||
* You may implement one provider for each of your behaviors, or one provider
|
||||
* for all of your behaviors; it really doesn't matter. This just allows for
|
||||
* some logical grouping of behaviors, where desired.
|
||||
* <p/>
|
||||
* Each behavior provider must be capable or serializing the behaviors it
|
||||
* creates, and re-create the behavior from its serialized form. It will
|
||||
* not be given any hints as to whether a provided tag was originally
|
||||
* produced by it, so you should add a sufficiently unique marker to the
|
||||
* output NBT to allow identification later on. I recommend generating a
|
||||
* UUID once, and using that. This is necessary to both save and restore
|
||||
* neural connection state between saves without breaking the state when
|
||||
* new behaviors are added, as well as to send states to the client.
|
||||
*/
|
||||
public interface BehaviorProvider {
|
||||
/**
|
||||
* Create all behaviors valid for the specified player.
|
||||
* <p/>
|
||||
* Note that this is only called on the server side when reconfiguring
|
||||
* nanomachines. If you have a behavior that actually acts client-only,
|
||||
* you still need to return it here, as it will be synchronized to the
|
||||
* client using {@link #writeToNBT} and {@link #readFromNBT}.
|
||||
*
|
||||
* @param player the player the behaviors should be created for.
|
||||
* @return list of new behaviors, may be <tt>null</tt>.
|
||||
*/
|
||||
Iterable<Behavior> createBehaviors(EntityPlayer player);
|
||||
|
||||
/**
|
||||
* Write a behavior to NBT.
|
||||
* <p/>
|
||||
* This will only be called for behaviors originally created by this provider.
|
||||
* <p/>
|
||||
* This will only be called on the server. All behaviors not saved will be
|
||||
* lost when loading again, they will <em>not</em> be regenerated using
|
||||
* {@link #createBehaviors}, so make sure to save all your behaviors.
|
||||
*
|
||||
* @param behavior the behavior to serialize.
|
||||
* @return the serialized representation of the specified behavior.
|
||||
*/
|
||||
NBTTagCompound writeToNBT(Behavior behavior);
|
||||
|
||||
/**
|
||||
* Restore a behavior from NBT.
|
||||
* <p/>
|
||||
* You are <em>not</em> guaranteed that his nbt belongs to a behavior
|
||||
* created by this provider! If the NBT cannot be handled, return
|
||||
* <tt>null</tt>.
|
||||
* <p/>
|
||||
* This is called both on the server and the client; on the server it
|
||||
* is called when restoring a saved player, on the client when
|
||||
* synchronizing a configuration.
|
||||
*
|
||||
* @param player the player the behaviors should be created for.
|
||||
* @param nbt the tag to restore the behavior from.
|
||||
* @return the restored behavior, or <tt>null</tt> if unhandled.
|
||||
*/
|
||||
Behavior readFromNBT(EntityPlayer player, NBTTagCompound nbt);
|
||||
}
|
116
src/main/java/li/cil/oc/api/nanomachines/Controller.java
Normal file
116
src/main/java/li/cil/oc/api/nanomachines/Controller.java
Normal file
@ -0,0 +1,116 @@
|
||||
package li.cil.oc.api.nanomachines;
|
||||
|
||||
/**
|
||||
* The nanomachine controller is responsible for keeping track of the current
|
||||
* layout of neural connections (i.e. how nanomachine "inputs" connect to
|
||||
* behaviors, directly or indirectly).
|
||||
* <p/>
|
||||
* Each input can connect to one or more nodes. A node can either be a
|
||||
* behavior, or an indirect connection, which in turn is connected to one
|
||||
* or more behaviors (there is at maximum one layer of indirection). Each
|
||||
* indirection may trigger one or more behaviors, but may also require one
|
||||
* or more inputs to activate its outputs.
|
||||
* <p/>
|
||||
* Each node, input or indirection, will only connect to one or two other
|
||||
* nodes, to keep randomization at a somewhat manageable level, but to still
|
||||
* allow for some optimization by re-rolling the connections.
|
||||
* <p/>
|
||||
* This interface is not meant to be implemented externally. To get a reference
|
||||
* to a controller, use {@link li.cil.oc.api.Nanomachines#getController}.
|
||||
*/
|
||||
public interface Controller {
|
||||
/**
|
||||
* Reconfigure the neural connections managed by this controller. This
|
||||
* will lead to the system being unavailable for a short while, in which
|
||||
* the neural connections are rebuilt in a new configuration. In addition,
|
||||
* some debuffs will be applied to the player.
|
||||
* <p/>
|
||||
* This will reset all inputs to disabled and deactivate all previously
|
||||
* active behaviors.
|
||||
*
|
||||
* @return the controller itself, for chaining / convenience.
|
||||
*/
|
||||
Controller reconfigure();
|
||||
|
||||
/**
|
||||
* Get the number of inputs available.
|
||||
* <p/>
|
||||
* This number depends on the total number of behaviors available, to keep
|
||||
* randomization at a manageable level. It is computed internally and
|
||||
* based on a configuration value.
|
||||
*
|
||||
* @return the total number of available inputs.
|
||||
*/
|
||||
int getTotalInputCount();
|
||||
|
||||
/**
|
||||
* Get the total number of inputs that may be active at the same time
|
||||
* before negative effects are applied to the player.
|
||||
* <p/>
|
||||
* The number of active inputs may exceed this value, but this will
|
||||
* have negative effects on the player.
|
||||
*
|
||||
* @return the number of inputs that may be active at a time.
|
||||
*/
|
||||
int getSafeInputCount();
|
||||
|
||||
/**
|
||||
* Get whether the input with the specified index is active.
|
||||
*
|
||||
* @param index the input index.
|
||||
* @return whether the input is active.
|
||||
* @throws IndexOutOfBoundsException if <code>index < 0</code> or <code>index >= getInputCount</code>.
|
||||
*/
|
||||
boolean getInput(int index);
|
||||
|
||||
/**
|
||||
* Set the state of the input with the specified index.
|
||||
*
|
||||
* @param index the input index.
|
||||
* @param value whether the input should be active.
|
||||
* @throws IndexOutOfBoundsException if <code>index < 0</code> or <code>index >= getInputCount</code>.
|
||||
*/
|
||||
void setInput(int index, boolean value);
|
||||
|
||||
/**
|
||||
* Get the list of currently active behaviors, based on the current input states.
|
||||
* <p/>
|
||||
* Note that behaviors may behave differently depending on how many active
|
||||
* inputs they have. Behaviors in the returned list will have at least one
|
||||
* active input.
|
||||
*
|
||||
* @return the list of currently active behaviors. Never <tt>null</tt>.
|
||||
*/
|
||||
Iterable<Behavior> getActiveBehaviors();
|
||||
|
||||
/**
|
||||
* Get the number of active inputs for the specified behavior.
|
||||
*
|
||||
* @param behavior the behavior to get the number of inputs for.
|
||||
* @return the number of inputs active for the specified behavior.
|
||||
*/
|
||||
int getInputCount(Behavior behavior);
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
/**
|
||||
* The amount of energy stored by this nanomachine controller.
|
||||
*/
|
||||
double getLocalBuffer();
|
||||
|
||||
/**
|
||||
* The maximum amount of energy stored by this nanomachine controller.
|
||||
*/
|
||||
double getLocalBufferSize();
|
||||
|
||||
/**
|
||||
* Try to apply the specified delta to the controller's buffer.
|
||||
* <p/>
|
||||
* A negative value will drain energy from the buffer, a positive value
|
||||
* will inject energy into the buffer.
|
||||
*
|
||||
* @param delta the amount of energy to consume or store.
|
||||
* @return the remainder of the delta that could not be applied.
|
||||
*/
|
||||
double changeBuffer(double delta);
|
||||
}
|
@ -100,6 +100,12 @@ opencomputers {
|
||||
|
||||
# The radius in which computer beeps can be heard.
|
||||
beepRadius: 16
|
||||
|
||||
# Position of the power indicator for nanomachines, by default left to the
|
||||
# player's health, specified by negative values. Values in [0, 1) will be
|
||||
# treated as relative positions, values in [1, inf) will be treated as
|
||||
# absolute positions.
|
||||
nanomachineHudPos: [-1, -1]
|
||||
}
|
||||
|
||||
# Computer related settings, concerns server performance and security.
|
||||
@ -566,6 +572,10 @@ opencomputers {
|
||||
|
||||
# The internal buffer size of the hover boots.
|
||||
hoverBoots: 15000.0
|
||||
|
||||
# Amount of energy stored by nanomachines. Yeah, I also don't know
|
||||
# where all that energy is stored. It's quite fascinating.
|
||||
nanomachines: 100000
|
||||
}
|
||||
|
||||
# Default "costs", i.e. how much energy certain operations consume.
|
||||
@ -771,6 +781,12 @@ opencomputers {
|
||||
# Energy required for one transposer operation (regardless of the number
|
||||
# of items / fluid volume moved).
|
||||
transposer: 1
|
||||
|
||||
# Energy consumed per tick per active input node by nanomachines.
|
||||
nanomachineInput: 0.5
|
||||
|
||||
# Energy consumed when reconfiguring nanomachines.
|
||||
nanomachinesReconfigure: 5000
|
||||
}
|
||||
|
||||
# The rate at which different blocks accept external power. All of these
|
||||
@ -958,6 +974,67 @@ opencomputers {
|
||||
relayAmountUpgrade: 1
|
||||
}
|
||||
|
||||
# Nanomachine related values. Note that most of these are relative, as
|
||||
# they scale with the number of total effects controlled by nanomachines,
|
||||
# which may very much vary depending on other mods used together with OC.
|
||||
# To configure this, you'll need to know how this works a bit more in-
|
||||
# depth, so here goes: there are three layers, the behavior layer, the
|
||||
# connector layer, and the input layer. The behavior layer consists of
|
||||
# one node for each behavior provided by registered providers (by default
|
||||
# these will be potion effects and a few other things). The connector
|
||||
# layer merely serves to mix things up a little. The input layer is made
|
||||
# up from nodes that can be triggered by the nanomachines. Each connector
|
||||
# node has behavior nodes it outputs to, and gets signals from input nodes.
|
||||
# Behavior nodes get signals from both the connector and the input layers.
|
||||
# Reconfiguring builds up random connections. Some behaviors change what
|
||||
# they do based on the number of active inputs (e.g. potion effects will
|
||||
# increase their amplification value).
|
||||
nanomachines {
|
||||
# The relative amount of triggers available based on the number of
|
||||
# available behaviors (such as different potion effects). For example,
|
||||
# if there are a total of 10 behaviors available, 0.5 means there will
|
||||
# be 5 trigger inputs, triggers being the inputs that can be activated
|
||||
# via nanomachines.
|
||||
triggerQuota: 0.5
|
||||
|
||||
# The relative number of connectors based on the number of available
|
||||
# behaviors (see triggerQuota).
|
||||
connectorQuota: 0.2
|
||||
|
||||
# The maximum number of inputs for each node of the "neural network"
|
||||
# nanomachines connect to. I.e. each behavior node and connector node
|
||||
# may only have up to this many inputs.
|
||||
maxInputs: 2
|
||||
|
||||
# The maximum number of outputs for each node (see maxInputs).
|
||||
maxOutputs: 2
|
||||
|
||||
# How many input nodes may be active at the same time before negative
|
||||
# effects are applied to the player.
|
||||
safeInputCount: 2
|
||||
|
||||
# The time in seconds it takes to reconfigure the nanomachines. This is
|
||||
# to avoid spamming reconfigurations.
|
||||
reconfigureCooldown: 5
|
||||
|
||||
# Range of the item magnet behavior added for each active input.
|
||||
magnetRange: 8
|
||||
|
||||
# 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
|
||||
# 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.
|
||||
potionBlacklist: [
|
||||
"potion.heal",
|
||||
"potion.regeneration",
|
||||
"potion.invisibility",
|
||||
"potion.saturation"
|
||||
]
|
||||
}
|
||||
|
||||
# 3D printer related stuff.
|
||||
printer {
|
||||
# The maximum number of shape for a state of a 3D print allowed. This is
|
||||
|
@ -26,6 +26,7 @@ Keep in mind that some of these may not be available, depending on the recipe se
|
||||
* [Geolyzer](geolyzer.md)
|
||||
* [Motion Sensor](motionSensor.md)
|
||||
* [Redstone I/O](redstone.md)
|
||||
* [Transposer](transposer.md)
|
||||
* [Waypoint](waypoint.md)
|
||||
|
||||
## Assembly / Printing
|
||||
|
@ -0,0 +1,69 @@
|
||||
# Headline with more lines [with link](redirect1.md) and *some* more
|
||||
|
||||
This is some test text for the subset of Markdown supported by the planned ingame documentation system for OpenComputers.
|
||||

|
||||

|
||||
*This* is *italic* text, ~~strikethrough~~ maybe abc-ter **some** text **in bold**. Is _this underlined_? Oh, no, _it's also italic!_ Well, this [a link](../index.md).
|
||||

|
||||
## Smaller headline [also with *link* but this __one__ longer](../block/adapter.md)
|
||||
|
||||

|
||||
|
||||
some text directly above the item stack renderer to test spacing
|
||||

|
||||
some text directly below the item stack renderer to test spacing
|
||||
|
||||
This is *italic
|
||||
over two* lines. But *this ... no *this is* **_bold italic_** *text*.
|
||||
|
||||
### even smaller
|
||||
|
||||
*not italic *because ** why would it be*eh
|
||||
|
||||
`test for code`
|
||||
`that's not code yet`
|
||||
`function f(a)`
|
||||
` testingIndent(a)`
|
||||
` do`
|
||||
` lalala()`
|
||||
` end`
|
||||
`end`
|
||||
yeah, line spacing is a bit low, but otherwise too little text fits on one screen.
|
||||
this is some `code` that's inline. then `some more CODE that` line wraps and so on.
|
||||
|
||||
isn't*.
|
||||
|
||||
# not a header
|
||||
|
||||
* this is a list item and the text that will be wrapped will be indented appropriately
|
||||
- this should also `work for code rendered text, if it doesn't i` will be a sad person
|
||||
|
||||
asdasd  qweqwe
|
||||
|
||||
And finally, [this is a link!](https://avatars1.githubusercontent.com/u/514903).
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
wrap testing
|
||||
12345678901234567890.1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
`123456789012345678901234567890.12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890`
|
||||
|
||||
* 12345678901234567890.1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
- `123456789012345678901234567890.12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890`
|
||||
|
||||
this is a test for anan inline image kakakakalalsd 123 as
|
||||
|
||||
this is a test for an
|
||||
an image with a break after it
|
||||
|
||||
this is a test for an
|
||||

|
||||
an image between two lines
|
||||
|
||||
this is a test for an
|
||||
|
||||

|
||||
|
||||
an image between two blank lines
|
@ -2,4 +2,6 @@
|
||||
|
||||

|
||||
|
||||
Encountered only when using hard-mode recipes, it is used to etch [circuit boards](circuitBoard.md) before crafting [printed circuit boards](printedCircuitBoard.md).
|
||||
This tasty [citation needed] concoction can be consumed if you ever feel the need for some... fun. Or ruining your digestive tract. Or both. It can also serve as ingredient in other, more useful items.
|
||||
|
||||
When using hard-mode recipes, it is used to etch [circuit boards](circuitBoard.md) before crafting [printed circuit boards](printedCircuitBoard.md).
|
||||
|
@ -87,3 +87,4 @@ Keep in mind that some of these may not be available, depending on the recipe se
|
||||
|
||||
## Other
|
||||
* [Hover Boots](hoverBoots.md)
|
||||
* [Nanomachines](nanomachines.md)
|
||||
|
@ -0,0 +1,29 @@
|
||||
# Nanomachines
|
||||
|
||||

|
||||
|
||||
These little guys interface with your nervous system to make you harder, better, faster, stronger, or kill you. Sometimes both at the same time! Put simply, nanomachines provide a power driven system for applying buffs (and debuffs) to the player they reside in. To "install" nanomachines, eat them!
|
||||
|
||||
Once injected, a new power indicator in your HUD will indicate how much energy your nanomachines have left to work with. You can recharge them by standing near a [charger](../block/charger.md). The more use you make of the nanomachines, the more energy they'll consume.
|
||||
|
||||
Nanomachines provide a certain number of "inputs" that can be triggered, causing many different effects on the player, ranging from visual effects such as particles spawning near the player, to select potion effects and some more rare and special behaviors!
|
||||
|
||||
Which input triggers what effect depends on the current configuration of the nanomachines, the actual "connections" being random per configuration. This means you'll have to try enabling different inputs to see what they do. If you're unhappy with a configuration, you can always reconfigure your nanomachines. Beware that enabling too many inputs at a time has severe negative effects on you!
|
||||
|
||||
By default, the nanomachines will be on standby. You'll need to control them using wireless messages, so carrying a [tablet](tablet.md) with a [wireless network card](wlanCard.md) is strongly recommended. Nanomachines will only react to wireless signals emitted by devices no further than two meters away, but they will react to messages on any port, and from any device!
|
||||
|
||||
Nanomachines react to a simple, proprietary protocol: each packet must consist of multiple parts, the first of which is the "header" and must equal the string `nanomachines`. The second part must be the command name. Additional parts are parameters for the command. The following commands are available, formatted as `commandName(arg1, ...)`:
|
||||
|
||||
- `setResponsePort(port:number)` - Set the port nanomachines should send response messages to, for commands that have a response.
|
||||
- `dispose()` - Destroy all nanomachines currently in the player.
|
||||
- `reconfigure()` - Cause the nanomachines to enter a new configuration.
|
||||
- `getTotalInputCount()` - Request a message with the total number of available inputs.
|
||||
- `getSafeInputCount()` - Request a message with the number of *safe* inputs.
|
||||
- `getInput(index:number)` - Request a message with the current state of the input with the specified index.
|
||||
- `setInput(index:number, value:boolean)` - Set the state of the input with the specified index to the specified value.
|
||||
- `getActiveEffects()` - Request a list of active effects. Note that some effects may not show up in this list.
|
||||
- `getPowerState()` - Request a message with the currently stored and maximum stored energy of the nanomachines.
|
||||
|
||||
For example, in OpenOS:
|
||||
- `component.modem.broadcast(1, "nanomachines", "setInput", 1, true)` will enable the first input.
|
||||
- `component.modem.broadcast(1, "nanomachines", "reconfigure")` will reconfigure the nanomachines.
|
@ -26,6 +26,7 @@
|
||||
* [Геоанализатор](geolyzer.md)
|
||||
* [Датчик движения](motionSensor.md)
|
||||
* [Редстоун-I/O](redstone.md)
|
||||
* [Транспозер](transposer.md)
|
||||
* [Путевая точка](waypoint.md)
|
||||
|
||||
## Сборка / Печать
|
||||
|
@ -247,7 +247,7 @@ key.materialCosts=Materialkosten anzeigen
|
||||
# Item / Block Tooltips
|
||||
oc:tooltip.AccessPoint=Verhält sich wie ein Switch, aber empfängt zusätzlich Drahtlosnachrichten und leitet Pakete aus dem Festnetz drahtlos weiter.
|
||||
oc:tooltip.AbstractBusCard=Erlaubt es, LIP-Pakete des Abstrakten Busses von §fStargateTech 2§7 zu senden und zu empfangen.
|
||||
oc:tooltip.Acid=Eine hochgiftige Möchtegernflüssigkeit, wird üblicherweise nur von gewissen Piraten konsumiert. Dank ihrer korrosiven Eigenschaften ideal zum Bedrucken von Leiterplatten geeignet.
|
||||
oc:tooltip.Acid=Eine hochgiftige Möchtegernflüssigkeit, wird üblicherweise nur von gewissen Piraten konsumiert. Mag sich aber auch zu anderen Zwecken eignen.
|
||||
oc:tooltip.Adapter=Erlaubt es, Blöcke anzusteuern, die keine Komponentenblöcke sind, wie etwa reguläre Minecraft-Blöcke oder Blöcke anderer Mods.
|
||||
oc:tooltip.ALU=Zählt Zahlen zum Zeitvertreib. Klingt komisch, is aber so.
|
||||
oc:tooltip.Analyzer=Erlaubt es, Informationen über Blöcke anzuzeigen, wie zum Bleistift ihre §fAdresse§7 und ihren §fKomponentennamen§7.[nl] Erlaubt zudem, den Fehler anzuzeigen, der zu einem Computerabsturz geführt hat, falls der Computer nicht regulär heruntergefahren wurde.
|
||||
|
@ -100,6 +100,7 @@ item.oc.Microchip2.name=Microchip (Tier 3)
|
||||
item.oc.MicrocontrollerCase0.name=Microcontroller Case (Tier 1)
|
||||
item.oc.MicrocontrollerCase1.name=Microcontroller Case (Tier 2)
|
||||
item.oc.MicrocontrollerCase3.name=Microcontroller Case (Creative)
|
||||
item.oc.Nanomachines.name=Nanomachines
|
||||
item.oc.NetworkCard.name=Network Card
|
||||
item.oc.NumPad.name=Numeric Keypad
|
||||
item.oc.Present.name=A little something...
|
||||
@ -250,7 +251,7 @@ key.materialCosts=Show Material Costs
|
||||
# Item / Block Tooltips
|
||||
oc:tooltip.AccessPoint=Acts like a Switch, but additionally receives wireless packets and relays wired packets wirelessly.
|
||||
oc:tooltip.AbstractBusCard=Allows interacting with §fStargateTech 2§7's abstract bus by sending and receiving LIP packets.
|
||||
oc:tooltip.Acid=A highly toxic pseudo-liquid, usually only consumed by certain pirates. Thanks to its corrosive nature it is perfectly suited for etching circuit boards.
|
||||
oc:tooltip.Acid=A highly toxic pseudo-liquid, usually only consumed by certain pirates. May prove to be useful in other ways, too, however.
|
||||
oc:tooltip.Adapter=Used to control non-component blocks, such as vanilla blocks or blocks from other mods.
|
||||
oc:tooltip.ALU=Adds numbers so you don't have to. It might be better this way.
|
||||
oc:tooltip.Analyzer=Used to display information about blocks, such as their §faddress§7 and §fcomponent name§7.[nl] Also displays the error that caused a computer to crash if it did not shut down normally.
|
||||
@ -306,6 +307,7 @@ oc:tooltip.Microchip=The chip formerly known as Integrated Circuit. I have no id
|
||||
oc:tooltip.Microcontroller=Microcontrollers are computers boiled down to the essentials. They are intended to take care of very specific tasks, running only a single program that is provided on the EEPROM built into them.[nl] §cCan not connect to external components.§7
|
||||
oc:tooltip.MicrocontrollerCase=Base component for building microcontrollers. Place it into an assembler to add further components and assemble a microcontroller.
|
||||
oc:tooltip.MotionSensor=Can detect movement of nearby living beings. Requires clear line-of-sight.
|
||||
oc:tooltip.Nanomachines=Control unit and a bunch of nanomachines for ingestion, if you dare.
|
||||
oc:tooltip.NetworkCard=Allows distant computers connected by other blocks (such as cable) to communicate by sending messages to each other.
|
||||
oc:tooltip.PowerAcceptor=Energy conversion speed: §f%s/t§7
|
||||
oc:tooltip.PowerConverter.BuildCraft=§fBuildCraft MJ§7: §a%s:%s§7
|
||||
|
@ -384,6 +384,10 @@ end
|
||||
local args, options = shell.parse(...)
|
||||
local history = {}
|
||||
|
||||
local function escapeMagic(text)
|
||||
return text:gsub('[%(%)%.%%%+%-%*%?%[%^%$]', '%%%1')
|
||||
end
|
||||
|
||||
local function getMatchingPrograms(baseName)
|
||||
local result = {}
|
||||
-- TODO only matching files with .lua extension for now, might want to
|
||||
@ -391,7 +395,7 @@ local function getMatchingPrograms(baseName)
|
||||
if not baseName or #baseName == 0 then
|
||||
baseName = "^(.*)%.lua$"
|
||||
else
|
||||
baseName = "^(" .. baseName .. ".*)%.lua$"
|
||||
baseName = "^(" .. escapeMagic(baseName) .. ".*)%.lua$"
|
||||
end
|
||||
for basePath in string.gmatch(os.getenv("PATH"), "[^:]+") do
|
||||
for file in fs.list(basePath) do
|
||||
@ -404,7 +408,8 @@ local function getMatchingPrograms(baseName)
|
||||
return result
|
||||
end
|
||||
|
||||
local function getMatchingFiles(baseName)
|
||||
local function getMatchingFiles(partialPrefix, name)
|
||||
local baseName = shell.resolve(partialPrefix .. name)
|
||||
local result, basePath = {}
|
||||
-- note: we strip the trailing / to make it easier to navigate through
|
||||
-- directories using tab completion (since entering the / will then serve
|
||||
@ -416,12 +421,12 @@ local function getMatchingFiles(baseName)
|
||||
baseName = "^(.-)/?$"
|
||||
else
|
||||
basePath = fs.path(baseName) or "/"
|
||||
baseName = "^(" .. fs.name(baseName) .. ".-)/?$"
|
||||
baseName = "^(" .. escapeMagic(fs.name(baseName)) .. ".-)/?$"
|
||||
end
|
||||
for file in fs.list(basePath) do
|
||||
local match = file:match(baseName)
|
||||
if match then
|
||||
table.insert(result, fs.concat(basePath, match))
|
||||
table.insert(result, partialPrefix .. match)
|
||||
end
|
||||
end
|
||||
-- (cont.) but if there's only one match and it's a directory, *then* we
|
||||
@ -444,10 +449,20 @@ local function hintHandler(line, cursor)
|
||||
-- first part and no path, look for programs in the $PATH
|
||||
result = getMatchingPrograms(line)
|
||||
else -- just look normal files
|
||||
result = getMatchingFiles(shell.resolve(partial or line))
|
||||
local partialPrefix = (partial or line)
|
||||
local name = fs.name(partialPrefix)
|
||||
partialPrefix = partialPrefix:sub(1, -name:len() - 1)
|
||||
result = getMatchingFiles(partialPrefix, name)
|
||||
end
|
||||
local resultSuffix = ""
|
||||
if searchInPath then
|
||||
resultSuffix = " "
|
||||
elseif #result == 1 and result[1]:sub(-1) ~= '/' then
|
||||
resultSuffix = " "
|
||||
end
|
||||
prefix = prefix or ""
|
||||
for i = 1, #result do
|
||||
result[i] = (prefix or "") .. result[i] .. (searchInPath and " " or "")
|
||||
result[i] = prefix .. result[i] .. resultSuffix
|
||||
end
|
||||
table.sort(result)
|
||||
return result
|
||||
|
@ -15,6 +15,11 @@ manual {
|
||||
type: shapeless
|
||||
input: [book, "oc:circuitChip1"]
|
||||
}
|
||||
nanomachines {
|
||||
input: [["oc:chamelium", "oc:wlanCard", "oc:chamelium"]
|
||||
["oc:cpu2", "oc:materialAcid", "oc:ram1"]
|
||||
["oc:chamelium", "oc:capacitor", "oc:chamelium"]]
|
||||
}
|
||||
texturePicker {
|
||||
input: [[dyeBlack, dyeRed, dyeGreen]
|
||||
[dyeBlue, "oc:analyzer", dyePurple]
|
||||
@ -360,7 +365,10 @@ nuggetIron {
|
||||
output: 9
|
||||
}
|
||||
cuttingWire = false
|
||||
acid = false
|
||||
acid {
|
||||
type: shapeless
|
||||
input: [bucketWater, sugar, slimeball, fermentedSpiderEye, bone]
|
||||
}
|
||||
ingotIron {
|
||||
input: [[nuggetIron, nuggetIron, nuggetIron],
|
||||
[nuggetIron, nuggetIron, nuggetIron],
|
||||
|
@ -190,10 +190,6 @@ nuggetIron {
|
||||
cuttingWire {
|
||||
input: [[stickWood, nuggetIron, stickWood]]
|
||||
}
|
||||
acid {
|
||||
type: shapeless
|
||||
input: [bucketWater, sugar, slimeball, fermentedSpiderEye, bone]
|
||||
}
|
||||
disk {
|
||||
input: [["", nuggetIron, ""]
|
||||
[nuggetIron, "", nuggetIron]
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 213 B |
Binary file not shown.
After Width: | Height: | Size: 199 B |
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,5 @@
|
||||
{
|
||||
"animation": {
|
||||
"frametime": 4
|
||||
}
|
||||
}
|
@ -119,6 +119,7 @@ object Constants {
|
||||
final val MicrocontrollerCaseCreative = "microcontrollerCaseCreative"
|
||||
final val MicrocontrollerCaseTier1 = "microcontrollerCase1"
|
||||
final val MicrocontrollerCaseTier2 = "microcontrollerCase2"
|
||||
final val Nanomachines = "nanomachines"
|
||||
final val NavigationUpgrade = "navigationUpgrade"
|
||||
final val NetworkCard = "lanCard"
|
||||
final val NumPad = "numPad"
|
||||
|
@ -39,6 +39,13 @@ class Settings(val config: Config) {
|
||||
val beepSampleRate = config.getInt("client.beepSampleRate")
|
||||
val beepAmplitude = config.getInt("client.beepVolume") max 0 min Byte.MaxValue
|
||||
val beepRadius = config.getDouble("client.beepRadius").toFloat max 1 min 32
|
||||
val nanomachineHudPos = Array(config.getDoubleList("client.nanomachineHudPos"): _*) match {
|
||||
case Array(x, y) =>
|
||||
(x: Double, y: Double)
|
||||
case _ =>
|
||||
OpenComputers.log.warn("Bad number of HUD coordiantes, ignoring.")
|
||||
(-1.0, -1.0)
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
// computer
|
||||
@ -157,6 +164,7 @@ class Settings(val config: Config) {
|
||||
val bufferDrone = config.getDouble("power.buffer.drone") max 0
|
||||
val bufferMicrocontroller = config.getDouble("power.buffer.mcu") max 0
|
||||
val bufferHoverBoots = config.getDouble("power.buffer.hoverBoots") max 1
|
||||
val bufferNanomachines = config.getDouble("power.buffer.nanomachines") max 0
|
||||
|
||||
// power.cost
|
||||
val computerCost = config.getDouble("power.cost.computer") max 0
|
||||
@ -202,6 +210,8 @@ class Settings(val config: Config) {
|
||||
val dataCardComplexByte = config.getDouble("power.cost.dataCardComplexByte") max 0
|
||||
val dataCardAsymmetric = config.getDouble("power.cost.dataCardAsymmetric") max 0
|
||||
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
|
||||
|
||||
// power.rate
|
||||
val accessPointRate = config.getDouble("power.rate.accessPoint") max 0
|
||||
@ -307,7 +317,8 @@ class Settings(val config: Config) {
|
||||
val inputUsername = config.getBoolean("misc.inputUsername")
|
||||
val maxClipboard = config.getInt("misc.maxClipboard") max 0
|
||||
val maxNetworkPacketSize = config.getInt("misc.maxNetworkPacketSize") max 0
|
||||
val maxNetworkPacketParts = config.getInt("misc.maxNetworkPacketParts") max 0
|
||||
// Need at least 4 for nanomachine protocol. Because I can!
|
||||
val maxNetworkPacketParts = config.getInt("misc.maxNetworkPacketParts") max 4
|
||||
val maxOpenPorts = config.getInt("misc.maxOpenPorts") max 0
|
||||
val maxWirelessRange = config.getDouble("misc.maxWirelessRange") max 0
|
||||
val rTreeMaxEntries = 10
|
||||
@ -339,6 +350,18 @@ 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
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
// nanomachines
|
||||
val nanomachineTriggerQuota = config.getDouble("nanomachines.triggerQuota") max 0
|
||||
val nanomachineConnectorQuota = config.getDouble("nanomachines.connectorQuota") max 0
|
||||
val nanomachineMaxInputs = config.getInt("nanomachines.maxInputs") max 1
|
||||
val nanomachineMaxOutputs = config.getInt("nanomachines.maxOutputs") max 1
|
||||
val nanomachinesSafeInputCount = config.getDouble("nanomachines.safeInputCount") max 0 min 1
|
||||
val nanomachineReconfigureTimeout = config.getDouble("nanomachines.reconfigureCooldown") max 0
|
||||
val nanomachineMagnetRange = config.getDouble("nanomachines.magnetRange") max 0
|
||||
val nanomachineDisintegrationRange = config.getInt("nanomachines.disintegrationRange") max 0
|
||||
val nanomachinePotionBlacklist = config.getAnyRefList("nanomachines.potionBlacklist")
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
// printer
|
||||
val maxPrintComplexity = config.getInt("printer.maxShapes")
|
||||
|
@ -4,12 +4,14 @@ import java.io.EOFException
|
||||
|
||||
import li.cil.oc.Localization
|
||||
import li.cil.oc.Settings
|
||||
import li.cil.oc.api
|
||||
import li.cil.oc.api.component
|
||||
import li.cil.oc.api.event.FileSystemAccessEvent
|
||||
import li.cil.oc.client.renderer.PetRenderer
|
||||
import li.cil.oc.common.Loot
|
||||
import li.cil.oc.common.PacketType
|
||||
import li.cil.oc.common.container
|
||||
import li.cil.oc.common.nanomachines.ControllerImpl
|
||||
import li.cil.oc.common.tileentity._
|
||||
import li.cil.oc.common.tileentity.traits._
|
||||
import li.cil.oc.common.{PacketHandler => CommonPacketHandler}
|
||||
@ -60,6 +62,9 @@ object PacketHandler extends CommonPacketHandler {
|
||||
case PacketType.HologramTranslation => onHologramPositionOffsetY(p)
|
||||
case PacketType.HologramValues => onHologramValues(p)
|
||||
case PacketType.LootDisk => onLootDisk(p)
|
||||
case PacketType.NanomachinesConfiguration => onNanomachinesConfiguration(p)
|
||||
case PacketType.NanomachinesInputs => onNanomachinesInputs(p)
|
||||
case PacketType.NanomachinesPower => onNanomachinesPower(p)
|
||||
case PacketType.NetSplitterState => onNetSplitterState(p)
|
||||
case PacketType.ParticleEffect => onParticleEffect(p)
|
||||
case PacketType.PetVisibility => onPetVisibility(p)
|
||||
@ -283,6 +288,51 @@ object PacketHandler extends CommonPacketHandler {
|
||||
}
|
||||
}
|
||||
|
||||
def onNanomachinesConfiguration(p: PacketParser) = {
|
||||
p.readEntity[EntityPlayer]() match {
|
||||
case Some(player) =>
|
||||
val hasController = p.readBoolean()
|
||||
if (hasController) {
|
||||
api.Nanomachines.installController(player) match {
|
||||
case controller: ControllerImpl => controller.load(p.readNBT())
|
||||
case _ => // Wat.
|
||||
}
|
||||
}
|
||||
else {
|
||||
api.Nanomachines.uninstallController(player)
|
||||
}
|
||||
case _ => // Invalid packet.
|
||||
}
|
||||
}
|
||||
|
||||
def onNanomachinesInputs(p: PacketParser) = {
|
||||
p.readEntity[EntityPlayer]() match {
|
||||
case Some(player) => api.Nanomachines.getController(player) match {
|
||||
case controller: ControllerImpl =>
|
||||
val inputs = new Array[Byte](p.readInt())
|
||||
p.read(inputs)
|
||||
controller.configuration.synchronized {
|
||||
for ((value, index) <- inputs.zipWithIndex if index < controller.configuration.triggers.length) {
|
||||
controller.configuration.triggers(index).isActive = value == 1
|
||||
}
|
||||
controller.activeBehaviorsDirty = true
|
||||
}
|
||||
case _ => // Wat.
|
||||
}
|
||||
case _ => // Invalid packet.
|
||||
}
|
||||
}
|
||||
|
||||
def onNanomachinesPower(p: PacketParser) = {
|
||||
p.readEntity[EntityPlayer]() match {
|
||||
case Some(player) => api.Nanomachines.getController(player) match {
|
||||
case controller: ControllerImpl => controller.storedEnergy = p.readDouble()
|
||||
case _ => // Wat.
|
||||
}
|
||||
case _ => // Invalid packet.
|
||||
}
|
||||
}
|
||||
|
||||
def onNetSplitterState(p: PacketParser) =
|
||||
p.readTileEntity[NetSplitter]() match {
|
||||
case Some(t) =>
|
||||
|
@ -13,6 +13,8 @@ import li.cil.oc.client.renderer.entity.DroneRenderer
|
||||
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.init.Items
|
||||
import li.cil.oc.common.item.traits.Delegate
|
||||
import li.cil.oc.common.tileentity
|
||||
import li.cil.oc.common.tileentity.ServerRack
|
||||
@ -79,6 +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(PetRenderer)
|
||||
MinecraftForge.EVENT_BUS.register(ServerRack)
|
||||
MinecraftForge.EVENT_BUS.register(Sound)
|
||||
|
@ -47,6 +47,8 @@ object Textures {
|
||||
val ManualHome = L("manual_home")
|
||||
val ManualMissingItem = L("manual_missing_item")
|
||||
val ManualTab = L("manual_tab")
|
||||
val Nanomachines = L("nanomachines_power")
|
||||
val NanomachinesBar = L("nanomachines_power_bar")
|
||||
val Printer = L("printer")
|
||||
val PrinterInk = L("printer_ink")
|
||||
val PrinterMaterial = L("printer_material")
|
||||
|
@ -54,6 +54,8 @@ abstract class PacketBuilder(stream: OutputStream) extends DataOutputStream(stre
|
||||
|
||||
def sendToAllPlayers() = OpenComputers.channel.sendToAll(packet)
|
||||
|
||||
def sendToPlayersNearEntity(e: Entity, range: Option[Double] = None): Unit = sendToNearbyPlayers(e.getEntityWorld, e.posX, e.posY, e.posZ, range)
|
||||
|
||||
def sendToPlayersNearTileEntity(t: TileEntity, range: Option[Double] = None): Unit = sendToNearbyPlayers(t.getWorld, t.getPos.getX + 0.5, t.getPos.getY + 0.5, t.getPos.getZ + 0.5, range)
|
||||
|
||||
def sendToPlayersNearHost(host: EnvironmentHost, range: Option[Double] = None): Unit = sendToNearbyPlayers(host.world, host.xPosition, host.yPosition, host.zPosition, range)
|
||||
|
@ -22,6 +22,9 @@ object PacketType extends Enumeration {
|
||||
HologramTranslation,
|
||||
HologramValues,
|
||||
LootDisk,
|
||||
NanomachinesConfiguration,
|
||||
NanomachinesInputs,
|
||||
NanomachinesPower,
|
||||
NetSplitterState,
|
||||
ParticleEffect,
|
||||
PetVisibility, // Goes both ways.
|
||||
|
@ -73,6 +73,7 @@ class Proxy {
|
||||
api.API.fileSystem = fs.FileSystem
|
||||
api.API.items = Items
|
||||
api.API.machine = machine.Machine
|
||||
api.API.nanomachines = nanomachines.Nanomachines
|
||||
api.API.network = network.Network
|
||||
|
||||
api.API.config = Settings.get.config
|
||||
|
@ -18,7 +18,7 @@ object HoverBootsHandler {
|
||||
val hasHoverBoots = !player.isSneaking && equippedArmor(player).exists(stack => stack.getItem match {
|
||||
case boots: HoverBoots =>
|
||||
Settings.get.ignorePower || {
|
||||
if (player.onGround && !player.capabilities.isCreativeMode && player.worldObj.getTotalWorldTime % 20 == 0) {
|
||||
if (player.onGround && !player.capabilities.isCreativeMode && player.worldObj.getTotalWorldTime % Settings.get.tickFrequency == 0) {
|
||||
val velocity = player.motionX * player.motionX + player.motionY * player.motionY + player.motionZ * player.motionZ
|
||||
if (velocity > 0.015f) {
|
||||
boots.charge(stack, -Settings.get.hoverBootMove, simulate = false)
|
||||
|
@ -0,0 +1,146 @@
|
||||
package li.cil.oc.common.event
|
||||
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileOutputStream
|
||||
|
||||
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.nanomachines.ControllerImpl
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.ScaledResolution
|
||||
import net.minecraft.client.renderer.Tessellator
|
||||
import net.minecraft.entity.player.EntityPlayer
|
||||
import net.minecraft.nbt.CompressedStreamTools
|
||||
import net.minecraft.nbt.NBTTagCompound
|
||||
import net.minecraftforge.client.event.RenderGameOverlayEvent
|
||||
import net.minecraftforge.event.entity.living.LivingEvent
|
||||
import net.minecraftforge.event.entity.player.PlayerEvent
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
|
||||
|
||||
object NanomachinesEventHandler {
|
||||
|
||||
object Client {
|
||||
@SubscribeEvent
|
||||
def onRenderGameOverlay(e: RenderGameOverlayEvent.Post): Unit = {
|
||||
if (e.`type` == RenderGameOverlayEvent.ElementType.TEXT) {
|
||||
val mc = Minecraft.getMinecraft
|
||||
api.Nanomachines.getController(mc.thePlayer) match {
|
||||
case controller: Controller =>
|
||||
val res = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight)
|
||||
val sizeX = 8
|
||||
val sizeY = 12
|
||||
val width = res.getScaledWidth
|
||||
val height = res.getScaledHeight
|
||||
val (x, y) = Settings.get.nanomachineHudPos
|
||||
val left =
|
||||
math.min(width - sizeX,
|
||||
if (x < 0) width / 2 - 91 - 12
|
||||
else if (x < 1) width * x
|
||||
else x)
|
||||
val top =
|
||||
math.min(height - sizeY,
|
||||
if (y < 0) height - 39
|
||||
else if (y < 1) y * height
|
||||
else y)
|
||||
val fill = controller.getLocalBuffer / controller.getLocalBufferSize
|
||||
Minecraft.getMinecraft.getTextureManager.bindTexture(Textures.GUI.Nanomachines)
|
||||
drawRect(left.toInt, top.toInt, sizeX, sizeY, sizeX, sizeY)
|
||||
Minecraft.getMinecraft.getTextureManager.bindTexture(Textures.GUI.NanomachinesBar)
|
||||
drawRect(left.toInt, top.toInt, sizeX, sizeY, sizeX, sizeY, fill)
|
||||
case _ => // Nothing to show.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def drawRect(x: Int, y: Int, w: Int, h: Int, tw: Int, th: Int, fill: Double = 1) {
|
||||
val sx = 1f / tw
|
||||
val sy = 1f / th
|
||||
val t = Tessellator.getInstance
|
||||
val r = t.getWorldRenderer
|
||||
r.startDrawingQuads()
|
||||
r.addVertexWithUV(x, y + h, 0, 0, h * sy)
|
||||
r.addVertexWithUV(x + w, y + h, 0, w * sx, h * sy)
|
||||
r.addVertexWithUV(x + w, y + h * (1 - fill), 0, w * sx, 1 - fill)
|
||||
r.addVertexWithUV(x, y + h * (1 - fill), 0, 0, 1 - fill)
|
||||
t.draw()
|
||||
}
|
||||
}
|
||||
|
||||
object Common {
|
||||
@SubscribeEvent
|
||||
def onLivingUpdate(e: LivingEvent.LivingUpdateEvent): Unit = {
|
||||
e.entity match {
|
||||
case player: EntityPlayer => api.Nanomachines.getController(player) match {
|
||||
case controller: ControllerImpl =>
|
||||
if (controller.player eq player) {
|
||||
controller.update()
|
||||
}
|
||||
else {
|
||||
// Player entity instance changed (e.g. respawn), recreate the controller.
|
||||
val nbt = new NBTTagCompound()
|
||||
controller.save(nbt)
|
||||
api.Nanomachines.uninstallController(controller.player)
|
||||
api.Nanomachines.installController(player) match {
|
||||
case newController: ControllerImpl =>
|
||||
newController.load(nbt)
|
||||
newController.reset()
|
||||
case _ => // Eh?
|
||||
}
|
||||
}
|
||||
case _ => // Not a player with nanomachines.
|
||||
}
|
||||
case _ => // Not a player.
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
def onPlayerSave(e: PlayerEvent.SaveToFile): Unit = {
|
||||
val file = e.getPlayerFile("ocnm")
|
||||
api.Nanomachines.getController(e.entityPlayer) match {
|
||||
case controller: ControllerImpl =>
|
||||
try {
|
||||
val nbt = new NBTTagCompound()
|
||||
controller.save(nbt)
|
||||
val fos = new FileOutputStream(file)
|
||||
try CompressedStreamTools.writeCompressed(nbt, fos) catch {
|
||||
case t: Throwable =>
|
||||
OpenComputers.log.warn("Error saving nanomachine state.", t)
|
||||
}
|
||||
fos.close()
|
||||
}
|
||||
catch {
|
||||
case t: Throwable =>
|
||||
OpenComputers.log.warn("Error saving nanomachine state.", t)
|
||||
}
|
||||
case _ => // Not a player with nanomachines.
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
def onPlayerLoad(e: PlayerEvent.LoadFromFile): Unit = {
|
||||
val file = e.getPlayerFile("ocnm")
|
||||
if (file.exists()) {
|
||||
api.Nanomachines.getController(e.entityPlayer) match {
|
||||
case controller: ControllerImpl =>
|
||||
try {
|
||||
val fis = new FileInputStream(file)
|
||||
try controller.load(CompressedStreamTools.readCompressed(fis)) catch {
|
||||
case t: Throwable =>
|
||||
OpenComputers.log.warn("Error loading nanomachine state.", t)
|
||||
}
|
||||
fis.close()
|
||||
}
|
||||
catch {
|
||||
case t: Throwable =>
|
||||
OpenComputers.log.warn("Error loading nanomachine state.", t)
|
||||
}
|
||||
case _ => // Not a player with nanomachines.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,3 +1,34 @@
|
||||
package li.cil.oc.common.item
|
||||
|
||||
class Acid(val parent: Delegator) extends traits.Delegate
|
||||
import net.minecraft.entity.player.EntityPlayer
|
||||
import net.minecraft.item.EnumAction
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.potion.Potion
|
||||
import net.minecraft.potion.PotionEffect
|
||||
import net.minecraft.world.World
|
||||
|
||||
class Acid(val parent: Delegator) extends traits.Delegate {
|
||||
override def onItemRightClick(stack: ItemStack, world: World, player: EntityPlayer): ItemStack = {
|
||||
player.setItemInUse(stack, getMaxItemUseDuration(stack))
|
||||
stack
|
||||
}
|
||||
|
||||
override def getItemUseAction(stack: ItemStack): EnumAction = EnumAction.DRINK
|
||||
|
||||
override def getMaxItemUseDuration(stack: ItemStack): Int = 32
|
||||
|
||||
override def onItemUseFinish(stack: ItemStack, world: World, player: EntityPlayer): ItemStack = {
|
||||
if (!world.isRemote) {
|
||||
player.addPotionEffect(new PotionEffect(Potion.blindness.id, 200))
|
||||
player.addPotionEffect(new PotionEffect(Potion.poison.id, 100))
|
||||
player.addPotionEffect(new PotionEffect(Potion.moveSlowdown.id, 600))
|
||||
player.addPotionEffect(new PotionEffect(Potion.confusion.id, 1200))
|
||||
player.addPotionEffect(new PotionEffect(Potion.fireResistance.id, 6000))
|
||||
player.addPotionEffect(new PotionEffect(Potion.saturation.id, 2000))
|
||||
|
||||
stack.stackSize -= 1
|
||||
}
|
||||
if (stack.stackSize > 0) stack
|
||||
else null
|
||||
}
|
||||
}
|
||||
|
30
src/main/scala/li/cil/oc/common/item/Nanomachines.scala
Normal file
30
src/main/scala/li/cil/oc/common/item/Nanomachines.scala
Normal file
@ -0,0 +1,30 @@
|
||||
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.ItemStack
|
||||
import net.minecraft.world.World
|
||||
|
||||
class Nanomachines(val parent: Delegator) extends traits.Delegate {
|
||||
override def onItemRightClick(stack: ItemStack, world: World, player: EntityPlayer): ItemStack = {
|
||||
if (!api.Nanomachines.hasController(player)) {
|
||||
player.setItemInUse(stack, getMaxItemUseDuration(stack))
|
||||
}
|
||||
stack
|
||||
}
|
||||
|
||||
override def getItemUseAction(stack: ItemStack): EnumAction = EnumAction.EAT
|
||||
|
||||
override def getMaxItemUseDuration(stack: ItemStack): Int = 32
|
||||
|
||||
override def onItemUseFinish(stack: ItemStack, world: World, player: EntityPlayer): ItemStack = {
|
||||
if (!world.isRemote && !api.Nanomachines.hasController(player)) {
|
||||
api.Nanomachines.installController(player).reconfigure()
|
||||
|
||||
stack.stackSize -= 1
|
||||
}
|
||||
if (stack.stackSize > 0) stack
|
||||
else null
|
||||
}
|
||||
}
|
@ -0,0 +1,302 @@
|
||||
package li.cil.oc.common.nanomachines
|
||||
|
||||
import java.lang
|
||||
import java.util.UUID
|
||||
|
||||
import com.google.common.base.Charsets
|
||||
import com.google.common.base.Strings
|
||||
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.network.Packet
|
||||
import li.cil.oc.api.network.WirelessEndpoint
|
||||
import li.cil.oc.server.PacketSender
|
||||
import li.cil.oc.util.BlockPosition
|
||||
import li.cil.oc.util.ExtendedNBT._
|
||||
import li.cil.oc.util.PlayerUtils
|
||||
import net.minecraft.entity.player.EntityPlayer
|
||||
import net.minecraft.entity.player.EntityPlayerMP
|
||||
import net.minecraft.nbt.NBTTagCompound
|
||||
import net.minecraft.potion.Potion
|
||||
import net.minecraft.potion.PotionEffect
|
||||
import net.minecraft.util.EnumParticleTypes
|
||||
import net.minecraft.world.World
|
||||
|
||||
import scala.collection.convert.WrapAsJava._
|
||||
import scala.collection.convert.WrapAsScala._
|
||||
import scala.collection.mutable
|
||||
|
||||
class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessEndpoint {
|
||||
if (isServer) api.Network.joinWirelessNetwork(this)
|
||||
|
||||
final val MaxSenderDistance = 2f
|
||||
final val FullSyncInterval = 20 * 60
|
||||
|
||||
var uuid = UUID.randomUUID.toString
|
||||
var responsePort = 0
|
||||
var storedEnergy = Settings.get.bufferNanomachines * 0.25
|
||||
var hadPower = true
|
||||
val configuration = new NeuralNetwork(this)
|
||||
val activeBehaviors = mutable.Set.empty[Behavior]
|
||||
var activeBehaviorsDirty = true
|
||||
var configCooldown = 0
|
||||
var hasSentConfiguration = false
|
||||
|
||||
override def world: World = player.getEntityWorld
|
||||
|
||||
override def x: Int = BlockPosition(player).x
|
||||
|
||||
override def y: Int = BlockPosition(player).y
|
||||
|
||||
override def z: Int = BlockPosition(player).z
|
||||
|
||||
override def receivePacket(packet: Packet, sender: WirelessEndpoint): Unit = {
|
||||
if (getLocalBuffer > 0) {
|
||||
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 {
|
||||
case Some(header: Array[Byte]) if new String(header, Charsets.UTF_8) == "nanomachines" =>
|
||||
val command = packet.data.drop(1).map {
|
||||
case value: Array[Byte] => new String(value, Charsets.UTF_8)
|
||||
case value => value
|
||||
}
|
||||
command match {
|
||||
case Array("setResponsePort", port: java.lang.Number) =>
|
||||
responsePort = port.intValue max 0 min 0xFFFF
|
||||
respond(sender, "responsePort", responsePort)
|
||||
case Array("dispose") =>
|
||||
api.Nanomachines.uninstallController(player)
|
||||
respond(sender, "disposed")
|
||||
case Array("reconfigure") =>
|
||||
reconfigure()
|
||||
respond(sender, "reconfigured")
|
||||
case Array("getTotalInputCount") =>
|
||||
respond(sender, "totalInputCount", getTotalInputCount)
|
||||
case Array("getSafeInputCount") =>
|
||||
respond(sender, "safeInputCount", getSafeInputCount)
|
||||
case Array("getInput", index: java.lang.Number) =>
|
||||
try {
|
||||
val trigger = getInput(index.intValue - 1)
|
||||
respond(sender, "input", index.intValue, trigger)
|
||||
}
|
||||
catch {
|
||||
case _: Throwable =>
|
||||
respond(sender, "input", "error")
|
||||
}
|
||||
case Array("setInput", index: java.lang.Number, value: java.lang.Boolean) =>
|
||||
try {
|
||||
setInput(index.intValue - 1, value.booleanValue)
|
||||
respond(sender, "input", index.intValue, getInput(index.intValue - 1))
|
||||
}
|
||||
catch {
|
||||
case _: Throwable =>
|
||||
respond(sender, "input", "error")
|
||||
}
|
||||
case Array("getActiveEffects") =>
|
||||
configuration.synchronized {
|
||||
val names = getActiveBehaviors.map(_.getNameHint).filterNot(Strings.isNullOrEmpty)
|
||||
val joined = "{" + names.map(_.replace(',', '_').replace('"', '_')).mkString(",") + "}"
|
||||
respond(sender, "active", joined)
|
||||
}
|
||||
case Array("getPowerState") =>
|
||||
respond(sender, "power", getLocalBuffer, getLocalBufferSize)
|
||||
case _ => // Ignore.
|
||||
}
|
||||
case _ => // Not for us.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def respond(endpoint: WirelessEndpoint, data: Any*): Unit = {
|
||||
if (responsePort > 0) {
|
||||
val cost = Settings.get.wirelessCostPerRange * 10
|
||||
val epsilon = 0.1
|
||||
if (changeBuffer(-cost) > -epsilon) {
|
||||
val packet = api.Network.newPacket(uuid, null, responsePort, (Iterable("nanomachines") ++ data.map(_.asInstanceOf[AnyRef])).toArray)
|
||||
api.Network.sendWirelessPacket(this, 10, packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
override def reconfigure() = {
|
||||
if (isServer && configCooldown < 1) configuration.synchronized {
|
||||
configuration.reconfigure()
|
||||
activeBehaviorsDirty = true
|
||||
configCooldown = (Settings.get.nanomachineReconfigureTimeout * 20).toInt
|
||||
|
||||
player match {
|
||||
case playerMP: EntityPlayerMP if playerMP.playerNetServerHandler != null =>
|
||||
player.addPotionEffect(new PotionEffect(Potion.blindness.id, 100))
|
||||
player.addPotionEffect(new PotionEffect(Potion.poison.id, 150))
|
||||
player.addPotionEffect(new PotionEffect(Potion.moveSlowdown.id, 200))
|
||||
changeBuffer(-Settings.get.nanomachineReconfigureCost)
|
||||
|
||||
hasSentConfiguration = false
|
||||
case _ => // We're still setting up / loading.
|
||||
}
|
||||
}
|
||||
this
|
||||
}
|
||||
|
||||
override def getTotalInputCount: Int = configuration.synchronized(configuration.triggers.length)
|
||||
|
||||
override def getSafeInputCount: Int = configuration.synchronized(configuration.triggers.length * Settings.get.nanomachinesSafeInputCount).toInt
|
||||
|
||||
override def getInput(index: Int): Boolean = configuration.synchronized(configuration.triggers(index).isActive)
|
||||
|
||||
override def setInput(index: Int, value: Boolean): Unit = {
|
||||
if (isServer && configCooldown < 1) configuration.synchronized {
|
||||
configuration.triggers(index).isActive = value
|
||||
activeBehaviorsDirty = true
|
||||
}
|
||||
}
|
||||
|
||||
override def getActiveBehaviors: lang.Iterable[Behavior] = configuration.synchronized {
|
||||
cleanActiveBehaviors()
|
||||
activeBehaviors
|
||||
}
|
||||
|
||||
override def getInputCount(behavior: Behavior): Int = configuration.synchronized(configuration.inputs(behavior))
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
override def getLocalBuffer: Double = storedEnergy
|
||||
|
||||
override def getLocalBufferSize: Double = Settings.get.bufferNanomachines
|
||||
|
||||
override def changeBuffer(delta: Double): Double = {
|
||||
if (isClient) delta
|
||||
else if (delta < 0 && (Settings.get.ignorePower || player.capabilities.isCreativeMode)) 0.0
|
||||
else {
|
||||
val newValue = storedEnergy + delta
|
||||
storedEnergy = math.min(math.max(newValue, 0), getLocalBufferSize)
|
||||
newValue - storedEnergy
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
def update(): Unit = {
|
||||
if (isServer) {
|
||||
api.Network.updateWirelessNetwork(this)
|
||||
}
|
||||
|
||||
if (configCooldown > 0) {
|
||||
configCooldown -= 1
|
||||
return
|
||||
}
|
||||
|
||||
val 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())
|
||||
else active.foreach(_.onEnable())
|
||||
}
|
||||
|
||||
if (hasPower) {
|
||||
active.foreach(_.update())
|
||||
|
||||
if (isServer) {
|
||||
if (player.getEntityWorld.getTotalWorldTime % Settings.get.tickFrequency == 0) {
|
||||
changeBuffer(-Settings.get.nanomachineCost * Settings.get.tickFrequency * (activeInputs + 0.5))
|
||||
PacketSender.sendNanomachinePower(player)
|
||||
}
|
||||
|
||||
val overload = activeInputs - getSafeInputCount
|
||||
if (!player.capabilities.isCreativeMode && overload > 0 && player.getEntityWorld.getTotalWorldTime % 20 == 0) {
|
||||
player.setHealth(player.getHealth - overload)
|
||||
player.performHurtAnimation()
|
||||
}
|
||||
}
|
||||
|
||||
if (isClient) {
|
||||
val energyRatio = getLocalBuffer / (getLocalBufferSize + 1)
|
||||
val triggerRatio = activeInputs / (configuration.triggers.length + 1)
|
||||
val intensity = (energyRatio + triggerRatio) * 0.25
|
||||
PlayerUtils.spawnParticleAround(player, EnumParticleTypes.PORTAL, intensity)
|
||||
}
|
||||
}
|
||||
|
||||
if (isServer) {
|
||||
// Send new power state, if it changed.
|
||||
if (hadPower != hasPower) {
|
||||
PacketSender.sendNanomachinePower(player)
|
||||
}
|
||||
|
||||
// Send a full sync every now and then, e.g. for other players coming
|
||||
// closer that weren't there to get the initial info for an enabled
|
||||
// input.
|
||||
if (!hasSentConfiguration || player.getEntityWorld.getTotalWorldTime % FullSyncInterval == 0) {
|
||||
hasSentConfiguration = true
|
||||
PacketSender.sendNanomachineConfiguration(player)
|
||||
}
|
||||
}
|
||||
|
||||
hadPower = hasPower
|
||||
}
|
||||
|
||||
def reset(): Unit = {
|
||||
configuration.synchronized {
|
||||
for (index <- 0 until getTotalInputCount) {
|
||||
configuration.triggers(index).isActive = false
|
||||
activeBehaviorsDirty = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def dispose(): Unit = {
|
||||
reset()
|
||||
if (isServer) {
|
||||
api.Network.leaveWirelessNetwork(this)
|
||||
PacketSender.sendNanomachineConfiguration(player)
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
def save(nbt: NBTTagCompound): Unit = configuration.synchronized {
|
||||
nbt.setString("uuid", uuid)
|
||||
nbt.setInteger("port", responsePort)
|
||||
nbt.setDouble("energy", storedEnergy)
|
||||
nbt.setNewCompoundTag("configuration", configuration.save)
|
||||
}
|
||||
|
||||
def load(nbt: NBTTagCompound): Unit = configuration.synchronized {
|
||||
uuid = nbt.getString("uuid")
|
||||
responsePort = nbt.getInteger("port")
|
||||
storedEnergy = nbt.getDouble("energy")
|
||||
configuration.load(nbt.getCompoundTag("configuration"))
|
||||
activeBehaviorsDirty = true
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
private def isClient = world.isRemote
|
||||
|
||||
private def isServer = !isClient
|
||||
|
||||
private def cleanActiveBehaviors(): Unit = {
|
||||
if (activeBehaviorsDirty) {
|
||||
configuration.synchronized(if (activeBehaviorsDirty) {
|
||||
activeBehaviors.clear()
|
||||
val newBehaviors = configuration.behaviors.filter(_.isActive).map(_.behavior)
|
||||
val addedBehaviors = newBehaviors -- activeBehaviors
|
||||
val removedBehaviors = activeBehaviors -- newBehaviors
|
||||
activeBehaviors.clear()
|
||||
activeBehaviors ++= newBehaviors
|
||||
activeBehaviorsDirty = false
|
||||
addedBehaviors.foreach(_.onEnable())
|
||||
removedBehaviors.foreach(_.onDisable())
|
||||
|
||||
if (isServer) {
|
||||
PacketSender.sendNanomachineInputs(player)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package li.cil.oc.common.nanomachines
|
||||
|
||||
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.util.PlayerUtils
|
||||
import net.minecraft.entity.player.EntityPlayer
|
||||
|
||||
import scala.collection.convert.WrapAsJava._
|
||||
import scala.collection.mutable
|
||||
|
||||
object Nanomachines extends api.detail.NanomachinesAPI {
|
||||
val providers = mutable.Set.empty[BehaviorProvider]
|
||||
|
||||
val serverControllers = mutable.WeakHashMap.empty[EntityPlayer, ControllerImpl]
|
||||
val clientControllers = mutable.WeakHashMap.empty[EntityPlayer, ControllerImpl]
|
||||
|
||||
def controllers(player: EntityPlayer) = if (player.getEntityWorld.isRemote) clientControllers else serverControllers
|
||||
|
||||
override def addProvider(provider: BehaviorProvider): Unit = providers += provider
|
||||
|
||||
override def getProviders: java.lang.Iterable[BehaviorProvider] = providers
|
||||
|
||||
def getController(player: EntityPlayer): Controller = {
|
||||
if (hasController(player)) controllers(player).getOrElseUpdate(player, new ControllerImpl(player))
|
||||
else null
|
||||
}
|
||||
|
||||
def hasController(player: EntityPlayer) = {
|
||||
PlayerUtils.persistedData(player).getBoolean(Settings.namespace + "hasNanomachines")
|
||||
}
|
||||
|
||||
def installController(player: EntityPlayer) = {
|
||||
if (!hasController(player)) {
|
||||
PlayerUtils.persistedData(player).setBoolean(Settings.namespace + "hasNanomachines", true)
|
||||
}
|
||||
getController(player) // Initialize controller instance.
|
||||
}
|
||||
|
||||
override def uninstallController(player: EntityPlayer): Unit = {
|
||||
getController(player) match {
|
||||
case controller: ControllerImpl =>
|
||||
PlayerUtils.persistedData(player).removeTag(Settings.namespace + "hasNanomachines")
|
||||
controllers(player) -= player
|
||||
controller.dispose()
|
||||
case _ => // Doesn't have one anyway.
|
||||
}
|
||||
}
|
||||
}
|
161
src/main/scala/li/cil/oc/common/nanomachines/NeuralNetwork.scala
Normal file
161
src/main/scala/li/cil/oc/common/nanomachines/NeuralNetwork.scala
Normal file
@ -0,0 +1,161 @@
|
||||
package li.cil.oc.common.nanomachines
|
||||
|
||||
import li.cil.oc.Settings
|
||||
import li.cil.oc.api
|
||||
import li.cil.oc.api.Persistable
|
||||
import li.cil.oc.api.nanomachines.Behavior
|
||||
import li.cil.oc.api.nanomachines.BehaviorProvider
|
||||
import li.cil.oc.util.ExtendedNBT._
|
||||
import net.minecraft.nbt.NBTTagCompound
|
||||
import net.minecraftforge.common.util.Constants.NBT
|
||||
|
||||
import scala.collection.convert.WrapAsScala._
|
||||
import scala.collection.mutable
|
||||
import scala.util.Random
|
||||
|
||||
class NeuralNetwork(controller: ControllerImpl) extends Persistable {
|
||||
val triggers = mutable.ArrayBuffer.empty[TriggerNeuron]
|
||||
val connectors = mutable.ArrayBuffer.empty[ConnectorNeuron]
|
||||
val behaviors = mutable.ArrayBuffer.empty[BehaviorNeuron]
|
||||
|
||||
val behaviorMap = mutable.Map.empty[Behavior, BehaviorNeuron]
|
||||
|
||||
def inputs(behavior: Behavior) = behaviorMap.get(behavior) match {
|
||||
case Some(node) => node.inputs.count(_.isActive)
|
||||
case _ => 0
|
||||
}
|
||||
|
||||
def reconfigure(): Unit = {
|
||||
// Rebuild list of valid behaviors.
|
||||
behaviors.clear()
|
||||
behaviors ++= api.Nanomachines.getProviders.
|
||||
map(p => (p, Option(p.createBehaviors(controller.player)).map(_.filter(_ != null)).orNull)). // Remove null behaviors.
|
||||
filter(_._2 != null). // Remove null lists..
|
||||
flatMap(pb => pb._2.map(b => new BehaviorNeuron(pb._1, b)))
|
||||
|
||||
// Adjust length of trigger list and reset.
|
||||
while (triggers.length > behaviors.length * Settings.get.nanomachineTriggerQuota) {
|
||||
triggers.remove(triggers.length - 1)
|
||||
}
|
||||
triggers.foreach(_.isActive = false)
|
||||
while (triggers.length < behaviors.length * Settings.get.nanomachineTriggerQuota) {
|
||||
triggers += new TriggerNeuron()
|
||||
}
|
||||
|
||||
// Adjust length of connector list and reset.
|
||||
while (connectors.length > behaviors.length * Settings.get.nanomachineConnectorQuota) {
|
||||
connectors.remove(connectors.length - 1)
|
||||
}
|
||||
connectors.foreach(_.inputs.clear())
|
||||
while (connectors.length < behaviors.length * Settings.get.nanomachineConnectorQuota) {
|
||||
connectors += new ConnectorNeuron()
|
||||
}
|
||||
|
||||
// Build connections.
|
||||
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)
|
||||
for (sink <- sinkPool if sources.nonEmpty) {
|
||||
for (n <- 0 to rng.nextInt(Settings.get.nanomachineMaxInputs) if sources.nonEmpty) {
|
||||
val sourceIndex = rng.nextInt(sources.length)
|
||||
sink.inputs += sources.remove(sourceIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
sourcePool ++= mutable.ArrayBuffer.fill(Settings.get.nanomachineMaxOutputs)(connectors.map(_.asInstanceOf[Neuron])).flatten
|
||||
connect(behaviors, sourcePool)
|
||||
|
||||
// Clean up dead nodes.
|
||||
val deadConnectors = connectors.filter(_.inputs.isEmpty)
|
||||
connectors --= deadConnectors
|
||||
behaviors.foreach(_.inputs --= deadConnectors)
|
||||
|
||||
val deadBehaviors = behaviors.filter(_.inputs.isEmpty)
|
||||
behaviors --= deadBehaviors
|
||||
|
||||
behaviorMap.clear()
|
||||
behaviorMap ++= behaviors.map(n => n.behavior -> n)
|
||||
}
|
||||
|
||||
override def save(nbt: NBTTagCompound): Unit = {
|
||||
nbt.setNewTagList("triggers", triggers.map(t => {
|
||||
val nbt = new NBTTagCompound()
|
||||
nbt.setBoolean("isActive", t.isActive)
|
||||
nbt
|
||||
}))
|
||||
|
||||
nbt.setNewTagList("connectors", connectors.map(c => {
|
||||
val nbt = new NBTTagCompound()
|
||||
nbt.setIntArray("triggerInputs", c.inputs.map(triggers.indexOf(_)).filter(_ >= 0).toArray)
|
||||
nbt
|
||||
}))
|
||||
|
||||
nbt.setNewTagList("behaviors", behaviors.map(b => {
|
||||
val nbt = new NBTTagCompound()
|
||||
nbt.setIntArray("triggerInputs", b.inputs.map(triggers.indexOf(_)).filter(_ >= 0).toArray)
|
||||
nbt.setIntArray("connectorInputs", b.inputs.map(connectors.indexOf(_)).filter(_ >= 0).toArray)
|
||||
nbt.setTag("behavior", b.provider.writeToNBT(b.behavior))
|
||||
nbt
|
||||
}))
|
||||
}
|
||||
|
||||
override def load(nbt: NBTTagCompound): Unit = {
|
||||
triggers.clear()
|
||||
nbt.getTagList("triggers", NBT.TAG_COMPOUND).foreach((t: NBTTagCompound) => {
|
||||
val neuron = new TriggerNeuron()
|
||||
neuron.isActive = t.getBoolean("isActive")
|
||||
triggers += neuron
|
||||
})
|
||||
|
||||
connectors.clear()
|
||||
nbt.getTagList("connectors", NBT.TAG_COMPOUND).foreach((t: NBTTagCompound) => {
|
||||
val neuron = new ConnectorNeuron()
|
||||
neuron.inputs ++= t.getIntArray("triggerInputs").map(triggers.apply)
|
||||
connectors += neuron
|
||||
})
|
||||
|
||||
behaviors.clear()
|
||||
nbt.getTagList("behaviors", NBT.TAG_COMPOUND).foreach((t: NBTTagCompound) => {
|
||||
api.Nanomachines.getProviders.find(p => p.readFromNBT(controller.player, t.getCompoundTag("behavior")) match {
|
||||
case b: Behavior =>
|
||||
val neuron = new BehaviorNeuron(p, b)
|
||||
neuron.inputs ++= t.getIntArray("triggerInputs").map(triggers.apply)
|
||||
neuron.inputs ++= t.getIntArray("connectorInputs").map(connectors.apply)
|
||||
behaviors += neuron
|
||||
true // Done.
|
||||
case _ =>
|
||||
false // Keep looking.
|
||||
})
|
||||
})
|
||||
|
||||
behaviorMap.clear()
|
||||
behaviorMap ++= behaviors.map(n => n.behavior -> n)
|
||||
}
|
||||
|
||||
trait Neuron {
|
||||
def isActive: Boolean
|
||||
}
|
||||
|
||||
class TriggerNeuron extends Neuron {
|
||||
var isActive = false
|
||||
}
|
||||
|
||||
class ConnectorNeuron extends Neuron {
|
||||
val inputs = mutable.ArrayBuffer.empty[Neuron]
|
||||
|
||||
override def isActive = inputs.exists(_.isActive)
|
||||
}
|
||||
|
||||
class BehaviorNeuron(val provider: BehaviorProvider, val behavior: Behavior) extends ConnectorNeuron
|
||||
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
package li.cil.oc.common.nanomachines.provider
|
||||
|
||||
import li.cil.oc.Settings
|
||||
import li.cil.oc.api
|
||||
import li.cil.oc.util.BlockPosition
|
||||
import li.cil.oc.util.ExtendedWorld._
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.block.state.IBlockState
|
||||
import net.minecraft.entity.player.EntityPlayer
|
||||
import net.minecraft.entity.player.EntityPlayerMP
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.nbt.NBTTagCompound
|
||||
import net.minecraft.world.World
|
||||
import net.minecraftforge.event.ForgeEventFactory
|
||||
import net.minecraftforge.event.entity.player.PlayerInteractEvent.Action
|
||||
import net.minecraftforge.fml.common.eventhandler.Event
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
object DisintegrationProvider extends SimpleProvider {
|
||||
final val Id = "c4e7e3c2-8069-4fbb-b08e-74b1bddcdfe7"
|
||||
|
||||
override def doCreateBehaviors(player: EntityPlayer) = Iterable(new DisintegrationBehavior(player))
|
||||
|
||||
override def doReadFromNBT(player: EntityPlayer, nbt: NBTTagCompound) = new DisintegrationBehavior(player)
|
||||
|
||||
class DisintegrationBehavior(player: EntityPlayer) extends SimpleBehavior(player) {
|
||||
var breakingMap = mutable.Map.empty[BlockPosition, SlowBreakInfo]
|
||||
var breakingMapNew = mutable.Map.empty[BlockPosition, SlowBreakInfo]
|
||||
|
||||
// Note: intentionally not overriding getNameHint. Gotta find this one manually!
|
||||
|
||||
override def onDisable(): Unit = {
|
||||
val world = player.getEntityWorld
|
||||
for (pos <- breakingMap.keys) {
|
||||
world.destroyBlockInWorldPartially(pos.hashCode(), pos, -1)
|
||||
}
|
||||
breakingMap.clear()
|
||||
}
|
||||
|
||||
override def update(): Unit = {
|
||||
val world = player.getEntityWorld
|
||||
if (!world.isRemote) player match {
|
||||
case playerMP: EntityPlayerMP =>
|
||||
val now = world.getTotalWorldTime
|
||||
|
||||
// Check blocks in range.
|
||||
val blockPos = BlockPosition(player)
|
||||
val actualRange = Settings.get.nanomachineDisintegrationRange * api.Nanomachines.getController(player).getInputCount(this)
|
||||
for (x <- -actualRange to actualRange; y <- 0 to actualRange * 2; z <- -actualRange to actualRange) {
|
||||
val pos = BlockPosition(blockPos.offset(x, y, z))
|
||||
breakingMap.get(pos) match {
|
||||
case Some(info) if info.checkTool(player) =>
|
||||
breakingMapNew += pos -> info
|
||||
info.update(world, player, now)
|
||||
case None =>
|
||||
val event = ForgeEventFactory.onPlayerInteract(player, Action.LEFT_CLICK_BLOCK, world, pos.toBlockPos, null)
|
||||
val allowed = !event.isCanceled && event.useBlock != Event.Result.DENY && event.useItem != Event.Result.DENY
|
||||
val adventureOk = !world.getWorldInfo.getGameType.isAdventure || player.canPlayerEdit(pos.toBlockPos, null, player.getCurrentEquippedItem)
|
||||
if (allowed && adventureOk && !world.isAirBlock(pos)) {
|
||||
val blockState = world.getBlockState(pos.toBlockPos)
|
||||
val hardness = blockState.getBlock.getPlayerRelativeBlockHardness(player, world, pos.toBlockPos)
|
||||
if (hardness > 0) {
|
||||
val timeToBreak = (1 / hardness).toInt
|
||||
if (timeToBreak < 20 * 30) {
|
||||
val info = new SlowBreakInfo(now, now + timeToBreak, pos, Option(player.getCurrentEquippedItem).map(_.copy()), blockState)
|
||||
world.destroyBlockInWorldPartially(pos.hashCode(), pos, 0)
|
||||
breakingMapNew += pos -> info
|
||||
}
|
||||
}
|
||||
}
|
||||
case _ => // Tool changed, pretend block doesn't exist for this tick.
|
||||
}
|
||||
}
|
||||
|
||||
// Handle completed breaks.
|
||||
for ((pos, info) <- breakingMap) {
|
||||
if (info.timeBroken < now) {
|
||||
breakingMapNew -= pos
|
||||
info.finish(world, playerMP)
|
||||
}
|
||||
}
|
||||
|
||||
// Handle aborted / incomplete breaks.
|
||||
for (pos <- breakingMap.keySet -- breakingMapNew.keySet) {
|
||||
world.destroyBlockInWorldPartially(pos.hashCode(), pos, -1)
|
||||
}
|
||||
|
||||
val tmp = breakingMap
|
||||
breakingMap.clear()
|
||||
breakingMap = breakingMapNew
|
||||
breakingMapNew = tmp
|
||||
case _ => // Not available for fake players, sorry :P
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SlowBreakInfo(val timeStarted: Long, val timeBroken: Long, val pos: BlockPosition, val originalTool: Option[ItemStack], val blockState: IBlockState) {
|
||||
var lastDamageSent = 0
|
||||
|
||||
def checkTool(player: EntityPlayer): Boolean = {
|
||||
val currentTool = Option(player.getCurrentEquippedItem).map(_.copy())
|
||||
(currentTool, originalTool) match {
|
||||
case (Some(stackA), Some(stackB)) => stackA.getItem == stackB.getItem && (stackA.isItemStackDamageable || stackA.getItemDamage == stackB.getItemDamage)
|
||||
case (None, None) => true
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
||||
def update(world: World, player: EntityPlayer, now: Long): Unit = {
|
||||
val timeTotal = timeBroken - timeStarted
|
||||
if (timeTotal > 0) {
|
||||
val timeTaken = now - timeStarted
|
||||
val damage = 10 * timeTaken / timeTotal
|
||||
if (damage != lastDamageSent) {
|
||||
lastDamageSent = damage.toInt
|
||||
world.destroyBlockInWorldPartially(pos.hashCode(), pos, lastDamageSent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def finish(world: World, player: EntityPlayerMP): Unit = {
|
||||
val sameBlock = world.getBlockState(pos.toBlockPos) == blockState
|
||||
if (sameBlock) {
|
||||
world.destroyBlockInWorldPartially(pos.hashCode(), pos, -1)
|
||||
if (player.theItemInWorldManager.tryHarvestBlock(pos.toBlockPos)) {
|
||||
world.playAuxSFX(2001, pos, Block.getIdFromBlock(blockState.getBlock) + (blockState.getBlock.getMetaFromState(blockState) << 12))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package li.cil.oc.common.nanomachines.provider
|
||||
|
||||
import li.cil.oc.Settings
|
||||
import li.cil.oc.api
|
||||
import net.minecraft.entity.item.EntityItem
|
||||
import net.minecraft.entity.player.EntityPlayer
|
||||
import net.minecraft.nbt.NBTTagCompound
|
||||
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"
|
||||
|
||||
override def doCreateBehaviors(player: EntityPlayer) = Iterable(new MagnetBehavior(player))
|
||||
|
||||
override def doReadFromNBT(player: EntityPlayer, nbt: NBTTagCompound) = new MagnetBehavior(player)
|
||||
|
||||
class MagnetBehavior(player: EntityPlayer) extends SimpleBehavior(player) {
|
||||
override def getNameHint = "magnet"
|
||||
|
||||
override def update(): Unit = {
|
||||
val world = player.getEntityWorld
|
||||
if (!world.isRemote) {
|
||||
val actualRange = Settings.get.nanomachineMagnetRange * api.Nanomachines.getController(player).getInputCount(this)
|
||||
val items = world.getEntitiesWithinAABB(classOf[EntityItem], player.getEntityBoundingBox.expand(actualRange, actualRange, actualRange))
|
||||
items.collect {
|
||||
case item: EntityItem if !item.cannotPickup && item.getEntityItem != null && player.inventory.mainInventory.exists(stack => stack == null || stack.stackSize < stack.getMaxStackSize && stack.isItemEqual(item.getEntityItem)) =>
|
||||
val dx = player.posX - item.posX
|
||||
val dy = player.posY - item.posY
|
||||
val dz = player.posZ - item.posZ
|
||||
val delta = new Vec3(dx, dy, dz).normalize()
|
||||
item.addVelocity(delta.xCoord * 0.1, delta.yCoord * 0.1, delta.zCoord * 0.1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package li.cil.oc.common.nanomachines.provider
|
||||
|
||||
import li.cil.oc.api
|
||||
import li.cil.oc.api.nanomachines.Behavior
|
||||
import li.cil.oc.util.PlayerUtils
|
||||
import net.minecraft.entity.player.EntityPlayer
|
||||
import net.minecraft.nbt.NBTTagCompound
|
||||
import net.minecraft.util.EnumParticleTypes
|
||||
|
||||
object ParticleProvider extends SimpleProvider {
|
||||
final val Id = "b48c4bbd-51bb-4915-9367-16cff3220e4b"
|
||||
|
||||
final val ParticleTypes = Array(
|
||||
EnumParticleTypes.FIREWORKS_SPARK,
|
||||
EnumParticleTypes.TOWN_AURA,
|
||||
EnumParticleTypes.SMOKE_NORMAL,
|
||||
EnumParticleTypes.SPELL_WITCH,
|
||||
EnumParticleTypes.NOTE,
|
||||
EnumParticleTypes.ENCHANTMENT_TABLE,
|
||||
EnumParticleTypes.FLAME,
|
||||
EnumParticleTypes.LAVA,
|
||||
EnumParticleTypes.WATER_SPLASH,
|
||||
EnumParticleTypes.REDSTONE,
|
||||
EnumParticleTypes.SLIME,
|
||||
EnumParticleTypes.HEART,
|
||||
EnumParticleTypes.VILLAGER_HAPPY
|
||||
)
|
||||
|
||||
override def doCreateBehaviors(player: EntityPlayer): Iterable[Behavior] = ParticleTypes.map(new ParticleBehavior(_, player))
|
||||
|
||||
override def doWriteToNBT(behavior: Behavior, nbt: NBTTagCompound): Unit = {
|
||||
behavior match {
|
||||
case particles: ParticleBehavior =>
|
||||
nbt.setInteger("effectName", particles.effectType.getParticleID)
|
||||
case _ => // Wat.
|
||||
}
|
||||
}
|
||||
|
||||
override def doReadFromNBT(player: EntityPlayer, nbt: NBTTagCompound): Behavior = {
|
||||
val effectType = EnumParticleTypes.getParticleFromId(nbt.getInteger("effectName"))
|
||||
new ParticleBehavior(effectType, player)
|
||||
}
|
||||
|
||||
class ParticleBehavior(var effectType: EnumParticleTypes, player: EntityPlayer) extends SimpleBehavior(player) {
|
||||
override def getNameHint = "particles"
|
||||
|
||||
override def update(): Unit = {
|
||||
val world = player.getEntityWorld
|
||||
if (world.isRemote) {
|
||||
PlayerUtils.spawnParticleAround(player, effectType, api.Nanomachines.getController(player).getInputCount(this) * 0.25)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
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 net.minecraft.entity.player.EntityPlayer
|
||||
import net.minecraft.nbt.NBTTagCompound
|
||||
import net.minecraft.potion.Potion
|
||||
import net.minecraft.potion.PotionEffect
|
||||
|
||||
import scala.collection.convert.WrapAsScala._
|
||||
|
||||
object PotionProvider extends SimpleProvider {
|
||||
final val Id = "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
|
||||
|
||||
override def doCreateBehaviors(player: EntityPlayer) = {
|
||||
Potion.potionTypes.filter(_ != null).filterNot(PotionBlacklist.contains).map(new PotionBehavior(_, player))
|
||||
}
|
||||
|
||||
override def doWriteToNBT(behavior: Behavior, nbt: NBTTagCompound): Unit = {
|
||||
behavior match {
|
||||
case potionBehavior: PotionBehavior =>
|
||||
nbt.setInteger("potionId", potionBehavior.potion.id)
|
||||
case _ => // Shouldn't happen, ever.
|
||||
}
|
||||
}
|
||||
|
||||
override def doReadFromNBT(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) {
|
||||
final val RefreshInterval = 40
|
||||
|
||||
def amplifier(player: EntityPlayer) = api.Nanomachines.getController(player).getInputCount(this) - 1
|
||||
|
||||
override def getNameHint: String = potion.getName.stripPrefix("potion.")
|
||||
|
||||
override def onEnable(): Unit = {}
|
||||
|
||||
override def onDisable(): Unit = {}
|
||||
|
||||
override def update(): Unit = {
|
||||
player.getActivePotionEffect(potion) match {
|
||||
case effect: PotionEffect if effect.getDuration > RefreshInterval / 2 => // Effect still active.
|
||||
case _ => player.addPotionEffect(new PotionEffect(potion.id, RefreshInterval, amplifier(player)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
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 = {}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
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
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ import li.cil.oc.Localization
|
||||
import li.cil.oc.Settings
|
||||
import li.cil.oc.api
|
||||
import li.cil.oc.api.Driver
|
||||
import li.cil.oc.api.nanomachines.Controller
|
||||
import li.cil.oc.api.network._
|
||||
import li.cil.oc.common.Slot
|
||||
import li.cil.oc.common.entity.Drone
|
||||
@ -30,7 +31,7 @@ class Charger extends traits.Environment with traits.PowerAcceptor with traits.R
|
||||
withConnector(Settings.get.bufferConverter).
|
||||
create()
|
||||
|
||||
val connectors = mutable.Set.empty[(Vec3, Connector)]
|
||||
val connectors = mutable.Set.empty[Chargeable]
|
||||
|
||||
var chargeSpeed = 0.0
|
||||
|
||||
@ -81,9 +82,7 @@ class Charger extends traits.Environment with traits.PowerAcceptor with traits.R
|
||||
val charge = Settings.get.chargeRateExternal * chargeSpeed * Settings.get.tickFrequency
|
||||
canCharge ||= charge > 0 && node.globalBuffer >= charge * 0.5
|
||||
if (canCharge) {
|
||||
connectors.foreach {
|
||||
case (_, connector) => node.changeBuffer(connector.changeBuffer(charge + node.changeBuffer(-charge)))
|
||||
}
|
||||
connectors.foreach(connector => node.changeBuffer(connector.changeBuffer(charge + node.changeBuffer(-charge))))
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,15 +110,15 @@ class Charger extends traits.Environment with traits.PowerAcceptor with traits.R
|
||||
}
|
||||
|
||||
if (isClient && chargeSpeed > 0 && hasPower && world.getWorldInfo.getWorldTotalTime % 10 == 0) {
|
||||
connectors.foreach {
|
||||
case (position, _) =>
|
||||
val theta = world.rand.nextDouble * Math.PI
|
||||
val phi = world.rand.nextDouble * Math.PI * 2
|
||||
val dx = 0.45 * Math.sin(theta) * Math.cos(phi)
|
||||
val dy = 0.45 * Math.sin(theta) * Math.sin(phi)
|
||||
val dz = 0.45 * Math.cos(theta)
|
||||
world.spawnParticle(EnumParticleTypes.VILLAGER_HAPPY, position.xCoord + dx, position.yCoord + dz, position.zCoord + dy, 0, 0, 0)
|
||||
}
|
||||
connectors.foreach(connector => {
|
||||
val position = connector.pos
|
||||
val theta = world.rand.nextDouble * Math.PI
|
||||
val phi = world.rand.nextDouble * Math.PI * 2
|
||||
val dx = 0.45 * Math.sin(theta) * Math.cos(phi)
|
||||
val dy = 0.45 * Math.sin(theta) * Math.sin(phi)
|
||||
val dz = 0.45 * Math.cos(theta)
|
||||
world.spawnParticle(EnumParticleTypes.VILLAGER_HAPPY, position.xCoord + dx, position.yCoord + dz, position.zCoord + dy, 0, 0, 0)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -193,23 +192,59 @@ class Charger extends traits.Environment with traits.PowerAcceptor with traits.R
|
||||
}
|
||||
|
||||
def updateConnectors() {
|
||||
val robotConnectors = EnumFacing.values.map(side => {
|
||||
val robots = EnumFacing.values.map(side => {
|
||||
val blockPos = BlockPosition(this).offset(side)
|
||||
if (world.blockExists(blockPos)) Option(world.getTileEntity(blockPos))
|
||||
else None
|
||||
}).collect {
|
||||
case Some(t: RobotProxy) => (BlockPosition(t).toVec3, t.robot.node.asInstanceOf[Connector])
|
||||
case Some(t: RobotProxy) => new RobotChargeable(t.robot)
|
||||
}
|
||||
val droneConnectors = world.getEntitiesWithinAABB(classOf[Drone], BlockPosition(this).bounds.expand(1, 1, 1)).collect {
|
||||
case drone: Drone => (new Vec3(drone.posX, drone.posY, drone.posZ), drone.components.node.asInstanceOf[Connector])
|
||||
val bounds = BlockPosition(this).bounds.expand(1, 1, 1)
|
||||
val drones = world.getEntitiesWithinAABB(classOf[Drone], bounds).collect {
|
||||
case drone: Drone => new DroneChargeable(drone)
|
||||
}
|
||||
|
||||
val players = world.getEntitiesWithinAABB(classOf[EntityPlayer], bounds).collect {
|
||||
case player: EntityPlayer => new PlayerChargeable(player)
|
||||
}
|
||||
|
||||
// Only update list when we have to, keeps pointless block updates to a minimum.
|
||||
if (connectors.size != robotConnectors.length + droneConnectors.size || (connectors.size > 0 && connectors.map(_._2).diff((robotConnectors ++ droneConnectors).map(_._2).toSet).size > 0)) {
|
||||
|
||||
val newConnectors = robots ++ drones ++ players
|
||||
if (connectors.size != newConnectors.length || (connectors.nonEmpty && (connectors -- newConnectors).nonEmpty)) {
|
||||
connectors.clear()
|
||||
connectors ++= robotConnectors
|
||||
connectors ++= droneConnectors
|
||||
connectors ++= newConnectors
|
||||
world.notifyNeighborsOfStateChange(getPos, getBlockType)
|
||||
}
|
||||
}
|
||||
|
||||
trait Chargeable {
|
||||
def pos: Vec3
|
||||
|
||||
def changeBuffer(delta: Double): Double
|
||||
}
|
||||
|
||||
abstract class ConnectorChargeable(val connector: Connector) extends Chargeable {
|
||||
override def changeBuffer(delta: Double): Double = connector.changeBuffer(delta)
|
||||
}
|
||||
|
||||
class RobotChargeable(val robot: Robot) extends ConnectorChargeable(robot.node.asInstanceOf[Connector]) {
|
||||
override def pos: Vec3 = BlockPosition(robot).toVec3
|
||||
}
|
||||
|
||||
class DroneChargeable(val drone: Drone) extends ConnectorChargeable(drone.components.node.asInstanceOf[Connector]) {
|
||||
override def pos: Vec3 = new Vec3(drone.posX, drone.posY, drone.posZ)
|
||||
}
|
||||
|
||||
class PlayerChargeable(val player: EntityPlayer) extends Chargeable {
|
||||
override def pos: Vec3 = new Vec3(player.posX, player.posY, player.posZ)
|
||||
|
||||
override def changeBuffer(delta: Double): Double = {
|
||||
api.Nanomachines.getController(player) match {
|
||||
case controller: Controller => controller.changeBuffer(delta)
|
||||
case _ => delta // Cannot charge.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -27,6 +27,10 @@ import li.cil.oc.common.item.Analyzer
|
||||
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.MagnetProvider
|
||||
import li.cil.oc.common.nanomachines.provider.ParticleProvider
|
||||
import li.cil.oc.common.nanomachines.provider.PotionProvider
|
||||
import li.cil.oc.common.template._
|
||||
import li.cil.oc.integration.ModProxy
|
||||
import li.cil.oc.integration.Mods
|
||||
@ -80,6 +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(RobotCommonHandler)
|
||||
MinecraftForge.EVENT_BUS.register(SaveHandler)
|
||||
MinecraftForge.EVENT_BUS.register(Tablet)
|
||||
@ -246,6 +251,11 @@ object ModOpenComputers extends ModProxy {
|
||||
api.Manual.addTab(new TextureTabIconRenderer(Textures.GUI.ManualHome), "oc:gui.Manual.Home", "%LANGUAGE%/index.md")
|
||||
api.Manual.addTab(new ItemStackTabIconRenderer(api.Items.get("case1").createItemStack(1)), "oc:gui.Manual.Blocks", "%LANGUAGE%/block/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(ParticleProvider)
|
||||
api.Nanomachines.addProvider(PotionProvider)
|
||||
api.Nanomachines.addProvider(MagnetProvider)
|
||||
}
|
||||
|
||||
def useWrench(player: EntityPlayer, pos: BlockPos, changeDurability: Boolean): Boolean = {
|
||||
|
@ -1,14 +1,17 @@
|
||||
package li.cil.oc.server
|
||||
|
||||
import li.cil.oc.api
|
||||
import li.cil.oc.api.component.TextBuffer.ColorDepth
|
||||
import li.cil.oc.api.driver.EnvironmentHost
|
||||
import li.cil.oc.api.event.FileSystemAccessEvent
|
||||
import li.cil.oc.api.network.Node
|
||||
import li.cil.oc.common._
|
||||
import li.cil.oc.common.nanomachines.ControllerImpl
|
||||
import li.cil.oc.common.tileentity.Waypoint
|
||||
import li.cil.oc.common.tileentity.traits._
|
||||
import li.cil.oc.util.BlockPosition
|
||||
import li.cil.oc.util.PackedColor
|
||||
import net.minecraft.entity.player.EntityPlayer
|
||||
import net.minecraft.entity.player.EntityPlayerMP
|
||||
import net.minecraft.inventory.Container
|
||||
import net.minecraft.item.ItemStack
|
||||
@ -251,6 +254,51 @@ object PacketSender {
|
||||
}
|
||||
}
|
||||
|
||||
def sendNanomachineConfiguration(player: EntityPlayer): Unit = {
|
||||
val pb = new SimplePacketBuilder(PacketType.NanomachinesConfiguration)
|
||||
|
||||
pb.writeEntity(player)
|
||||
api.Nanomachines.getController(player) match {
|
||||
case controller: ControllerImpl =>
|
||||
pb.writeBoolean(true)
|
||||
val nbt = new NBTTagCompound()
|
||||
controller.save(nbt)
|
||||
pb.writeNBT(nbt)
|
||||
case _ =>
|
||||
pb.writeBoolean(false)
|
||||
}
|
||||
|
||||
pb.sendToPlayersNearEntity(player)
|
||||
}
|
||||
|
||||
def sendNanomachineInputs(player: EntityPlayer): Unit = {
|
||||
api.Nanomachines.getController(player) match {
|
||||
case controller: ControllerImpl =>
|
||||
val pb = new SimplePacketBuilder(PacketType.NanomachinesInputs)
|
||||
|
||||
pb.writeEntity(player)
|
||||
val inputs = controller.configuration.triggers.map(i => if (i.isActive) 1.toByte else 0.toByte).toArray
|
||||
pb.writeInt(inputs.length)
|
||||
pb.write(inputs)
|
||||
|
||||
pb.sendToPlayersNearEntity(player)
|
||||
case _ => // Wat.
|
||||
}
|
||||
}
|
||||
|
||||
def sendNanomachinePower(player: EntityPlayer): Unit = {
|
||||
api.Nanomachines.getController(player) match {
|
||||
case controller: ControllerImpl =>
|
||||
val pb = new SimplePacketBuilder(PacketType.NanomachinesPower)
|
||||
|
||||
pb.writeEntity(player)
|
||||
pb.writeDouble(controller.getLocalBuffer)
|
||||
|
||||
pb.sendToPlayersNearEntity(player)
|
||||
case _ => // Wat.
|
||||
}
|
||||
}
|
||||
|
||||
def sendNetSplitterState(t: tileentity.NetSplitter): Unit = {
|
||||
val pb = new SimplePacketBuilder(PacketType.NetSplitterState)
|
||||
|
||||
|
@ -304,7 +304,8 @@ class Player(val agent: internal.Agent) extends FakePlayer(agent.world.asInstanc
|
||||
block.onBlockClicked(world, pos, this)
|
||||
world.extinguishFire(this, pos, side)
|
||||
|
||||
val isBlockUnbreakable = block.getBlockHardness(world, pos) < 0
|
||||
val hardness = block.getBlockHardness(world, pos)
|
||||
val isBlockUnbreakable = hardness < 0
|
||||
val canDestroyBlock = !isBlockUnbreakable && block.canEntityDestroy(world, pos, this)
|
||||
if (!canDestroyBlock) {
|
||||
return 0
|
||||
@ -320,7 +321,6 @@ class Player(val agent: internal.Agent) extends FakePlayer(agent.world.asInstanc
|
||||
return 0
|
||||
}
|
||||
|
||||
val hardness = block.getBlockHardness(world, pos)
|
||||
val strength = getBreakSpeed(state, pos)
|
||||
val breakTime =
|
||||
if (cobwebOverride) Settings.get.swingDelay
|
||||
|
@ -124,12 +124,6 @@ class NetworkCard(val host: EnvironmentHost) extends prefab.ManagedEnvironment {
|
||||
}
|
||||
}
|
||||
|
||||
def receivePacket(packet: Packet, source: WirelessEndpoint) {
|
||||
val (dx, dy, dz) = ((source.x + 0.5) - host.xPosition, (source.y + 0.5) - host.yPosition, (source.z + 0.5) - host.zPosition)
|
||||
val distance = Math.sqrt(dx * dx + dy * dy + dz * dz)
|
||||
receivePacket(packet, distance)
|
||||
}
|
||||
|
||||
protected def receivePacket(packet: Packet, distance: Double) {
|
||||
if (packet.source != node.address && Option(packet.destination).forall(_ == node.address)) {
|
||||
if (openPorts.contains(packet.port)) {
|
||||
|
@ -36,6 +36,12 @@ class WirelessNetworkCard(host: EnvironmentHost) extends NetworkCard(host) with
|
||||
|
||||
override def world = host.world
|
||||
|
||||
def receivePacket(packet: Packet, source: WirelessEndpoint) {
|
||||
val (dx, dy, dz) = ((source.x + 0.5) - host.xPosition, (source.y + 0.5) - host.yPosition, (source.z + 0.5) - host.zPosition)
|
||||
val distance = Math.sqrt(dx * dx + dy * dy + dz * dz)
|
||||
receivePacket(packet, distance)
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
@Callback(direct = true, doc = """function():number -- Get the signal strength (range) used when sending messages.""")
|
||||
|
@ -1,5 +1,6 @@
|
||||
package li.cil.oc.util
|
||||
|
||||
import com.google.common.hash.Hashing
|
||||
import li.cil.oc.api.driver.EnvironmentHost
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.util._
|
||||
@ -34,6 +35,18 @@ class BlockPosition(val x: Int, val y: Int, val z: Int, val world: Option[World]
|
||||
case position: BlockPosition => position.x == x && position.y == y && position.z == z && position.world == world
|
||||
case _ => super.equals(obj)
|
||||
}
|
||||
|
||||
override def hashCode(): Int = {
|
||||
Hashing.
|
||||
goodFastHash(32).
|
||||
newHasher(16).
|
||||
putInt(x).
|
||||
putInt(y).
|
||||
putInt(z).
|
||||
putInt(world.hashCode()).
|
||||
hash().
|
||||
asInt()
|
||||
}
|
||||
}
|
||||
|
||||
object BlockPosition {
|
||||
@ -45,6 +58,10 @@ object BlockPosition {
|
||||
|
||||
def apply(x: Double, y: Double, z: Double) = new BlockPosition(x, y, z, None)
|
||||
|
||||
def apply(v: Vec3) = new BlockPosition(v.xCoord, v.yCoord, v.zCoord, None)
|
||||
|
||||
def apply(v: Vec3, world: World) = new BlockPosition(v.xCoord, v.yCoord, v.zCoord, Option(world))
|
||||
|
||||
def apply(host: EnvironmentHost): BlockPosition = BlockPosition(host.xPosition, host.yPosition, host.zPosition, host.world)
|
||||
|
||||
def apply(entity: Entity): BlockPosition = BlockPosition(entity.posX, entity.posY, entity.posZ, entity.worldObj)
|
||||
|
@ -35,6 +35,8 @@ object ExtendedWorld {
|
||||
|
||||
def breakBlock(position: BlockPosition, drops: Boolean = true) = world.destroyBlock(position.toBlockPos, drops)
|
||||
|
||||
def destroyBlockInWorldPartially(entityId: Int, position: BlockPosition, progress: Int) = world.sendBlockBreakProgress(entityId, position.toBlockPos, progress)
|
||||
|
||||
def extinguishFire(player: EntityPlayer, position: BlockPosition, side: EnumFacing) = world.extinguishFire(player, position.toBlockPos, side)
|
||||
|
||||
def getBlockHardness(position: BlockPosition) = getBlock(position).getBlockHardness(world, position.toBlockPos)
|
||||
|
@ -2,6 +2,7 @@ package li.cil.oc.util
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer
|
||||
import net.minecraft.nbt.NBTTagCompound
|
||||
import net.minecraft.util.EnumParticleTypes
|
||||
|
||||
object PlayerUtils {
|
||||
def persistedData(player: EntityPlayer): NBTTagCompound = {
|
||||
@ -11,4 +12,15 @@ object PlayerUtils {
|
||||
}
|
||||
nbt.getCompoundTag(EntityPlayer.PERSISTED_NBT_TAG)
|
||||
}
|
||||
|
||||
def spawnParticleAround(player: EntityPlayer, effectType: EnumParticleTypes, chance: Double = 1.0): Unit = {
|
||||
val rng = player.getEntityWorld.rand
|
||||
if (chance >= 1 || rng.nextDouble() < chance) {
|
||||
val bounds = player.getEntityBoundingBox
|
||||
val x = bounds.minX + (bounds.maxX - bounds.minX) * rng.nextDouble() * 1.5
|
||||
val y = bounds.minY + (bounds.maxY - bounds.minY) * rng.nextDouble() * 0.5
|
||||
val z = bounds.minZ + (bounds.maxZ - bounds.minZ) * rng.nextDouble() * 1.5
|
||||
player.getEntityWorld.spawnParticle(effectType, x, y, z, 0, 0, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user