Quote:
Seeing that MC starts a new perl interpreter thread for each plugin script, I assume it will be the same for all other languages, with the only probable exception being LUA (not sure how exactly LUA scripts are parsed). This allows a bit of 'multitasking' or 'parallel processing', if you get the idea. This much said, here are my questions..
All plugins have their own script state, including if you use Lua. This is in addition to the script state for the "main" world.
They are not threads. It is simply co-operative multi-tasking, if you like. At any particular moment only one will be active. If one choses to "hog" the machine (eg. by sleeping) then they all wait for it to finish.
Quote:
I've noticed that BroadcastPlugin() triggers the according function in all Plugins "simultaneously". This was confirmed by running 2 plugins and letting one of them sleep for 2 and the other for 3 seconds.
It sends the message to each plugin in sequence. As the source is publicly available you can look at it and see for yourself.
// tell a plugin the message
for (POSITION pluginpos = m_PluginList.GetHeadPosition(); pluginpos; )
{
CPlugin * pPlugin = m_PluginList.GetNext (pluginpos);
if (!(pPlugin->m_bEnabled)) // ignore disabled plugins
continue;
// see what the plugin makes of this,
pPlugin->ExecutePluginScript (ON_PLUGIN_BROADCAST,
pPlugin->m_dispid_plugin_broadcast,
Message,
(LPCTSTR) strCurrentID,
(LPCTSTR) strCurrentName,
Text);
if (pPlugin->m_dispid_plugin_broadcast != DISPID_UNKNOWN)
iCount++;
} // end of doing each plugin
It calls the "OnPluginBroadcast" function (if it exists) in each plugin, in the order they are in the plugin list (the load order), ignoring disabled plugins. As they are not separate threads it must necessarily wait for each one to finish before moving on.
Quote:
But there is an interesting issue: MC seems to wait until all plugins return from the function (I see the reason for that), but if you let both send something to the output (with Note() for example), you will see that something arrives, but not what. The previous lines get "duplicated", and the output is redrawn
If a plugin draws to the screen (or if anything does for that matter), then it does what most Windows programs do - scrolls the output buffer the appropriate number of lines, and then "invalidates" (marks for a redraw) the parts that are new - that is, that need refreshing. This is an efficiency issue. The invalidation causes Windows to raise a "draw" event which is serviced next time through the main event loop. If every line was individually redrawn at the moment the "writing" was done, there would be much more noticeable flicker, and it would be slower. As part of the scrolling the original line is left behind, and thus you (usually for a very brief period) see a duplication.
You virtually never notice this "duplicated line" effect, it all happens so fast that the new text is drawn almost instantly. However if you do something that takes a long time, and thus delay the processing of the draw event, you can see it. For example, a long script:
for i = 1, 1000 do print ("hello") end
This will temporarily duplicate the last line on the screen, as it is scrolled up 1000 times, and then after a moment, everything is redrawn.
The design of MUSHclient (including this aspect) is what has made it consistently come out first in MUD client speed benchmarks - for drawing incoming text.
Usually with MUD text, incoming text (from the MUD) is itself a Windows event, and thus you will get something like this:
- Text arrives and is processed (first event)
- Line is drawn on screen
- Screen scrolls up a line
- Bottom line is invalidated
- Main loop is re-entered
- Draw event is processed (second event)
- Line is drawn
- Go back to point 1
Thus for normal MUD text, things are drawn "properly".
Quote:
... if you take those two plugins that sleep on BroadcastPlugin() ...
I wouldn't sleep in plugins. As I said before, that effectively hangs the client. You can make plugins effectively sleep by using Lua and making a Lua co-routine. See this thread:
http://www.gammon.com.au/forum/?id=4956
Quote:
When playing with OnPluginPacketReceived(), I kind of expected all plugins to get the original packet. But instead, MC seems to 'walk' through all plugins in the order they were loaded, passing the return of the previous to the next one.
As the documentation for OnPluginPacketReceived says:
You can return data from this function (in version 3.59 onwards). If you do, then the returned data will replace the incoming data. In other words, you can change words, omit lines, add new lines, and MUSHclient will proceed as if the altered line had arrived from the MUD.
I don't see how it could do it differently. Each plugin, since it can modify the incoming text, effectively has to change what MUSHclient considers the packet. If you happen to call OnPluginPacketReceived in multiple plugins, they each have to get the (now) modified packet.
Quote:
This is kind of 'unreliable', because while the plugins seem to be always loaded in the order you installed them, you can mess it up by reloading a plugin (this pushes it to the end of the list).
Personally I wouldn't use multiple plugins, that modify incoming packets, in a way that clashes with each other.
It would be OK if one did a "add newline to prompt", and another replaced "color" with "colour" (for example). But to make two plugins that both fiddle with incoming packets is asking for trouble IMHO.
Sure you might make a definable load order, but what do you do if two plugins both want to be first on the list?
Quote:
If I let both plugins report back the time when they received the packet and the time when they were done with it and were about to return it, sometimes the second plugin reports a 'received' time that is -before- the 'returned' time of the first plugin ...
How are you measuring the time? The loop for doing OnPluginPacketReceived is very similar to the one for OnPluginBroadcast. They each are handled in sequence. And no, Notes are not done in a separate thread. |