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.
* 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} customData - User-defined data that will be forwarded to the action.
*
* @example
* 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)
* 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])
{
@ -110,7 +111,7 @@ Trigger.prototype.RegisterTrigger = function(event, name, triggerData)
if (!triggerData.action)
triggerData.action = name;
this[event][name] = triggerData;
this[event][name] = { "triggerData": triggerData, "customData": customData };
// setup range query
if (event == "OnRange")
@ -141,90 +142,70 @@ Trigger.prototype.DisableTrigger = function(event, name)
{
if (!this[event][name])
{
warn("Trigger.js: Disabling unknown trigger");
warn("Trigger.js: Disabling unknown trigger " + name);
return;
}
let data = this[event][name];
let triggerData = this[event][name].triggerData;
// special casing interval and range triggers for performance
if (event == "OnInterval")
{
if (!data.timer) // don't disable it a second time
if (!triggerData.timer) // don't disable it a second time
return;
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
cmpTimer.CancelTimer(data.timer);
data.timer = null;
cmpTimer.CancelTimer(triggerData.timer);
triggerData.timer = null;
}
else if (event == "OnRange")
{
if (!data.queries)
if (!triggerData.queries)
{
warn("Trigger.js: Range query wasn't set up before trying to disable it.");
return;
}
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
for (let query of data.queries)
for (let query of triggerData.queries)
cmpRangeManager.DisableActiveQuery(query);
}
data.enabled = false;
triggerData.enabled = false;
};
Trigger.prototype.EnableTrigger = function(event, name)
{
if (!this[event][name])
{
warn("Trigger.js: Enabling unknown trigger");
warn("Trigger.js: Enabling unknown trigger " + name);
return;
}
let data = this[event][name];
let triggerData = this[event][name].triggerData;
// special casing interval and range triggers for performance
if (event == "OnInterval")
{
if (data.timer) // don't enable it a second time
if (triggerData.timer) // don't enable it a second time
return;
if (!data.interval)
if (!triggerData.interval)
{
warn("Trigger.js: An interval trigger should have an intervel in its data");
return;
}
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
data.timer = cmpTimer.SetInterval(this.entity, IID_Trigger, "DoAction",
data.delay || 0, data.interval, { "name": name });
triggerData.timer = cmpTimer.SetInterval(this.entity, IID_Trigger, "DoAction",
triggerData.delay || 0, triggerData.interval, { "name": name });
}
else if (event == "OnRange")
{
if (!data.queries)
if (!triggerData.queries)
{
warn("Trigger.js: Range query wasn't set up before");
return;
}
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
for (let query of data.queries)
for (let query of triggerData.queries)
cmpRangeManager.EnableActiveQuery(query);
}
data.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 });
triggerData.enabled = true;
};
Trigger.prototype.OnGlobalInitGame = function(msg)
@ -298,15 +279,15 @@ Trigger.prototype.OnGlobalDiplomacyChanged = function(msg)
*
* @param {number} time - Delay in milliseconds.
* @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.
*/
Trigger.prototype.DoAfterDelay = function(time, action, data)
Trigger.prototype.DoAfterDelay = function(time, action, eventData)
{
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
return cmpTimer.SetTimeout(SYSTEM_ENTITY, IID_Trigger, "DoAction", time, {
"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 {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.
* If not given, interval will be used.
* @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);
return cmpTimer.SetInterval(SYSTEM_ENTITY, IID_Trigger, "DoAction", start !== undefined ? start : time, time, {
"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)
{
if (this[msg.action])
this[msg.action](msg.data || null);
this[msg.action](msg?.eventData, msg?.customData, msg?.triggerData);
else
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);
}
this.currentCollections = {};
this.actions = {};
this.triggers = {};
};
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
* Some of the data has sendible defaults (mentionned next to the object)
* 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.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 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);
this.currentCollections[tag] = [];
this.actions[tag] = action;
this.triggers[tag] = name;
return tag;
};
@ -72,7 +72,7 @@ TriggerPoint.prototype.OnRangeUpdate = function(msg)
r.added = msg.added;
r.removed = msg.removed;
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);
};