TrainCarts/API/SignAction
This TrainCarts API allows custom signs to be registered, so that the registered executor callback is automatically run when trains go past them. This makes it very easy to make trains perform unique actions using a third-party plugin.
Example Template
To begin, create a new class in your plugin with the following code:
import org.bukkit.entity.Player; import com.bergerkiller.bukkit.tc.controller.MinecartMember; import com.bergerkiller.bukkit.tc.events.SignActionEvent; import com.bergerkiller.bukkit.tc.events.SignChangeActionEvent; import com.bergerkiller.bukkit.tc.signactions.SignAction; import com.bergerkiller.bukkit.tc.signactions.SignActionType; import com.bergerkiller.bukkit.tc.utils.SignBuildOptions; /** * Displays a welcome message to the players in the train */ public class SignActionWelcome extends SignAction { @Override public boolean match(SignActionEvent info) { // Checks that the second line starts with 'welcome' (case-insensitive) return info.isType("welcome"); } @Override public void execute(SignActionEvent info) { // When a [train] sign is placed, activate when powered by redstone when the train // goes over the sign, or when redstone is activated. if (info.isTrainSign() && info.isAction(SignActionType.GROUP_ENTER, SignActionType.REDSTONE_ON) && info.isPowered() && info.hasGroup() ) { for (MinecartMember<?> member : info.getGroup()) { sendGreetingForCart(info, member); } return; } // When a [cart] sign is placed, activate when powered by redstone when each cart // goes over the sign, or when redstone is activated. if (info.isCartSign() && info.isAction(SignActionType.MEMBER_ENTER, SignActionType.REDSTONE_ON) && info.isPowered() && info.hasMember() ) { sendGreetingForCart(info, info.getMember()); return; } } public void sendGreetingForCart(SignActionEvent info, MinecartMember<?> member) { // Lines 3 and 4 configure the message to send String message = info.getLine(2) + info.getLine(3); // Send to all player passengers of the cart (could be multiple seats!) for (Player passenger : member.getEntity().getPlayerPassengers()) { passenger.sendMessage(message); } } @Override public boolean build(SignChangeActionEvent event) { // This is executed when a player places down a sign matching this sign action // Permissions are checked and then a message is displayed to the player // For simplicity you can use the SignBuildOptions API for this. // You are free to use your own code here that checks permissions/etc. return SignBuildOptions.create() .setName(event.isCartSign() ? "cart welcome greeter" : "train welcome greeter") .setDescription("sends a welcome message to all players in the train") .handle(event.getPlayer()); } }
This is a simple example of a sign that sends a message to all players in the train. By default signs will support the standard TrainCarts conventions for the first line, where redstone options can be configured. The second line is typically used to match the sign type, and the last two lines are free to be used for anything.
To register the above class, perform the following in your plugin's main class:
import org.bukkit.plugin.java.JavaPlugin; import com.bergerkiller.bukkit.tc.signactions.SignAction; public class TCWelcomeSign extends JavaPlugin { public final SignActionWelcome signActionWelcome = new SignActionWelcome(); @Override public void onEnable() { // Register the signs SignAction.register(signActionWelcome); } @Override public void onDisable() { // Unregister the signs to prevent problems during /reload SignAction.unregister(signActionWelcome); } }
It is important to both register and unregister the sign. That way, when the server is reloaded, or the plugin or reloaded using for example PlugMan, things don't break.
The Execute Method
Various events are sent to signs and can be handled by the sign. All events are handled through the execute(event) callback.
Cart/Train Enter and Leave
When each individual cart hits a piece of track with a sign matching the sign action, the MEMBER_ENTER event is fired. When they move off the track again, a MEMBER_LEAVE event is fired. Similarly, for entire trains, a GROUP_ENTER and GROUP_LEAVE is fired.
Redstone
When the sign becomes powered from an unpowered state, REDSTONE_ON and REDSTONE_CHANGE fire. In reverse, REDSTONE_OFF and REDSTONE_CHANGE fire. When the power state doesn't change, but other blocks nearby change redstone levels that might influence the sign behavior, just REDSTONE_CHANGE is fired. The event has helper methods to figure out the power state of the sign or a given direction of the sign.
Movement
Every tick, while the train is moving, a MEMBER_MOVE event is fired. By default through, this is disabled for performance reasons. To use this event, override isMemberMoveHandled(event) and return true there.
Updates
When players enter the train, leave it, properties change or other similar events occur, a MEMBER_UPDATE event fires. This is useful if the sign uses such information to, for example, toggle a lever.
Loaded Changed Event
The loadedChanged(event, loaded) method can be overrided to get notified when a sign matching this sign action is loaded or unloaded on the server. A sign is loaded when placed, or when a chunk loads with the sign in it. A sign is unloaded when destroyed, or when a chunk unloads with the sign in it. Be careful not to load or unload chunks in this method. This is a useful method to cache data in memory while the sign is in use.
Remote Control
Remote control enables the sign to be activated by redstone, to then operate on one or more trains by name pattern. To use remote control with the sign, override canSupportRC() and return true.
Path Finding
Some advanced methods can be overrided to make the sign act as a node in the path-finding network:
- isRailSwitcher(event) - Return true if this sign switches the rails from/to any direction
- getRailDestinationName(event) - Return non-null to provide a unique destination name
- isPathFindingBlocked(event, railState) - Return true to tell the path finding algorithm that in this direction no further movement is possible