HeroScript Extension Plugin

From HEWIKI
Jump to: navigation, search


Contents

He advanced.png

Note: This page gives a general overview of HeroScript Extensions. For implementation details, please see the HSEIDemo download.

Overview

Both the client and the servers support dynamically loaded plugins which add HeroScript external functions, as of HeroEngine version 1.19.0. The same interface is used for both client and server. This page describes the external functions which control the plugins. The C++ API which is used to create a plugin is also documented here.

Dynamic Loading

A unique feature of the plugin architecture is that it supports the concept of dynamically loading and unloading plugins without restarting either the client or the server. In this way you can easily update plugins and iterate rapidly during plug-in development.

Built-in Functions

The following built-in functions are available in both client and server scripting environments. On the server side, they are available in area servers, but not the world server.

Load Script Plugin

This function loads a DLL plugin containing external functions.

It will return FALSE if:

external function LoadScriptPlugin(pluginDllName as String) as Boolean

Unload Script Plugin

This function unloads a previously loaded DLL. It will return false if the DLL was not loaded with the LoadScriptPlugin() function.

external function UnloadScriptPlugin(pluginDllName as String) as Boolean

List Loaded Script Plugins

This function returns a list of the loaded plugin DLLs.

external function ListLoadedScriptPlugins() as List of String

Is Script Plugin Loaded

This query will return TRUE if the named plugin DLL is currently loaded.

external function IsScriptPluginLoaded(pluginDllName as String) as Boolean

Set Script Plugin Pump

All loaded plugin DLLs have a pump function which is called periodically. By default the plugins will be pumped; however this function can toggle this behavior on or off. If called on a plugin which is not loaded, a script error will be thrown.

external function SetScriptPluginPump(pluginDllName as String, pumpPlugin as Boolean)

Definitions of External Functions in Plugins

The HeroScript Compiler needs function signature definitions to compile scripts which call external functions. While the script _ExternalFunctions is used to provide signatures for built-in and external functions that come with HeroEngine, it should not be edited by licensees, since publishes will overwrite any changes. Instead, the game-specific script ExternalFunctions should be edited, and game-specific function signatures for plugins added to that one instead.

HeroScriptExtensionInterface C++ API

To be a valid script plugin, a DLL must export a pair of extern C functions for getting and releasing an object pointer. The object returned must inherit from the HeroScriptExtensionInterface class.

Exported DLL Functions

The getHSLInterface() function should return a pointer to the HeroScriptExtensionInterface instantiation. If the function returns NULL, the DLL load process will fail gracefully.

The function releaseHSLInterface(), if it exists, is called before unloading the DLL. All allocated resources should be cleaned up at this point. If this function does not exist in the plugin, or returns a nonzero value, the plugin will be unloaded. A return value of zero indicates that it is not safe to unload this plugin.

extern "C" {

__declspec(dllexport) __cdecl HSEI::HeroScriptExtensionInterface * getHSLInterface(int version_number);

__declspec(dllexport) __cdecl int releaseHSLInterface(HSEI::HeroScriptExtensionInterface * aInterface);

}

HeroScriptExtensionInterface Class Declaration

This class should be inherited from in the plugin. The init() function is called

namespace HEROSCRIPTEXTENSIONINTERFACE
{
  class HeroScriptExtensionInterface
  {
    public:
      virtual bool init(HeroScript::PluginInterface * scriptInterface) = 0;
      virtual void pump() = 0;
  };

};

namespace HSEI = HEROSCRIPTEXTENSIONINTERFACE;

Demo example

An example implementation of the HeroScript Extension Interface is provided on the downloads page, HSEIDemo.zip. Within this file, are files with compilable C++ code, and an HSL script. The code can be compiled to create a special DLL that adds new example external functions to HeroScript.

Once compiled, the DLL is put into the install directory on the client. A sample script then calls the load/unload functions which make the new DLL-enabled functions available to HSL. The sample script also has examples of functions which call the new DLL-enabled functions, via a CALL command.

Modifying the ExternalFunctions Script

To access the external functions in the plugin, the following function signatures must be added to the ExternalFunctions script.

external function DemoAdd(a as Integer, b as Integer) as Integer
 
external function DemoSubtractAsync(callbackScript as String, minuend as Float, subtrahend as Float)
 
external function DemoModifyRawData(callbackNode as ID, someData references RawData)
 
external function DemoGetRawDataLength(someData as RawData) as Integer

Example of Calling Demo Plugin

