PDA

View Full Version : Event Binding (Catching)


Inverness
12-29-2007, 01:48 PM
After lamenting over the fact that catchevent() did not function beyond GuiControls, I decided to throw together this class to replicate the functionality of catchevent().

This class when joined to an object will allow other objects to bind events so that when triggerboundevent() is called in the class object it is triggered on the objects bound to it; using the same event name or a different one.

The object you join the class to needs to have an object name or the variable this.bindname set so it can properly track the objects that have bound its event. This is also using a gloval variable 'static' which is a TStaticVar. I created this TStaticVar to organize 'global' variables that would be corrupting by being viewed in client flags or server flags (object refs and huge arrays).


public function bind(eventname, object, newname) {
if (this.name == null && this.bindname == null)
return;
if (object.type() != 2)
return;
temp.bn = (this.bindname == null? this.name: this.bindname);
this.bind2(temp.bn, eventname, object, newname);
}
public function bind2(bn, eventname, object, newname) {
if (static.(@ "binds_" @ bn @ "_" @ eventname).index(object) < 0) {
static.(@ "binds_" @ bn @ "_" @ eventname).add(object);
if (newname == null)
newname = eventname;
static.(@ "binds2_" @ bn @ "_" @ eventname).add(newname);
}
}
public function unbind(eventname, object) {
if (this.name == null && this.bindname == null)
return;
if (object.type() != 2)
return;
temp.bn = (this.bindname == null? this.name: this.bindname);
this.unbind2(temp.bn, eventname, object);
}
public function unbind2(bn, eventname, object) {
temp.ix = static.(@ "binds_" @ bn @ "_" @ eventname).index(object);
if (temp.ix > -1) {
static.(@ "binds_" @ bn @ "_" @ eventname).delete(temp.ix);
static.(@ "binds2_" @ bn @ "_" @ eventname).delete(temp.ix);
}
}
public function bindgc() {
if (this.name == null && this.bindname == null)
return;
temp.bn = (this.bindname == null? this.name: this.bindname);
this.bindgc2(temp.bn);
}
public function bindgc2(bn) {
temp.keys = 0;
with (static) {
temp.keys = getstringkeys("this.binds_" @ bn @ "_");
}
for (temp.eventname: temp.keys) {
for (temp.i = static.(@ "binds_" @ bn @ "_" @ eventname).size() - 1; i > -1; i --) {
if (static.(@ "binds_" @ bn @ "_" @ eventname)[i].type() != 2) {
static.(@ "binds_" @ bn @ "_" @ eventname).delete(i);
static.(@ "binds2_" @ bn @ "_" @ eventname).delete(i);
}
}
}
}
function onBindGarbageCollect() {
this.bindgc();
}
function triggerboundevent(eventname, p0, p1, p2, p3, p4, p5) {
if (this.name == null && this.bindname == null)
return;
temp.bn = (this.bindname == null? this.name: this.bindname);
this.triggerboundevent2(temp.bn, eventname, p0, p1, p2, p3, p4, p5);
}
function triggerboundevent2(bn, eventname, p0, p1, p2, p3, p4, p5) {
for (temp.i = 0; i < static.(@ "binds_" @ bn @ "_" @ eventname).size(); i ++) {
if (static.(@ "binds_" @ bn @ "_" @ eventname)[i].type() == 2) {
static.(@ "binds_" @ bn @ "_" @ eventname)[i].trigger(static.(@ "binds2_" @ temp.bn @ "_" @ eventname)[i], p0, p1, p2, p3, p4, p5);
}
}
}

I had split each function into two parts in the case that the object you want to call bind on isn't existing yet.
Here are two examples of how I use it (with most of script cut out):

// WEAPON: System
//#CLIENTSIDE
function onPlayerEnters() {
// Stuff
worldCheck();
}
function onWorldCheck() {
// Check to see if you're in a different world
triggerboundevent("WorldCheck");
if (yourindifferentworld) {
// World Change Functions
triggerboundevent("WorldChange");
}
}

// WEAPON: SysTime
//#CLIENTSIDE
function onCreated() {
// stuff
System.bind("WorldCheck", this);
System.bind("WorldChange", this);
setTimer(0.05);
}
function onWorldCheck() onTimeout();
function onWorldChange() addmsg(5, "You are now in " @ client.world);
function onTimeout() {
// Apply Day/Night effect depending on world
// If the world does not have day/night enabled, apply the seteffect()
setTimer(5);
}

// WEAPON: GuiInventory
//#CLIENTSIDE
function onCreated() {
// Stuff
System.bind2("MudObject_player_" @ player.account, "ReflectedObject", this);
}
function onReflectedObject() {
// New mud data from server, update the inventory view.
}

// OBJECT: MudObject_player_YourAccount
//#CLIENTSIDE
function onReflect(variables) {
// Set the variables
triggerboundevent("ReflectedObject");
}

You'll also notice that the class defines an event onBindGarbageCollect(), this is because every 60 seconds in the System weapon bindgc() is triggered to clear any objects that might have been destroyed from the bind array, after that is has triggerboundevent("BindGarbageCollect").

This is so any objects that are using the eventbind class besides System can bind that event so bindgc() is run for them automatically:

//#CLIENTSIDE
function onCreated() {
join("util_eventbind"); // The class
System.bind("BindGarbageCollect", this); // No need for separate scheduling.
}

Obviously, one has to make adjustments so it will fit on their server.

cbk1994
12-29-2007, 03:35 PM
So this replicates catchevent? Nice work, but seems like overkill. I thought you could use catchevent with other things, such as requesturl.

Inverness
12-30-2007, 01:51 AM
This replicates the functionality with stuff you script yourself, not just built-in Graal stuff.

cbk1994
12-30-2007, 02:05 AM
Works for me. Good job.

Kyranki
12-31-2007, 06:36 AM
EDIT:

Nevermind, understand it completely took a bit of slow reading is all. Nice work Inver, ++ rep for you.