API
ScrollingMenuSign exposes an API to allow other plugins to query and manipulate its menus.
Here are some examples of using the API:
Building with Maven
You can use the following repository and dependency information:
<repository> <id>DH Dropbox</id> <url>http://dl.dropboxusercontent.com/u/12467600/maven-repo</url> </repository> <dependency> <groupId>me.desht</groupId> <artifactId>scrollingmenusign</artifactId> <version>RELEASE</version> <scope>provided</scope> </dependency>
Set up the handler object
High level operations like menu creation etc. are handled via the SMSHandler interface:
import me.desht.scrollingmenusign.SMSHandler; import me.desht.scrollingmenusign.SMSMenu; import me.desht.scrollingmenusign.SMSException; import me.desht.scrollingmenusign.ScrollingMenuSign; SMSHandler smsHandler; // you would call something like this from your onEnable() method static void setupSMS() { if (smsHandler == null) { Plugin p = Bukkit.getServer().getPluginManager().getPlugin("ScrollingMenuSign"); if (p != null && p instanceof ScrollingMenuSign) { ScrollingMenuSign sms = (ScrollingMenuSign) p; smsHandler = sms.getHandler(); log("ScrollingMenuSign integration is enabled"); } else { log("ScrollingMenuSign integration is not enabled"); } } }
Create a new menu
Managing individual menus is done with the SMSMenu class...
SMSMenu menu = smsHandler.createMenu("mymenu", "&1My Title", "owner-name"); if (menu != null) { menu.addItem("Day", "/time day", "It's day time!"); menu.addItem("Night", "/time night", "It's night time!"); menu.addItem("Compass", "/compass", ""); } else { // should never get here }
Delete a menu
try { smsHandler.deleteMenu("mymenu"); } catch (SMSException e) { // e.getMessage() contains an error message }
Check if a menu exists
if (smsHandler.checkMenu("mymenu")) { // .... }
Retrieve a menu by name
try { SMSMenu menu = smsHandler.getMenu("mymenu"); // ... } catch (SMSException e) { // e.getMessage() contains an error message - probably no such menu }
Iterate through all known menus
for (SMSMenu menu : smsHandler.listMenus()) { // ... }
Get the name of the menu which owns the sign the player is looking at
String menuName = smsHandler.getTargetedMenuSign(player, false); if (menuName != null) { // ... }
Creating and Using Views
To interact with menu views (sign, map, spout, redstone), you will use SMSView or one of its subclasses. Sign/multisign, map & spout views are all scrollable views, and inherit from SMSScrollableView (which inherits from SMSView). (Sign/Multisign views actually inherit from SMSGlobalScrollableView which in turn inherits from SMSScrollableView. Globally scrollable views don't have a per-player scroll position). Redstone views, not having any visual appearance, are not scrollable and inherit from SMSView directly. Inventory views do have a visual appearance, but are not scrollable, so also inherit from SMSView directly. Spout and inventory views both implement the SMSPoppableView interface, which defines methods for popping view windows up and down for players, and checking if a view has a currently-popped up window for a player.
Note that all views need to have an owner - this should either be a valid player name (views created by the SMS sync
command use the name of the player who issued the command), or ScrollingMenuSign.CONSOLE_OWNER
.
// get the view manager object ViewManager mgr = ScrollingMenuSign.getInstance().getViewManager(); // create a sign view at <loc> on the given menu (exception thrown if no sign there) Location loc = new Location(world, x, y, z); SMSSignView view = mgr.addSignToMenu(menu, loc, player.getName()); // create a map view with the map <item> and give it a custom font short mapID = item.getDurability(); SMSMapView view = mgr.addMapToMenu(menu, mapID, player.getName()); view.setAttribute(SMSMapView.FONT, "lucidaconsole"); view.setAttribute(SMSMapView.FONTSIZE, "9"); // create a Spout view and set its hotkey to "p" SMSSpoutView view = mgr.addSpoutViewToMenu(menu, player.getName()); view.setAttribute(SMSSpoutView.SPOUTKEYS, "p"); // create an Inventory view SMSInventoryView view = mgr.addInventoryViewToMenu(menu, player.getName()); // other attributes are AUTO_POPDOWN (boolean) and SPACING (integer) view.setAttribute(SMSInventoryView.WIDTH, "5"); // to show/hide the inventory view via code: view.toggleGUI(player); // scroll the view at <loc> up or down // right now, the only kind of scrollable view which has a location in the // world is a sign/multisign view, but we'll keep the code generic... SMSView view = mgr.getViewForLocation(loc); if (view != null && view instanceof SMSScrollableView) { SMSScrollableView sView = (SMSScrollableView) view; sView.scrollUp(); sView.scrollDown(); } // execute the player's currently selected item via SMSUserAction // permission & view ownership checks for the player will be carried out // SMSException will be thrown if there was a problem SMSUserAction.EXECUTE.execute(player, view);
Some other useful operations
Individual menu items are represented by objects of the SMSMenuItem class.
SMSMenu menu = smsHandler.getMenu("mymenu"); // add an item menu.addItem("Day", "/time day", "It's day time"); // remove an item menu.removeItem(1); // by numeric index menu.removeItem("Day"); // by label // sort the menu menu.sortItems(); // set the menu to autosort menu.setAutosort(true); // get the specified item SMSMenuItem item = menu.getItem(1); // by numeric index SMSMenuItem item = menu.getItem("day"); // by label // executing the item directly // permission & view ownership is bypassed if you do this // player can be null, in which case the command will be run as the console item.execute(player); /* * A repaint is always needed after any operation which changes the * menu's contents - repaints are not done automatically. This forces * all the menu's views to update their appearance. */ menu.notifyObservers();
Hooking into the Command Parser
You can use SMS's command parser from other plugins too:
setupSMS(); // ... ParsedCommand cmd = smsHandler.runCommand(player, "$E,50 /command arg1 arg2 .."); if (cmd.getStatus() != ReturnStatus.CMD_OK) { log.warn("Command failed: " + cmd.getLastError()); }
Checking for maps that SMS is using
This may be useful if your plugin also uses maps and you want to co-exist peacefully with SMS:
ViewManager mgr = ScrollingMenuSign.getInstance().getViewManager();
ItemStack item = player.getItemInHand();
if (item.getType == Material.MAP && mgr.checkForMapId(item.getDurability())) {
// this map is being used by ScrollingMenuSign
}
Real-world Examples
The ChessCraft plugin (v0.4+) uses the ScrollingMenuSign API to create menus of the boards and games in the world. Players could use these menus to quickly see what boards are available, what games are in progress, etc. See in particular https://github.com/desht/ChessCraft/blob/master/src/main/java/me/desht/chesscraft/SMSIntegration.java
Heroes (v1.4.4+) uses ScrollingMenuSign to create class-specific spell scrolls using SMSMapView.
Comments