function LoadDemoPlugin()
  if ( LoadScriptPlugin("hseidemo.dll") )
    // The default is to pump plugins, so this code is not necessary, but included for completeness
    SetScriptPluginPump("hseidemo.dll", true)
  .
.
 
function UseDemoAdd()
  var sum = DemoAdd(1, 2)
  $CHAT.CHATAREA("default", "The sum is " + sum)
.
 
function UseDemoSubtractAsync()
  DemoSubtractAsync(SYSTEM.EXEC.THISSCRIPT, 3.5, 1.2)
.
 
// This function is called during the next pump cycle
function DemoSubtractionResult(difference as Float)
  $CHAT.CHATAREA("default", "The difference is " + difference)
.
 
// This function requires that a class and field be defined in the DOM
// class DemoRawData, archetype DATA, field DemoRawData
// field DemoRawDataField, type RAWDATA
// A script needs to be created named DemoRawDataClassMethods, and in the
// script, the method DemoRawDataModified() must be defined
 
function UseDemoModifyRawData()
  node as NodeRef of Class DemoRawData = CreateNodeFromClass("DemoRawData")
 
  DemoModifyRawData(node, node.DemoRawDataField)
 
  // clean up the node since we don't have any other references to it
  DestroyNode(node)
.

Script DemoRawDataClassMethods

method DemoRawDataModified()
  $CHAT.CHATAREA("default", "The raw data was modified")
.

Plugin Installation

For worlds that are hosted in HeroEngine's data center, we do not support uploading externally developed server plugins. You can, however, write client plugins and install the dll manually (i.e. copy/paste).

Faster iteration cycles during development are possible by:

Server Plugins

Server plugins should be placed in the Firestorm Daemons directory or in the run directory of the executable that will load the plugin (i.e. the area server directory). The FireStorm Daemons directory is checked first and therefore preferred.

Our recommendation is that the installation of your plugins be via the normal deploy mechanism.

Client Plugins

Client plugins should be placed in the run directory of the PlayerClient and/or HeroBlade. Installation is normally performed via the normal update/installation process.

Diagnosing Plugin Loading Problems

 To diagnose loading problems, there are two approaches. The first approach is to use a debugger to observe the load process and check for errors. The second is to examine the plugin with an external program to determine if there are unsatisfied dependencies which prevent the plugin from loading. Source for a simple plugin loader is included in the following pages:

Test Loader for Windows HeroScript Extension Plugins

Test Loader for Linux HeroScript Extension Plugins


If the test application throws "application configuration is incorrect errors," the number one thing to check is the dependencies on other DLLs in the plug-in, especially upon the Debug CRT runtimes (which are not installed on the server, nor should they be in a production environment) using the Visual Studio tools command prompt, with this command:

 DUMPBIN /DEPENDENTS plugin.DLL

while looking for the Microsoft Visual C Runtimes (MSVCR##.dll) and Visual C-Plus-plus runtimes (MSVCP##.dll). If the version says MSVCR80D.dll instead of MSVCR80.dll, then that is definitely related to debug runtimes.

 C:\p4\depot\HeroEngine\MAIN\heroblade\Run>dumpbin heclient.dll /dependents
Microsoft (R) COFF/PE Dumper Version 9.00.30729.01
Copyright (C) Microsoft Corporation.  All rights reserved.
Dump of file heclient.dll
File Type: DLL
Image has the following dependencies:
  gdiplus.dll
  COMCTL32.dll
  KERNEL32.dll
  USER32.dll
  GDI32.dll
  ole32.dll
  HEPlatformInterface.dll
  stlport.5.2.dll
  MSVCR90.dll                     <<<<
  BugslayerUtil.dll
  MSVCP90.dll                     <<<<
  SHFOLDER.dll
  granny2.dll
  d3d9.dll
  d3dx9_41.dll
  SpeedTreeRT.dll
  VERSION.dll
  DINPUT8.dll
  PSAPI.DLL
  WINMM.dll
  firestorm.dll
  PLOAD.dll
  COMDLG32.dll
  ADVAPI32.dll
  APEX_release.dll
Summary
    4B4000 .data
    21D000 .rdata
     C1000 .reloc
      8000 .rsrc
    869000 .text
      1000 .tls
C:\p4\depot\HeroEngine\MAIN\heroblade\Run>

Secondly, double-check that the list of dependent DLLs beyond the standard ones are available on the system -- the test tool will help you through this process.

See also

Personal tools
Namespaces
Variants
Actions
Navigation
Toolbox