Code snippets

From HEWIKI
(Redirected from Technical:Code Snippets)
Jump to: navigation, search

Contents

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
.
Personal tools
Namespaces
Variants
Actions
Navigation
Toolbox