Difference between revisions of "Event Handler"

From Legends of Aria Admin and Modding Wiki
Jump to: navigation, search
 
(29 intermediate revisions by one other user not shown)
Line 1: Line 1:
DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT
+
== Definition ==
DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT DRAFT
+
An Event Handler is a function registered in a special way to be called when certain things (events) happen.
 +
== Official Documentation ==
 +
Official Events Documentation: [[http://shardsonline.com/lN2rwhz4jSVambqesEBZ/lua-reference/events.html Events]]
 +
== Registering an EventHandler ==
 +
* Registering a function as EventHandler in its general abstract form is:
 +
RegisterEventHandler( (EventType)mEvent, (string)mEventIdentifier, (function)mEventHandler)
 +
The registered function can also be declared inline:
 +
RegisterEventHandler( (EventType)mEvent, (string)mEventIdentifier,
 +
          function(...)
 +
              -- Do Stuff --
 +
          end
 +
)
 +
 
 +
{| class="wikitable"
 +
|-
 +
! Header text !! Header text !! Header text
 +
|-
 +
| Example || Example || Example
 +
|-
 +
| Example || Example || Example
 +
|-
 +
| Example || Example || Example
 +
|}
 +
 
 +
== Event Types ==
 +
{| class="wikitable"
 +
! EventType !! Parameters !! Description
 +
|-
 +
| EventType.Arrived ||
 +
|-
 +
| EventType.ClientUserCommand ||
 +
|-
 +
| EventType.ClientObjectCommand ||
 +
|-
 +
| EventType.ClientTargetAnyObjResponse ||
 +
|-
 +
| EventType.ClientTargetGameObjResponse ||
 +
|-
 +
| EventType.ClientTargetLocResponse ||
 +
|-
 +
| EventType.ContainerItemAdded ||
 +
|-
 +
| EventType.ContainerItemRemoved ||
 +
|-
 +
| EventType.ContextMenuResponse ||
 +
|-
 +
| EventType.CreatedObject || || Fired upon item creation.
 +
|-
 +
| EventType.Destroyed || || Fired on [[GameObject]].Destroy()
 +
|-
 +
| EventType.DynamicWindowResponse ||
 +
|-
 +
| EventType.EnterView ||
 +
|-
 +
| EventType.GlobalVarUpdateResult ||
 +
|-
 +
| EventType.ItemEquipped ||
 +
|-
 +
| EventType.ItemUnequipped ||
 +
|-
 +
| EventType.LoadedFromBackup || || Fired when a module is 'attached' from backup data, useful for putting something back into the state it was last in. Think player login and server startup loading from backup files.
 +
|-
 +
| EventType.LeaveView ||
 +
|-
 +
| EventType.Message || [[Message]] ID || Fired when a [[Message]] is received.
 +
|-
 +
| EventType.ModuleAttached || [[Module]] Name || Fired when the [[Module]] this is declared in is attached to another [[GameObject]]
 +
|-
 +
| EventType.PlayerSpeech ||
 +
|-
 +
| EventType.RequestDrop ||
 +
|-
 +
| EventType.RequestEquip ||
 +
|-
 +
| EventType.RequestPickUp ||
 +
|-
 +
| EventType.StartMoving ||
 +
|-
 +
| EventType.Timer || [[Timer]] ID || Fired when a [[ScheduleTimerDelay]] completes.
 +
|-
 +
| EventType.Use ||
 +
|-
 +
| EventType.UserLogout ||
 +
|}
 +
 
 +
Example:
 +
RegisterEventHandler(EventType.Timer, "MyCoolestTimer", HandleTick)
 +
Explanation: This Registers the Function "HandleTick" as Handler for the Timer named "MyCoolestTimer", and it is called whenever this specific timer fires.
 +
 
 +
An inline function definition for this timer would look like this:
 +
RegisterEventHandler(EventType.Timer, "MyCoolestTimer",
 +
      function()
 +
          print("MyCoolestTimer just fired")
 +
      end
 +
)
  
  An Event Handler is a function registered in a special way to be called when certain things (events) happen.
+
<br>E.G. <code>this:FireTimer("MyCoolestTimer")</code> would fire the timer and thus call the "HandleTick" function.
 +
You can optionally pass data to an event when triggering it and thus give this data to the Event Handler.
 +
<br>E.G: in the last Example we could have called <code>this:FireTimer("MyCoolestTimer",{name="MyData",content="Stuff"})</code> which would pass a table to the timer and the handler. If the handler can handle this data depends on its definition.
 +
<br>Also: '''Some events pass default data to the handlers, it is necessary to know which events pass which data'''. You can find this information in the official documentation.
 +
 
 +
== Declaring EventHandlers ==
 +
As you could see above, the functions handling the triggered events can be declared externally or inline inside the [[RegisterEventHandler]] function.
 +
<br> Whatever you do: To let these functions do something meaningful they usually need to get some data and thus the following rule applies:
 +
A function definition for an EventHandler, be it declared inline or externally must declare its parameters in a way which is predefined by the type of the event it is handling. Handlers for Timer Events have different parameters than Handlers for Message or CreatedObject events. Otherwise errors occur or the function simply has no data available.
 +
 
 +
Check the official documentation to find out about these parameters
 +
If we want to use a timer like this:
 +
<syntaxhighlight lang="lua">
 +
  this:FireTimer("MyCoolTimer", {name="Stuff", data = "Moar Stuff"} )
 +
</syntaxhighlight>
 +
 
 +
we have to declare the Handler accordingly either inline:
 +
<syntaxhighlight lang="lua">
 +
RegisterEventHandler(EventType.Timer, "MyCoolTimer",
 +
  function(data)
 +
      -- tostring is used for handling nil values and numbers or table data properly
 +
      print(tostring(data.name).." is the name and "..tostring(data.data).." is the data")
 +
  end
 +
)
 +
</syntaxhighlight>
 +
Or externally:
 +
<syntaxhighlight lang="lua">
 +
function HandleCoolTimer(data)
 +
      -- tostring is used for handling nil values and numbers or table data properly
 +
      print(tostring(data.name).." is the name and "..tostring(data.data).." is the data")
 +
end
 +
 
 +
RegisterEventHandler(EventType.Timer, "MyCoolTimer", HandleCoolTimer )
 +
 
 +
</syntaxhighlight>
 +
 
 +
== Overriding and Modding EventHandlers ==
 +
[[OverrideEventHandler]]
 +
 
 +
The Problem:
 +
<br>''Building upon functions defined within event handlers''
 +
<br>''In an attempt to avoid excessive code maintenance when the base code changes between versions, I am trying to write all my mods as stand alone methods which override existing methods (and sometimes refer to the super method). This is working in most cases, but I have hit a few snags in which the base script defines a method directly within an EventHandler. For these situations I have been using OverrideEventHandler and then copying the entire base function and putting in my changes. Is there a better way to do this so I can avoid
 +
copying base code (in case of future changes)?''
 +
<br>[[http://shardsonline.com/forums/discussion/comment/9494/#Comment_9494 Forum Link]]
 +
 
 +
 
 +
The basic problem concerning modding here is to understand, that the [[RegisterEventHandler]] function links the event to the address of the function, not the function identifier (function name). Thus, if you mod the function you simply pirate the name of it and put your own stuff into it, but the event still works with the original function at the old address.
 +
<br>The following writeup illustrates the issue:
 +
 
 +
Situation - A -
 +
 
 +
<syntaxhighlight lang="lua">
 +
-- OriginalScript.lua
 +
RegisterEventHandler(EventType.Message,"TestMessage",
 +
    function()
 +
        DebugMessage("Just a test")
 +
    end
 +
)
 +
</syntaxhighlight>
 +
 
 +
The situation above has to be resolved by copying the code.
 +
<br>Your override would look like:
 +
 
 +
<syntaxhighlight lang="lua">
 +
-- OriginalScript.lua - modded version in mods/mymod/scripts
 +
require 'default:OriginalScript'
 +
OverrideEventHandler("default:OriginalScript",EventType.Message,"TestMessage",
 +
    function()
 +
        DebugMessage("Just a test")
 +
        DebugMessage("Modded additional Info")
 +
    end
 +
)
 +
</syntaxhighlight>
 +
 
 +
Situation - B -
 +
 
 +
<syntaxhighlight lang="lua">
 +
-- AnotherOriginalScript.lua
 +
function HandleTestMessage()
 +
    DebugMessage("Just a test")
 +
end
 +
RegisterEventHandler(EventType.Message,"TestMessage", HandleTestMessage)
 +
</syntaxhighlight>
 +
 
 +
This is better code. Still not optimal, since it requires to override the eventhandler if you alter the function or it will use the old function,
 +
despite your override. Your override would look like:
 +
 
 +
<syntaxhighlight lang="lua">
 +
-- AnotherOriginalScript.lua -- modded version
 +
require 'default:AnotherOriginalScript'
 +
OldHandleTestMessage = HandleTestMessage
 +
function HandleTestMessage()
 +
    OldHandleTestMessage()
 +
    DebugMessage("Modded additional Info")
 +
end
 +
OverrideEventHandler("AnotherOriginalScript",EventType.Message,"TestMessage", HandleTestMessage)
 +
</syntaxhighlight>
 +
 
 +
Situation - C -
 +
 
 +
<syntaxhighlight lang="lua">
 +
-- AndFinallyAThirdScript.lua
 +
function FinallyDoTheTestMessage() DebugMessage("Just a test") end
 +
function HandleTestMessage() FinallyDoTheTestMessage() end
 +
RegisterEventHandler(EventType.Message,"TestMessage", HandleTestMessage)
 +
</syntaxhighlight>
  
Official Events Documentation: [[http://shardsonline.com/lN2rwhz4jSVambqesEBZ/lua-reference/events.html Events]]
+
Most convenient solution:
 +
You can safely override FinallyDoTheTestMessage() without touching the event handler,
 +
but it adds another function call. Your modded script would look like:
  
* Registering a function as Event Handler in its general abstract form is:
+
<syntaxhighlight lang="lua">
RegisterEventHandler( (EventType)mEvent, (string)mEventIdentifier, (function)mEventHandler)  
+
-- AndFinallyAThirdScript.lua -- modded version
 +
require 'AndFinallyAThirdScript'
 +
OldFinallyDoTheTestMessage = FinallyDoTheTestMessage
 +
function FinallyDoTheTestMessage()
 +
    OldFinallyDoTheTestMessage()
 +
    DebugMessage("Modded additional Info")
 +
end
 +
</syntaxhighlight>
  
<code>mEvent</code> can be one of the following events:
 
EventType.LoadedFromBackup
 
EventType.Destroyed
 
EventType.CreatedObject
 
EventType.ModuleAttached
 
EventType.Timer
 
EventType.Message
 
EventType.EnterView
 
EventType.LeaveView
 
EventType.RequestPickUp
 
EventType.RequestDrop
 
EventType.RequestEquip
 
EventType.ContainerItemAdded
 
EventType.ContainerItemRemoved
 
EventType.ItemEquipped
 
EventType.ItemUnequipped
 
EventType.StartMoving
 
EventType.Arrived
 
EventType.Use
 
EventType.PlayerSpeech
 
EventType.ClientUserCommand
 
EventType.ClientObjectCommand
 
EventType.ClientTargetAnyObjResponse
 
EventType.ClientTargetGameObjResponse
 
EventType.ClientTargetLocResponse
 
EventType.ContextMenuResponse
 
EventType.DynamicWindowResponse
 
EventType.UserLogout
 
EventType.GlobalVarUpdateResult
 
  
[[Category:Drafts]]
+
[[Category:Drafts]][[Category:Event]]

Latest revision as of 18:52, 6 November 2016

Definition

An Event Handler is a function registered in a special way to be called when certain things (events) happen.

Official Documentation

Official Events Documentation: [Events]

Registering an EventHandler

  • Registering a function as EventHandler in its general abstract form is:
RegisterEventHandler( (EventType)mEvent, (string)mEventIdentifier, (function)mEventHandler) 

The registered function can also be declared inline:

RegisterEventHandler( (EventType)mEvent, (string)mEventIdentifier, 
         function(...) 
              -- Do Stuff -- 
         end
)
Header text Header text Header text
Example Example Example
Example Example Example
Example Example Example

Event Types

EventType Parameters Description
EventType.Arrived
EventType.ClientUserCommand
EventType.ClientObjectCommand
EventType.ClientTargetAnyObjResponse
EventType.ClientTargetGameObjResponse
EventType.ClientTargetLocResponse
EventType.ContainerItemAdded
EventType.ContainerItemRemoved
EventType.ContextMenuResponse
EventType.CreatedObject Fired upon item creation.
EventType.Destroyed Fired on GameObject.Destroy()
EventType.DynamicWindowResponse
EventType.EnterView
EventType.GlobalVarUpdateResult
EventType.ItemEquipped
EventType.ItemUnequipped
EventType.LoadedFromBackup Fired when a module is 'attached' from backup data, useful for putting something back into the state it was last in. Think player login and server startup loading from backup files.
EventType.LeaveView
EventType.Message Message ID Fired when a Message is received.
EventType.ModuleAttached Module Name Fired when the Module this is declared in is attached to another GameObject
EventType.PlayerSpeech
EventType.RequestDrop
EventType.RequestEquip
EventType.RequestPickUp
EventType.StartMoving
EventType.Timer Timer ID Fired when a ScheduleTimerDelay completes.
EventType.Use
EventType.UserLogout

Example:

RegisterEventHandler(EventType.Timer, "MyCoolestTimer", HandleTick)

Explanation: This Registers the Function "HandleTick" as Handler for the Timer named "MyCoolestTimer", and it is called whenever this specific timer fires.

An inline function definition for this timer would look like this:

RegisterEventHandler(EventType.Timer, "MyCoolestTimer", 
     function()
          print("MyCoolestTimer just fired")
     end
)


E.G. this:FireTimer("MyCoolestTimer") would fire the timer and thus call the "HandleTick" function. You can optionally pass data to an event when triggering it and thus give this data to the Event Handler.
E.G: in the last Example we could have called this:FireTimer("MyCoolestTimer",{name="MyData",content="Stuff"}) which would pass a table to the timer and the handler. If the handler can handle this data depends on its definition.
Also: Some events pass default data to the handlers, it is necessary to know which events pass which data. You can find this information in the official documentation.

Declaring EventHandlers

As you could see above, the functions handling the triggered events can be declared externally or inline inside the RegisterEventHandler function.
Whatever you do: To let these functions do something meaningful they usually need to get some data and thus the following rule applies:

A function definition for an EventHandler, be it declared inline or externally must declare its parameters in a way which is predefined by the type of the event it is handling. Handlers for Timer Events have different parameters than Handlers for Message or CreatedObject events. Otherwise errors occur or the function simply has no data available.

Check the official documentation to find out about these parameters If we want to use a timer like this:

 this:FireTimer("MyCoolTimer", {name="Stuff", data = "Moar Stuff"} )

we have to declare the Handler accordingly either inline:

RegisterEventHandler(EventType.Timer, "MyCoolTimer", 
   function(data) 
      -- tostring is used for handling nil values and numbers or table data properly
      print(tostring(data.name).." is the name and "..tostring(data.data).." is the data")
   end
)

Or externally:

function HandleCoolTimer(data)
      -- tostring is used for handling nil values and numbers or table data properly
      print(tostring(data.name).." is the name and "..tostring(data.data).." is the data")
end

RegisterEventHandler(EventType.Timer, "MyCoolTimer", HandleCoolTimer )

Overriding and Modding EventHandlers

OverrideEventHandler

The Problem:
Building upon functions defined within event handlers
In an attempt to avoid excessive code maintenance when the base code changes between versions, I am trying to write all my mods as stand alone methods which override existing methods (and sometimes refer to the super method). This is working in most cases, but I have hit a few snags in which the base script defines a method directly within an EventHandler. For these situations I have been using OverrideEventHandler and then copying the entire base function and putting in my changes. Is there a better way to do this so I can avoid copying base code (in case of future changes)?
[Forum Link]


The basic problem concerning modding here is to understand, that the RegisterEventHandler function links the event to the address of the function, not the function identifier (function name). Thus, if you mod the function you simply pirate the name of it and put your own stuff into it, but the event still works with the original function at the old address.
The following writeup illustrates the issue:

Situation - A -

-- OriginalScript.lua
RegisterEventHandler(EventType.Message,"TestMessage",
    function()
        DebugMessage("Just a test")
    end
)

The situation above has to be resolved by copying the code.
Your override would look like:

-- OriginalScript.lua - modded version in mods/mymod/scripts
require 'default:OriginalScript'
OverrideEventHandler("default:OriginalScript",EventType.Message,"TestMessage",
    function()
        DebugMessage("Just a test")
        DebugMessage("Modded additional Info")
    end
)

Situation - B -

-- AnotherOriginalScript.lua
function HandleTestMessage()
    DebugMessage("Just a test")
end
RegisterEventHandler(EventType.Message,"TestMessage", HandleTestMessage)

This is better code. Still not optimal, since it requires to override the eventhandler if you alter the function or it will use the old function, despite your override. Your override would look like:

-- AnotherOriginalScript.lua -- modded version
require 'default:AnotherOriginalScript'
OldHandleTestMessage = HandleTestMessage
function HandleTestMessage()
    OldHandleTestMessage()
    DebugMessage("Modded additional Info")
end
OverrideEventHandler("AnotherOriginalScript",EventType.Message,"TestMessage", HandleTestMessage)

Situation - C -

-- AndFinallyAThirdScript.lua
function FinallyDoTheTestMessage() DebugMessage("Just a test") end
function HandleTestMessage() FinallyDoTheTestMessage() end
RegisterEventHandler(EventType.Message,"TestMessage", HandleTestMessage)

Most convenient solution: You can safely override FinallyDoTheTestMessage() without touching the event handler, but it adds another function call. Your modded script would look like:

-- AndFinallyAThirdScript.lua -- modded version
require 'AndFinallyAThirdScript'
OldFinallyDoTheTestMessage = FinallyDoTheTestMessage
function FinallyDoTheTestMessage()
    OldFinallyDoTheTestMessage()
    DebugMessage("Modded additional Info")
end