Code snippets
|
This page contains "snippets" of code which may be helpful in various systems.
(Check if these need to be modernized for the current state of the development environment)
Communication
Send a Command Server to Server: the Remote Call
Summary: The following snippets sets up and sends a remote call to a known AreaInstance, receives the remote call, and handles it.
NOTE: A new, easier to use syntax is now available. See: RemoteCall2
function myRemote(data as string) // This function will call to a known AreaInstance, for this example we will assume you want to call the Mission System DataBase Area 444 EditInstance 0 as a result of the User typing /Mission //Setup a RemoteCallOut "object" rmc as Class RemoteCallOut rmc.toInstance.AreaID = 444 rmc.toInstance.AreaInstanceNumber = 0 rmc.toScript = SYSTEM.EXEC.THISSCRIPT rmc.toFunction = "ReceiveMyRemote" rmc.failScript = SYSTEM.EXEC.THISSCRIPT rmc.failFunction = "MyRemoteFailHandler" // Often you will want to pass the ID of the _PlayerAccount node for the user that initiated the remote call accountid as ID = me rmc.args["AccountID"] = accountid // Likewise, it is often useful to have the character characterid as ID = playerutils:GetMyChar(AccountID) rmc.args["CharacterID"] = characterid rmc.args["MyData"] = data // Initiate the Remote Call RemoteCall(rmc)
The following function is run in the AreaInstance specified by rmc.toInstance.area(rmc.toInstance.AreaInstanceNumber) at the function specified by rmc.toFunction in the script specified by rmc.toScript.
public function ReceiveMyRemote(rmcin as Class RemoteCallIn) data as string = rmcin.args["MyData"] // TODO: Do whatever it is you want with the data .
public function MyRemoteFailHandler(rmcin as Class RemoteCallIn) // TODO: Handle the failure, either by dropping it on the floor or doing something ScriptError("MyRemote Failed because the Remote Call was unable to complete its trip, AreaInstance is down?") .
Debug messaging that finds you anywhere
Summary: MsgPlayer, unless used at the World, will only message you if you are in the same AreaInstance in which the code is running. For cross instance Debugging, this is less than ideal. That and I hate typing MsgPlayer(me, "", "Debugging information")...too many letters!"
function Debug(Message as String) rmc as Class RemoteCallOut rmc.toInstance.AreaID=0 rmc.toInstance.AreaInstanceNumber = 0 rmc.toScript = SYSTEM.EXEC.THISSCRIPT rmc.toFunction = "RemoteDebug" rmc.failScript = SYSTEM.EXEC.THISSCRIPT rmc.failFunction = "RMCFailHandler" // Hard code the accountIDs of the accounts you wish to receive the messages rmc.args["MyAccountID"] = 4487000022 rmc.args["MySecondAccountID"] = 9095000011 rmc.args["Message"] = Message remotecall(rmc) .
public function RemoteDebug(rmcin as Class RemoteCallIn) MsgPlayer(rmcin.args["MyAccountID"], "", rmcin.args["Message"]) MsgPlayer(rmcin.args["MySecondAccountID"], "", rmcin.args["Message"]) .
Now you can just type Debug("My debugging message") in your script and it will find you no matter where you are.
Lots of code that isn't working Debug("Why does this code not work, values are: variable=" + variable + " variabletwo=" + variabletwo)
Serialization
Simple - via delimited text
Summary: Turn one or more parameters into a single string that is tilda(~) delimited for transmission in a remotecall. This is also how verbs pass their data from client to server.
function myDelimiter() myDelimitedString as string = ("Insert marvelous string here." + "~" + "Failed to think." + "~" + "Are we there yet?") rmc as class RemoteCallOut rmc.toInstance.AreaID = TargetArea rmc.toInstance.AreaInstanceNumber = TargetInstance rmc.toScript = SYSTEM.EXEC.THISSCRIPT rmc.toFunction = "ReceiveMyDelimiter" rmc.failScript = SYSTEM.EXEC.THISSCRIPT rmc.failFunction = "MyRemoteFailHandler" rmc.args["DelimitedString"] = myDelimitedString RemoteCall(rmc) .
public function ReceiveMyDelimiter (rmcin as Class RemoteCallIn) myParameterList as list of string SplitBy(rmcin.args["DelimitedString"], "~", myParameterList) // myParameterList now contains // myParameterList[1] = "Insert marvelous string here." // myParameterList[2] = "Failed to think of a marvelous string." // myParameterList[3] = "Are we there yet?" // TODO: Do whatever you needed with the data .
Copy Data
From a Noderef of Class Foo to a Variable of Class Foo
Summary: Copy all of the data in class Foo on a noderef to a variable.
Assume class Foo has a field named FooField as type string and a field FooList as type list of string.
myFooNode as noderef of class Foo myFooNode.FooField = "stuff" add back "joe" to myFooNode.FooList myFooVar as Class Foo = CopyFoo(myFooNode)
function CopyFoo(myFooNode as noderef) as Class Foo Where myFoodNode is kindof Foo myFooVar as Class Foo // Copy data from the foo class myFooVar.Foo = myFooNode.Foo . default ScriptError("myFooNode is not of class foo?") . . return myFooVar .
Parsing a String
Verb options - Simple - Tokenize or SplitBy
Summary: Given a user's input via a /verb, which is transmitted as a single string, parse the string to farm processing out to other functions.
Assume the existence of a verb /myverb registered in the /REGISTER system for verbs. The server side script would look like the following.
Note: A very minor change to use the built-in function SplitBy instead of Tokenize allows you to include parameters that consist of multiple words delimited by some character(s) other than a space. Tokenize essentially performs a SplitBy with " " as the delimiter.
Usage for /myverb /myVerb (option) (target) (parameters) Valid options: VIEW (target) DOSTUFF (target) (1..n additional parameters)
shared function ProcessInput(input as string) tokens as List of String tokenize(input, tokens) if tokens.length < 3 // Inproper input since /myverb requires a target at the minimum, so call usage Usage(input) else if tolower(tokens[2]) = "view" // use the tolower function to normalize input for the purposes of the string comparisons charid as id = GetCharByNameOrID(tokens[3]) if (charid = 0) MsgPlayer(me, "", "The character (" + tokens[3] + ") is not currently in this instance.") return . View(charid) else if tolower(tokens[2]) = "dostuff" charid as id = GetCharByNameOrID(tokens[3]) if (charid = 0) MsgPlayer(me, "", "The character (" + tokens[3] + ") is not currently in this instance.") return . dostuff(input, tokens, charid) // Often it is helpful to pass both the input and the tokenized form of the input to the functions that do the actual work. . .
Utility below assumes the character is in the same AreaInstance as the code that is running. If that is not the case, it reports as if the character is not online/in the area.
function GetCharFromNameOrID(input as String) as ID verifystr as String = input verifynum as Integer = input charid as ID // Autoconversion of a string to an integer/id results in 0 if a non-number is the value of the string. // By comparing the autoconverted version with the original you can determine if it held a number 0, or was autoconverted to 0 if ((verifynum = 0) and (verifystr != targetnum)) charname as String = input accountid as ID = FindPlayerByName(charname) charnode as NodeRef = playerutils:GetMyChar(accountid) if (charnode = None) return 0 else charid = charnode . else charid = input charnode as NodeRef = charid if (charnode = None) return 0 . . return charid .