Page MenuHomeWildfire Games
Paste P190

EngineProxy
ActivePublic

Authored by Stan on Dec 29 2019, 12:03 AM.
class EngineProxy
{
constructor()
{
this.componentCache = new Map();
this.timeout = 1000;
}
/**
* Returns the requested component for the entity.
* @param {number} ent
* @param {number} iid
*/
QueryInterface(ent, iid)
{
// warn(Engine.QueryInterface(ent, iid).constructor.name);
let entComponentCache = this.componentCache.get(ent);
// Entity is not cached yet.
if (!entComponentCache)
{
let cmp = Engine.QueryInterface(ent, iid);
if (!cmp)
return undefined;
this.componentCache.set(ent, {
[iid]:{
"timeStamp": Date.now(),
"component": cmp
}
})
return cmp;
}
// Component is not cached yet or cache is stale.
else if(entComponentCache && !entComponentCache[iid] || entComponentCache[iid] && Date.now() > entComponentCache[iid].timeStamp + this.timeout)
{
let cmp = Engine.QueryInterface(ent, iid);
if (!cmp)
return undefined;
entComponentCache[iid] = {
"timeStamp": Date.now(),
"component": cmp
}
this.componentCache.set(ent, entComponentCache);
return cmp;
}
return entComponentCache[iid].component;
}
}
global["Engine2"] = new EngineProxy();

Event Timeline

Stan created this paste.Dec 29 2019, 12:03 AM
Stan updated the paste's language from autodetect to js.
elexis added a subscriber: elexis.Dec 29 2019, 1:47 PM

QueryInterface(ent, iid)

let entComponentCache = this.componentCache.get(ent);

This saves a function call at the cost of adding a function call?

elexis changed the visibility from "All Users" to "Public (No Login Required)".Dec 29 2019, 1:47 PM
Stan added a comment.Dec 29 2019, 1:48 PM

This is bad code anyway ^^

Stan added a comment.Dec 29 2019, 2:37 PM

But a js function call should be cheaper than a C++ function call in theory, right?

This is bad code anyway ^^

The cleaning of the cache every 1000ms is bad.
If it is necessary to clean the cache upon some conditions, then the condition is certainly different from every 1000ms.
If there is no such condition (which I presume to be the case), then cleaning the cache is needless and defeating the purpose of the patch.

But a js function call should be cheaper than a C++ function call in theory, right?

Wouldn't take that for granted, you should measure it before making that statement.

For the case where an entity component requests another entity component of the same entityID (for instance UnitAI of entity 1234 requesting Healer, ResourcerGatherer or Builder of entity 1234) it can cache that within that entiy component directly, since the component will never change after init (maybe deserialization, didn't check).

If the cost for a function call is the same, then the patch would be making it slower, because you also have the cost of member look up (foo.bar) and the condition evaluation if (!entComponentCache) and else if(entComponentCache && !entComponentCache[iid] || entComponentCache[iid] && Date.now() > entComponentCache[iid].timeStamp + this.timeout) every call that is not done currently.

I suppose there is potential in caching the query results, since I expect there to be many thousands if not hundreds of thousands of these calls in a populated match and at least for the part where an entity component looks up another entity component of the same entity the function calls could be avoided. Needs a lot of code changes and measurement though. That effort might be put into optimizing the strongest bottlenecks prior perhaps (I guess effort is subjective and depending on previous knowledge.)

Stan added a subscriber: wraitii.Dec 29 2019, 3:13 PM

Sure. Anyway it shouldn't segfault. @wraitii told me the reason it segfaults it that it tries to access unvalidated pointers.