1
0
forked from 0ad/0ad

Allow registering custom data for triggers

This allows easier handling of e.g. range triggers calling into the same
function.

The original trigger data is also forwarded for convenience.

Differential Revision: https://code.wildfiregames.com/D3904
This was SVN commit r25413.
This commit is contained in:
wraitii 2021-05-09 16:55:36 +00:00
parent f653541e2c
commit 8f8996e338
2 changed files with 85 additions and 53 deletions

View File

@ -76,6 +76,7 @@ Trigger.prototype.GetTriggerPoints = function(ref)
* @param {string} name - Name of the trigger. * @param {string} name - Name of the trigger.
* If no action is specified in triggerData, the action will be the trigger name. * If no action is specified in triggerData, the action will be the trigger name.
* @param {Object} triggerData - f.e. enabled or not, delay for timers, range for range triggers. * @param {Object} triggerData - f.e. enabled or not, delay for timers, range for range triggers.
* @param {Object} customData - User-defined data that will be forwarded to the action.
* *
* @example * @example
* triggerData = { enabled: true, interval: 1000, delay: 500 } * triggerData = { enabled: true, interval: 1000, delay: 500 }
@ -91,7 +92,7 @@ Trigger.prototype.GetTriggerPoints = function(ref)
* maxRange = -1 * Maximum range for the query (-1 = no maximum) * maxRange = -1 * Maximum range for the query (-1 = no maximum)
* requiredComponent = 0 * Required component id the entities will have * requiredComponent = 0 * Required component id the entities will have
*/ */
Trigger.prototype.RegisterTrigger = function(event, name, triggerData) Trigger.prototype.RegisterTrigger = function(event, name, triggerData, customData = undefined)
{ {
if (!this[event]) if (!this[event])
{ {
@ -110,7 +111,7 @@ Trigger.prototype.RegisterTrigger = function(event, name, triggerData)
if (!triggerData.action) if (!triggerData.action)
triggerData.action = name; triggerData.action = name;
this[event][name] = triggerData; this[event][name] = { "triggerData": triggerData, "customData": customData };
// setup range query // setup range query
if (event == "OnRange") if (event == "OnRange")
@ -141,90 +142,70 @@ Trigger.prototype.DisableTrigger = function(event, name)
{ {
if (!this[event][name]) if (!this[event][name])
{ {
warn("Trigger.js: Disabling unknown trigger"); warn("Trigger.js: Disabling unknown trigger " + name);
return; return;
} }
let data = this[event][name];
let triggerData = this[event][name].triggerData;
// special casing interval and range triggers for performance // special casing interval and range triggers for performance
if (event == "OnInterval") if (event == "OnInterval")
{ {
if (!data.timer) // don't disable it a second time if (!triggerData.timer) // don't disable it a second time
return; return;
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
cmpTimer.CancelTimer(data.timer); cmpTimer.CancelTimer(triggerData.timer);
data.timer = null; triggerData.timer = null;
} }
else if (event == "OnRange") else if (event == "OnRange")
{ {
if (!data.queries) if (!triggerData.queries)
{ {
warn("Trigger.js: Range query wasn't set up before trying to disable it."); warn("Trigger.js: Range query wasn't set up before trying to disable it.");
return; return;
} }
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
for (let query of data.queries) for (let query of triggerData.queries)
cmpRangeManager.DisableActiveQuery(query); cmpRangeManager.DisableActiveQuery(query);
} }
data.enabled = false; triggerData.enabled = false;
}; };
Trigger.prototype.EnableTrigger = function(event, name) Trigger.prototype.EnableTrigger = function(event, name)
{ {
if (!this[event][name]) if (!this[event][name])
{ {
warn("Trigger.js: Enabling unknown trigger"); warn("Trigger.js: Enabling unknown trigger " + name);
return; return;
} }
let data = this[event][name]; let triggerData = this[event][name].triggerData;
// special casing interval and range triggers for performance // special casing interval and range triggers for performance
if (event == "OnInterval") if (event == "OnInterval")
{ {
if (data.timer) // don't enable it a second time if (triggerData.timer) // don't enable it a second time
return; return;
if (!data.interval) if (!triggerData.interval)
{ {
warn("Trigger.js: An interval trigger should have an intervel in its data"); warn("Trigger.js: An interval trigger should have an intervel in its data");
return; return;
} }
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
data.timer = cmpTimer.SetInterval(this.entity, IID_Trigger, "DoAction", triggerData.timer = cmpTimer.SetInterval(this.entity, IID_Trigger, "DoAction",
data.delay || 0, data.interval, { "name": name }); triggerData.delay || 0, triggerData.interval, { "name": name });
} }
else if (event == "OnRange") else if (event == "OnRange")
{ {
if (!data.queries) if (!triggerData.queries)
{ {
warn("Trigger.js: Range query wasn't set up before"); warn("Trigger.js: Range query wasn't set up before");
return; return;
} }
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
for (let query of data.queries) for (let query of triggerData.queries)
cmpRangeManager.EnableActiveQuery(query); cmpRangeManager.EnableActiveQuery(query);
} }
data.enabled = true; triggerData.enabled = true;
};
/**
* This function executes the actions bound to the events.
* It's either called directlty from other simulation scripts,
* or from message listeners in this file
*
* @param {string} event - One of eventNames
* @param {Object} data - will be passed to the actions
*/
Trigger.prototype.CallEvent = function(event, data)
{
if (!this[event])
{
warn("Trigger.js: Unknown trigger event called:\"" + event + "\".");
return;
}
for (let name in this[event])
if (this[event][name].enabled)
this.DoAction({ "action": this[event][name].action, "data": data });
}; };
Trigger.prototype.OnGlobalInitGame = function(msg) Trigger.prototype.OnGlobalInitGame = function(msg)
@ -298,15 +279,15 @@ Trigger.prototype.OnGlobalDiplomacyChanged = function(msg)
* *
* @param {number} time - Delay in milliseconds. * @param {number} time - Delay in milliseconds.
* @param {string} action - Name of the action function. * @param {string} action - Name of the action function.
* @param {Object} data - Arbitrary object that will be passed to the action function. * @param {Object} eventData - Arbitrary object that will be passed to the action function.
* @return {number} The ID of the timer, so it can be stopped later. * @return {number} The ID of the timer, so it can be stopped later.
*/ */
Trigger.prototype.DoAfterDelay = function(time, action, data) Trigger.prototype.DoAfterDelay = function(time, action, eventData)
{ {
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
return cmpTimer.SetTimeout(SYSTEM_ENTITY, IID_Trigger, "DoAction", time, { return cmpTimer.SetTimeout(SYSTEM_ENTITY, IID_Trigger, "DoAction", time, {
"action": action, "action": action,
"data": data "eventData": eventData
}); });
}; };
@ -315,27 +296,78 @@ Trigger.prototype.DoAfterDelay = function(time, action, data)
* *
* @param {number} interval - Interval in milleseconds between consecutive calls. * @param {number} interval - Interval in milleseconds between consecutive calls.
* @param {string} action - Name of the action function. * @param {string} action - Name of the action function.
* @param {Object} data - Arbitrary object that will be passed to the action function. * @param {Object} eventData - Arbitrary object that will be passed to the action function.
* @param {number} [start] - Optional initial delay in milleseconds before starting the calls. * @param {number} [start] - Optional initial delay in milleseconds before starting the calls.
* If not given, interval will be used. * If not given, interval will be used.
* @return {number} the ID of the timer, so it can be stopped later. * @return {number} the ID of the timer, so it can be stopped later.
*/ */
Trigger.prototype.DoRepeatedly = function(time, action, data, start) Trigger.prototype.DoRepeatedly = function(time, action, eventData, start)
{ {
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
return cmpTimer.SetInterval(SYSTEM_ENTITY, IID_Trigger, "DoAction", start !== undefined ? start : time, time, { return cmpTimer.SetInterval(SYSTEM_ENTITY, IID_Trigger, "DoAction", start !== undefined ? start : time, time, {
"action": action, "action": action,
"data": data "eventData": eventData
}); });
}; };
/** /**
* Called by the trigger listeners to exucute the actual action. Including sanity checks. * This function executes the actions bound to the events.
* It's either called directlty from other simulation scripts,
* or from message listeners in this file
*
* @param {string} event - One of eventNames
* @param {Object} data - will be passed to the actions
*/
Trigger.prototype.CallEvent = function(event, eventData)
{
if (!this[event])
{
warn("Trigger.js: Unknown trigger event called:\"" + event + "\".");
return;
}
for (let name in this[event])
if (this[event][name].triggerData.enabled)
this.DoAction({
"action": this[event][name].triggerData.action,
"eventData": eventData,
"customData": this[event][name].customData,
"triggerData": this[event][name].triggerData
});
};
/**
* Call the action method of a trigger with the given event Data.
* By default, call the trigger even if it is currently disabled.
*/
Trigger.prototype.CallTrigger = function(event, name, eventData, evenIfDisabled = true)
{
if (!this?.[event]?.[name])
{
warn(`Trigger.js: called a trigger '${name}' for event '${event}' that wasn't found`);
return;
}
if (!evenIfDisabled && !this[event][name].triggerData.enabled)
return;
this.DoAction({
"action": this[event][name].triggerData.action,
"eventData": eventData,
"customData": this[event][name].customData,
"triggerData": this[event][name].triggerData
});
};
/**
* Called by the trigger listeners to execute the actual action. Including sanity checks.
* Intended for internal use, prefer CallEvent or CallTrigger.
*/ */
Trigger.prototype.DoAction = function(msg) Trigger.prototype.DoAction = function(msg)
{ {
if (this[msg.action]) if (this[msg.action])
this[msg.action](msg.data || null); this[msg.action](msg?.eventData, msg?.customData, msg?.triggerData);
else else
warn("Trigger.js: called a trigger action '" + msg.action + "' that wasn't found"); warn("Trigger.js: called a trigger action '" + msg.action + "' that wasn't found");
}; };

View File

@ -15,7 +15,7 @@ TriggerPoint.prototype.Init = function()
cmpTrigger.RegisterTriggerPoint(this.template.Reference, this.entity); cmpTrigger.RegisterTriggerPoint(this.template.Reference, this.entity);
} }
this.currentCollections = {}; this.currentCollections = {};
this.actions = {}; this.triggers = {};
}; };
TriggerPoint.prototype.OnDestroy = function() TriggerPoint.prototype.OnDestroy = function()
@ -28,7 +28,7 @@ TriggerPoint.prototype.OnDestroy = function()
}; };
/** /**
* @param action Name of the action function defined under Trigger * @param name Name of the trigger.
* @param data The data is an object containing information for the range query * @param data The data is an object containing information for the range query
* Some of the data has sendible defaults (mentionned next to the object) * Some of the data has sendible defaults (mentionned next to the object)
* data.players = [1,2,3,...] * list of player ids * data.players = [1,2,3,...] * list of player ids
@ -37,7 +37,7 @@ TriggerPoint.prototype.OnDestroy = function()
* data.requiredComponent = 0 * Required component id the entities will have * data.requiredComponent = 0 * Required component id the entities will have
* data.enabled = false * If the query is enabled by default * data.enabled = false * If the query is enabled by default
*/ */
TriggerPoint.prototype.RegisterRangeTrigger = function(action, data) TriggerPoint.prototype.RegisterRangeTrigger = function(name, data)
{ {
var players = data.players || Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetAllPlayers(); var players = data.players || Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetAllPlayers();
var minRange = data.minRange || 0; var minRange = data.minRange || 0;
@ -48,7 +48,7 @@ TriggerPoint.prototype.RegisterRangeTrigger = function(action, data)
var tag = cmpRangeManager.CreateActiveQuery(this.entity, minRange, maxRange, players, cid, cmpRangeManager.GetEntityFlagMask("normal"), true); var tag = cmpRangeManager.CreateActiveQuery(this.entity, minRange, maxRange, players, cid, cmpRangeManager.GetEntityFlagMask("normal"), true);
this.currentCollections[tag] = []; this.currentCollections[tag] = [];
this.actions[tag] = action; this.triggers[tag] = name;
return tag; return tag;
}; };
@ -72,7 +72,7 @@ TriggerPoint.prototype.OnRangeUpdate = function(msg)
r.added = msg.added; r.added = msg.added;
r.removed = msg.removed; r.removed = msg.removed;
var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
cmpTrigger.DoAction({ "action": this.actions[msg.tag], "data": r }); cmpTrigger.CallTrigger("OnRange", this.triggers[msg.tag], r);
}; };