DOWNLOAD
(since JARs are not allowed to be used in scripts, the .rar contains the source files, which you can include in your project)
UPDATED: The two systems have been merged. Let me know if there are any issues.
Two people came to me asking how to implement certain functionality: 1. To link certain nodes to other nodes. Since some nodes won't come after other nodes (Bank will only come after WalkToBank), there's no reason to loop through EVERY node in the script depending on the current node. How could one implement a system that only check to see which node shohld be next out of the possible nodes, not all the nodes. 2. To allow other nodes to execute while the current node is executing. When the current node is WalkToBank and your player has low hp, the script will not eat, since the current node is WalkToBank and not eat. You could add a priority system, but the problem is not "performing one node before the other"; it's performing one node while another node is processing. There exists an asynchronous node executor, which executes a node on a background thread. But this does not account for possible memory incosnistencies by implementing memory barriers. Not to mention, such a burden isn't actually needed; a single-threaded system could give the same functionality, without the need for atomicy and synchronization, as long as the script is running at a specific frame rate (a guide on that coming soon; pm me if you aren't sure what that means). I have packaged both together. I haven't tested it with an actual script (performed some lazy tests), so let me know if there are any problems with it. NodeLinkerManager The idea is to take a group of nodes, and "map" them to a specific node. For example, the WalkToBank would only be followed to the Bank node, and in a pk script, a WalkToWild node will only be followed by FightPlayer and LookForPlayer. We want to link nodes to their possible outcomes. Usually, a node based script looks like this:
class MyScript extends Script {
private List<Node> nodes;
public void onStart() {
nodes = new ArrayList<>();
nodes.add(new WalkToBank(this));
// add other nodes
}
public int onLoop() {
for(Node node : nodes)
if(node.canProcess())
node.process();
}
}
abstract class Node {
private MethodProvider api;
protected Node(MethodProvider provider) {
this.api = api;
}
protected MethodProvider api() {
return api;
}
public abstract void process();
public abstract boolean canProcess();
}
final class WalkToBank extends Node {
// ...
}
The problem with this is, depending on the amount of nodes (which increase as decomposition is applied), the for loop in the onLoop method could take longer than it needs. This is because it could be checking nodes that could not possibly come after the current node. Instead, we want to check only the nodes that could possibly come after the current node. For this, you must specify which nodes can come after which nodes. This is done through the @Linked annotation:
import fts.node.Node;
@Linked(nodes = {
Bank.class
})
final class WalkToBank extends Node {
// ...same as usual
}
The other difference is how you add nodes. First, you need to declare the NodeLinkerManager in your script. You then add the type of the node you want. Any linked nodes that are specified through the @Linked annotation are instantiated, as well as the node you specified. To ensure no excess objects are created, NodeLinkerManager handles ALL instantiation; you simply specify the type of a node through a class literal:
final class MyScript extends Script {
private NodeLinkerManager manager;
public void onStart() {
manager = new NodeLinkerManager(this);
manager.add(WalkToBank.class);
}
public int onLoop() {
manager.process();
return 2;
}
}
NodeFragmentManager There are some actions that should be performed while other actions are performing. For example, if you are fighting, you might wanna check if you should eat or pot. You could hard-code the logic into the Fight node, but what if there are actions that apply to all nodes? The node fragment system sees those actions as "node fragments". A NodeFragment is the exact same thing as a Node, other than the ability to specify a NodeFragment when creating a node. You would specify the NodeFragment through the @Fragmented annotation:
@Fragmented(fragments = {
Eat.class;
})
final class WalkToBank extends Node {
// ...
}
final class Eat extends NodeFragment {
// ...same as a regular Node
}
When the current node is WalkToBank, Eat will also process. This will allow the bot to eat while it's walking to the bank (if needed).