My preferred method is different to the one explained in the blog post.
On state_entry, the rezzee sets up a listen for everything, in a preset channel. The object is taken to inventory with this listener active. The on_rez event does NOT reset the script (or there's no on_rez event whatsoever).
In the object_rez event, the rezzer sends the data to the rezzee via the same preset channel that the rezzee is listening on.
For security, the rezzee's listen event filters out the messages that don't come from the rezzer, by comparing (string)llGetObjectDetails(llGetKey(), (list)OBJECT_REZZER_KEY) with the id in the listener and returning if they don't match.
If no more messages are expected, when the message is successfully received the rezzee can now remove the listener. If more messages are expected, the rezzee can optionally set up a new listen with a filter for the key of the rezzer, and then shut down the old listener. The latter step is unnecessary, though: it would merely prevent script execution for messages that don't come from the rezzer.
This method is faster and uses less memory because there is less back-and-forth communication, which is why I prefer it. In particular, it removes the need for a listener in the rezzer in the frequent case of rezzer-to-rezzee communication only. It relies on the fact that the listen queue of the rezzee exists when the rezzer receives the object_rez event, regardless of whether the rezzee has already started executing or not. It works because while the rezzee is waiting for a chance to execute, the communication event is waiting in the queue, so it will eventually be received.
Rezzee:
integer ListenHandle;
default
{
state_entry()
{
ListenHandle = llListen(1234, "", "", "");
}
listen(integer chan, string name, key id, string msg)
{
if (id != (string)llGetObjectDetails(llGetKey(), (list)OBJECT_REZZER_KEY))
return;
llOwnerSay(msg); // or some other message processing here
llListenRemove(ListenHandle);
}
}
Rezzer:
default
{
touch_start(integer n)
{
llRezAtRoot(llGetInventoryName(INVENTORY_OBJECT, 0),
llGetPos()+<0,0,1>, <0,0,0>, <0,0,0,1>, 1);
}
object_rez(key id)
{
llRegionSayTo(id, 1234, "message");
}
}
But given that the official method endorsed by LL is different and more complex, I'd like to know if this simplified method is guaranteed to work in future.