I am using World.DoAfter to send lines of text to the mud (so as not to spam it, sort of like "Paste to world") in my script, but the lines sometimes do not arrive in the order I sent them from my script. This could probably be fixed if I made the time a decimal and increased the resolution, but that would take up many resources (it's an old PC) and I think this is a bug that should be fixed.
World.DoAfter bug
Posted by Poromenos on Sun 16 Oct 2005 04:10 PM — 4 posts, 18,363 views.
It's not a bug. Nowhere in the documentation does MUSHclient claim to execute timed events, in the order in which they are submitted, limited to the timer resolution.
In other words, if you do this:
MUSHclient does not claim they will be executed in that order. The examples given in various places of doing timed events in sequence usually (always?) give different time intervals, like this:
As an analogy, imagine you invite 5 friends around to eat dinner with you "at 6 o'clock - give or take a minute". Assuming your friends aren't late, you have no expectation that they will arrive in the order you asked them, they will simply arrive at the time given, within the resolution you specify, in this case within 1 minute of 6 o'clock.
MUSHclient works the same way.
To solve your problem, where you want the commands to be executed in sequence, I suggest that you use the queued system using Lua coroutines, that has been discussed a fair bit recently.
One approach would be to make a small plugin, that queues up commands to be sent, using that idea, pulling them out of the queue every second, and keeping them in order.
To save you a bit of effort, I have made a plugin to do just that. It will queue up commands and send them to the MUD every second. Since they are queued (in an internal Lua table) they will always be sent in the order they are queued, regardless of how quickly you queue them.
An example of calling it is below:
We are using CallPlugin to communicate with the plugin, however if an alias was required you could add it to the plugin easily enough.
If you execute this test code a couple of times it will slowly count to 10, without getting out of sequence.
In other words, if you do this:
DoAfter 1, "test A"
DoAfter 1, "test B"
DoAfter 1, "test C"
MUSHclient does not claim they will be executed in that order. The examples given in various places of doing timed events in sequence usually (always?) give different time intervals, like this:
DoAfter 1, "test A"
DoAfter 2, "test B"
DoAfter 3, "test C"
As an analogy, imagine you invite 5 friends around to eat dinner with you "at 6 o'clock - give or take a minute". Assuming your friends aren't late, you have no expectation that they will arrive in the order you asked them, they will simply arrive at the time given, within the resolution you specify, in this case within 1 minute of 6 o'clock.
MUSHclient works the same way.
To solve your problem, where you want the commands to be executed in sequence, I suggest that you use the queued system using Lua coroutines, that has been discussed a fair bit recently.
One approach would be to make a small plugin, that queues up commands to be sent, using that idea, pulling them out of the queue every second, and keeping them in order.
To save you a bit of effort, I have made a plugin to do just that. It will queue up commands and send them to the MUD every second. Since they are queued (in an internal Lua table) they will always be sent in the order they are queued, regardless of how quickly you queue them.
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>
<!-- Saved on Monday, October 17, 2005, 7:02 AM -->
<!-- MuClient version 3.67 -->
<!-- Plugin "Command_Queue" generated by Plugin Wizard -->
<muclient>
<plugin
name="Command_Queue"
author="Nick Gammon"
id="685b994664e3afced386d332"
language="Lua"
purpose="Queues up commands and sends one every second"
date_written="2005-10-17 06:47:09"
requires="3.61"
version="1.0"
>
</plugin>
<!-- Script -->
<script>
<![CDATA[
-- queue of things to send
queue = {}
-- called by a timer to resume a thread
function wait_timer_resume (name)
assert (coroutine.resume (thread))
end -- function wait_timer_resume
function worker_thread (thread)
while true do
coroutine.yield () -- wait a second
if table.getn (queue) > 0 then
Send (table.remove (queue, 1))
end -- of having an entry in the table
end -- of infinite while loop
end -- function worker_thread
function OnPluginInstall ()
-- timer will be called every second to kick things along
status = AddTimer ("wait_timer", 0, 0, 1, "",
timer_flag.Enabled +
timer_flag.Temporary + timer_flag.Replace,
"wait_timer_resume")
assert (status == error_code.eOK, error_desc [status])
-- start up worker thread
thread = coroutine.create (worker_thread)
assert (coroutine.resume (thread, thread))
end -- function OnPluginInstall
function OnPluginConnect ()
queue = {} -- start afresh when connecting
end -- function OnPluginConnect
function QueueIt (what)
table.insert (queue, what) -- insert into our queue
end -- function QueueIt
]]>
</script>
</muclient>
An example of calling it is below:
for i = 1, 10 do
CallPlugin ("685b994664e3afced386d332", "QueueIt", "think test " .. i)
end
We are using CallPlugin to communicate with the plugin, however if an alias was required you could add it to the plugin easily enough.
If you execute this test code a couple of times it will slowly count to 10, without getting out of sequence.
Hmm... Wouldn't it be simpler for MC to add/evaluate the timers in order? Or doesn't it work that way?
Well, timer events are not placed in a queue, because by their nature they have to be executed when the time expires, which is not necessarily related to the order in which you create timers.
A simple solution to your problem is to simply do something like this:
That way, when the timer fires, the things you want it to do are done in order. If the script gradually builds up the string, then it could simply concatenate a string, and then at the end do the DoAfter.
A simple solution to your problem is to simply do something like this:
DoAfter 1, "think this" & vbCrLf & "think that"
That way, when the timer fires, the things you want it to do are done in order. If the script gradually builds up the string, then it could simply concatenate a string, and then at the end do the DoAfter.