Commands
Contents |
Introduction
In Lugdunon, commands are what drive the game state. Any action that occurs should result in a command being generated to be handled in the update loop. Commands are also the method in which the client and server communicate. Commands are specific to a given server, and are loaded from the classpath based on their inclusion in the WORLD/etc/commands.json file.
Commands are referenced in code by their unique command id. Programmatically, commands are referenced by a short int opcode, meaning that commands are limited to at most 215-1 (32767). With the exception of of net.lugdunon.command.core.ErrorCommand, net.lugdunon.command.core.GetServerStatusCommand, and net.lugdunon.command.core.ConnectToServerCommand the opcode for a command is dynamically assigned at server start and should never be relied upon to remain the same value across server instances.
A command exists as a single instance, loaded and initialized upon server start for server-side commands and upon client connect for client-side commands. Commands are referenced in code via their command id, a unique string that identifies a specific command. How to call commands on the server and client will be examined towards the end of this article.
A quick word about DataView, EnhancedDataInput/OutputStream, and String length
All traffic that passes between the client and server via commands is packaged and unpackaged using an extended version of the default DataView on the client and extended versions of the java.io.DataInputStream and java.io.DataOutputStream on the server side. The enhancements amount to providing an analogue of the java data io functionality in the client as well as providing a method for writing UTF strings with lengths > 216-1. Listed below are the mappings of calls between the client and the server:
Client (Dataview) | Server (net.lugdunon.io.EnhancedCharacterInputStream) | |
---|---|---|
readInt8() | ⇄ | readByte() |
readUint8() | ⇄ | readUnsignedByte() |
readInt16() | ⇄ | readShort() |
readUint16() | ⇄ | readUnsignedShort() |
readInt32() | ⇄ | readInt() |
readUint32() | ⇄ | readInt() |
readFloat32() | ⇄ | readFloat() |
readFloat64() | ⇄ | readDouble() |
readBoolean() | ⇄ | readBoolean() |
readString() | ⇄ | readUTF() |
readLargeString() | ⇄ | readLargeUTF() |
Client (Dataview) | Server (net.lugdunon.io.EnhancedCharacterOutputStream) | |
---|---|---|
writeInt8() | ⇄ | writeByte() |
writeUint8() | ⇄ | writeUnsignedByte() |
writeInt16() | ⇄ | writeShort() |
writeUint16() | ⇄ | writeUnsignedShort() |
writeInt32() | ⇄ | writeInt() |
writeUint32() | ⇄ | writeInt() |
writeFloat32() | ⇄ | writeFloat() |
writeFloat64() | ⇄ | writeDouble() |
writeBoolean() | ⇄ | writeBoolean() |
writeString() | ⇄ | writeUTF() |
writeLargeString() | ⇄ | writeLargeUTF() |
One last thing to note. When determining the actual length (in bytes) of a string as it is written using the DataView.writeString() and DataView.writeLargeString() it is necessary to use the String.lengthInBytes() and String.largeLengthInBytes() functions to determine the actual length.
Client Side Command API
On the client-side, commands extend the net.lugdunon.command.core.Command javascript class. There are a few default functions that require overriding:
- /**
- * Accepts a parameter containing any data used to populate this command call.
- *
- * @param {Object} initData
- */
- net.lugdunon.command.core.Command.prototype.opInit=function(initData){};
- /**
- * Returns the length (in bytes) of the command call's data.
- *
- * @returns {Number}
- */
- net.lugdunon.command.core.Command.prototype.getCommandLength=function(){return(0);};
- /**
- * Where the command call's data is actually written to the dataView object passed in.
- *
- * @param {DataView} dataView
- */
- net.lugdunon.command.core.Command.prototype.buildCommand=function(dataView){};
- /**
- * Where a command that has come in from the server is processed. The response parameter is a DataView object for reading in the response data.
- *
- * @param {DataView} response
- */
- net.lugdunon.command.core.Command.prototype.commandReponse=function(response){};
Server Side Command API
On the server-side, commands extend the net.lugdunon.command.core.Command java class. There are a few abstract methods that require implementing:
- /**
- * Returns the length (in bytes) of the command call�s data.
- *
- * @return {int}
- */
- public abstract int getCommandLength();
- /**
- * Returns the unique string value that identifies this command.
- *
- * @return {String}
- */
- public abstract String getCommandId();
- /**
- * Returns a string containing the display name of the command.
- *
- * @return {String}
- */
- public abstract String getName();
- /**
- * Returns a string containing a short description of the command.
- *
- * @return {String}
- */
- public abstract String getDescription();
- /**
- * Returns the true if the command has a client side counterpart.
- * The server will not look for a client-side asset for this command when sending the commands code to the client on initial connect.
- *
- * @return {boolean}
- */
- public abstract boolean hasClientSide();
- /**
- * Handles the actual processing of the command and its data.
- *
- * @param request - Provides access to the EnhancedDataInputStream via getData() and (if the command originated from a client) the CommandWebSocket where the command originated via getOrigin().
- *
- * @throws IOException
- * @throws ConsoleFiredCommandNotSupportedException
- */
- public abstract void handle(CommandRequest request) throws IOException, ConsoleFiredCommandNotSupportedException;
Console Fired Commands
Console fired commands are a special subset of commands that are initiated via the client-side console. Console commands consist of an initial command identifier, called an opCodeAlias, that always begins with a ‘/’ character. For a full listing of console commands, check the Console Commands section. On the client-side, commands that are capable of being fired via the console must extend the net.lugdunon.command.core.console.ConsoleFiredCommand class and override the following functions:
- /**
- * Evaluates the passed in opCodeAlias and determines if this command is a match.
- *
- * For Example, if the console line is '/df impassable' the value of opCodeAlias will be 'df'.
- *
- * @param opCodeAlias - the opCodeAlias, minus the '/' to be checked.
- * @returns {Boolean} - true if the opCodeAlias matches this command.
- */
- net.lugdunon.command.core.console.ConsoleFiredCommand.prototype.matchesConsoleOpCodeAlias=function(opCodeAlias)
- {
- return(false);
- };
- /**
- * If this command is to be handled on the client side, then this function must be implemented.
- * It should evaluate the passed in data as the console line minus the command opCodeAlias.
- *
- * For Example, if the console line is '/df impassable' the value of consoleMessage will be 'impassable'.
- *
- * @param consoleMessage - the console message minus the opCodeAlias
- */
- net.lugdunon.command.core.console.ConsoleFiredCommand.prototype.handle=function(consoleMessage)
- {
- ;
- };
On the server-side, commands that are capable of being fired via the console must extend the net.lugdunon.command.core.console.ConsoleFiredCommand abstract class and implement the following functions:
- /**
- * Evaluates the passed in opCodeAlias and determines if this command is a match.
- *
- * For Example, if the console line is '/df impassable' the value of opCodeAlias will be 'df'.
- *
- * @param {String} opCodeAlias - the opCodeAlias, minus the '/' to be checked.
- * @returns {Boolean} - true if the opCodeAlias matches this command.
- */
- public abstract boolean matchesConsoleOpCodeAlias(String opCodeAlias);
- /**
- * Evaluates the passed in data as the console line minus the command opCodeAlias.
- *
- * For Example, if the console line is '/df impassable' the value of consoleMessage will be 'impassable'.
- *
- * @param {CommandRequest} request - the request where this command originated.
- * @param {String} consoleMessage - the console message minus the opCodeAlias.
- */
- public abstract void handle(CommandRequest request, String consoleMessage) throws IOException;