I'm currently using Svof as my main system, with some of my own bits and pieces added on. I have a pretty effective, if a little stupid, dor routine which is faster than that in Svof, but Svof's queue management is far superior.
I looked into how WSys queue management works, but couldn't get it to translate out effectively.
Does anyone have a standalone queue management system they use for Mudlet which makes use of serverside queueing, so multiple items can be added to the queue, taken out of the queue, etc?
I'm not expecting anyone to just hand it over on a plate, happy to do some of the work myself. but reaching out in hope of some guidance.
Tharos, the Announcer of Delos shouts, "It's near the end of the egghunt and I still haven't figured out how to pronounce Clean-dat-hoo."
1
Comments
Here's a quick(ish) rundown on some of the things my queueing system does:
Limits the number of queued commands to the appropriate size for the specified queue (one for the CLASS queue, six for the others).
I consider a command queued as soon as the function runs, and only use the trigger to verify that it has been queued, with a 1 second timer to cancel any commands that haven't actually been queued (due to lag, svof denying the command, amnesia, etc.), so even if I spam on my end I'm not spamming the game with unnecessary queue commands. Will also pick up actions from the QUEUE messages if it doesn't know about trying to queue them (but everything I have that uses queueing uses the script).
The queue function (used for actually queueing stuff) has six parameters, off the top of my head:
queue ("eq", "balance", "eqbal" or "class" plus some shorthands/alternatives that are hard-coded, like "voice" mapping to "class")
position (add or prepend)
command (string or table [will concatenate into a string using a command separator])
usesbal (boolean)
canprepend (boolean, I've never actually used this but coded it in just in case)
repeatable (default is false if you just don't pass a value, and for most commands you don't want to repeat them, but some - like movement or getting items - you will)
Can only have one balance using command queued at any one time in that queue, since there's no point trying to do more than one since the subsequent ones will fail. If you prepend, and it uses balance, it will by default refuse to do it (there's no point prepending a balance using command that will then stop everything else from happening); that's why the fifth parameter exists so you can in theory override this (but I don't know why you'd want to). If you add, and it uses balance, it will add it to the end of the queue OR replace the existing balance using command (which is always at the end of the queue).
If you prepend a non-balance using command, it will just prepend it. If you add a non-balance using command, it will insert it before the queued balance using command (if there is one, otherwise it just goes on the end). So if I already have my attack alias queued (which uses balance), and my opponent leaves, I can queue up directions to move, and it will be inserted before my attack, so I'll move/attack, rather than trying to attack/move.
Most commands aren't repeatable (there's no point in queueing up your attack alias six times, for example). However, the sixth parameter will allow you to say that it IS repeatable, so it will queue more than one of the same thing (I currently only use this for movement commands and GET/DROP/PUT).
Cuts down on spam and commands sent to the game. Rather than mashing an alias that constantly clears/queues a command, it will instead constantly run the function that will decide if it needs to do anything at all.
Results of disembowel testing | Knight limb counter | GMCP AB files
Code:
antonius.queueing = antonius.queueing or {} -- indexed tables (ordered arrays) containing the currently queued commands antonius.queueing.queues = antonius.queueing.queues or { balance = {}, equilibrium = {}, eqbal = {}, class = {} } antonius.queueing.timers = antonius.queueing.timers or { balance = nil, equilibrium = nil, eqbal = nil, class = nil } -- check if a given command is queued in the current queue antonius.queueing.isqueued = function(queue, command) local command = command:upper() for _, c in ipairs(antonius.queueing.queues[queue]) do if c.command == command then return true end end return false end antonius.queueing.getbalanceposition = function(queue) for i, c in pairs(antonius.queueing.queues[queue]) do if c.usesbal then return i end end return -1 end antonius.queueing.getcommand = function(queue, position) return antonius.queueing.queues[queue][position] end antonius.queueing.anyqueued = function(queue) return #antonius.queueing.queues[queue] > 0 end antonius.queueing.balancequeued = function(queue) return antonius.queueing.getbalanceposition(queue) ~= -1 end antonius.queueing.queuemap = { bal = "balance", eq = "equilibrium", voice = "class" } --[[ queue: balance, equilibrium, eqbal or class position: add or prepend --]] antonius.queueing.queue = function(queue, position, command, useseqbal, replaceeqbal, repeatable) local queue = antonius.queueing.queuemap[queue] or queue if not(queue == "balance" or queue == "equilibrium" or queue == "eqbal" or queue == "class") then antonius.echo("Invalid queue " .. queue .. ".") return elseif #antonius.queueing.queues[queue] == 6 then antonius.echo("Queue full: " .. queue .. ".") return end if type(command) == "table" then command = table.concat(command, "||") end --if ssc.inslowcuringmode() then send(command) return end if not repeatable and antonius.queueing.isqueued(queue, command) then return end if queue == "class" then antonius.queueing.queues.class = {command} send("queue add class " .. command, false) return end local commobj = { command = command:upper(), usesbal = useseqbal, confirmed = false } if position == "prepend" then -- don't want to prepend actions that use eq and/or balance if useseqbal then return end table.insert(antonius.queueing.queues[queue], 1, commobj) send("queue " .. position .. " " .. queue .. " " .. command, false) else local balpos = antonius.queueing.getbalanceposition(queue) local balcommand = antonius.queueing.getcommand(queue, balpos) if useseqbal or replaceeqbal then -- if we have one already queued, replace it if balpos ~= -1 then antonius.queueing.queues[queue][balpos] = commobj send("queue replace " .. queue .. " " .. balpos .. " " .. command, false) else -- otherwise, just insert at the end table.insert(antonius.queueing.queues[queue], commobj) send("queue " .. position .. " " .. queue .. " " .. command, false) end else -- if we don't have a balance using command queued, just add this to the end if balpos == -1 then table.insert(antonius.queueing.queues[queue], commobj) send("queue " .. position .. " " .. queue .. " " .. command, false) else -- otherwise, we want to shift the balance using command up one table.insert(antonius.queueing.queues[queue], balpos, commobj) send("queue insert " .. queue .. " " .. balpos .. " " .. command, false) end end end if antonius.queueing.timers[queue] then killTimer(antonius.queueing.timers[queue]) end antonius.queueing.timers[queue] = tempTimer(0.5, [[antonius.queueing.checkconfirm("]] .. queue .. [[")]]) end antonius.queueing.unqueue = function(queue) antonius.queueing.queues[queue] = {} end antonius.queueing.confirm = function(queue, command, position, index) local command = command:upper() local commandpresent = false -- confirm the first instance of this command we find for i, c in ipairs(antonius.queueing.queues[queue]) do if c.command == command then commandpresent = true if not c.confirmed then c.confirmed = true break end end end -- if we found this command, confirmed or otherwise, we don't need to do anything else -- if it was already confirmed, suggests a replace/add to shift up a balance using command if commandpresent then return end -- if we didn't find any instance of the specified command, could be an ADD command from something other than the script local commobj = { command = command, usesbal = position ~= "prepend", -- if not prepending, we assume it uses balance because we don't actually know confirmed = true -- we can automatically confirm it because it's in reaction to game output } if position == "insert" then table.insert(antonius.queueing.queues[queue], index, commobj) elseif position == "replace" then antonius.queueing.queues[queue][index] = commobj elseif position == "prepend" then table.insert(antonius.queueing.queues[queue], 1, commobj) else table.insert(antonius.queueing.queues[queue], commobj) end end antonius.queueing.checkconfirm = function(queue) killTimer(antonius.queueing.timers[queue]) antonius.queueing.timers[queue] = nil local indexes = {} for i, c in ipairs(antonius.queueing.queues[queue]) do if not c.confirmed then table.insert(indexes, i) end end for _, index in ipairs(indexes) do table.remove(antonius.queueing.queues[queue], index) end endTriggers (line delta is 0 for all multiline triggers):
Name: Queued command ran Multiline: Yes Pattern: [System]: Running queued (begin of line) Pattern: ^\[System\]\: Running queued (\w+) command: (.+)$ (perl regex) Code: antonius.queueing.unqueue(multimatches[2][2]) Name: Added queued command Multiline: Yes Pattern: [System]: Added (begin of line) Pattern: ^\[System\]\: Added (.+) to your (\w+) queue\.$ (perl regex) Code: local queue = multimatches[2][3] local command = multimatches[2][2] antonius.queueing.confirm(queue, command, "add") Name: Prepended queued command Multiline: Yes Pattern: [System]: Prepended (begin of line) Pattern: ^\[System\]\: Prepended (.+) to your (\w+) queue\.$ (perl regex) Code: local queue = multimatches[2][3] local command = multimatches[2][2] antonius.queueing.confirm(queue, command, "prepend") Name: Replaced queued command Multiline: Yes Pattern: [System]: replaced command (begin of line) Pattern: ^\[System\]: replaced command #(\d+) in the (\w+) queue with (.+)\.$ (perl regex) Code: local queue = multimatches[2][3] local command = multimatches[2][4] antonius.queueing.confirm(queue, command, "replace", tonumber(multimatches[2][2])) Name: Inserted queued command Multiline: Yes Pattern: [System]: inserted (begin of line) Pattern: ^\[System\]: inserted(?:ed)? command #(\d+) in the (\w+) queue with (.+)\.$ (perl regex) Code: local queue = multimatches[2][3] local command = multimatches[2][4] antonius.queueing.confirm(queue, command, "insert", tonumber(multimatches[2][2])) Name: Cleared all queues Multiline: No Pattern: Your queues are already empty. (exact match) Pattern: Cleared your queues. (exact match) Code: antonius.queueing.queues = { balance = {}, equilibrium = {}, eqbal = {}, class = {} } Name: Cleared queue Multiline: No Pattern: ^Your (\w+) queue is already empty\.$ (perl regex) Pattern: ^\[System\]\: Queued (\w+) commands cleared\.$ (perl regex) Pattern: ^Your (\w+) queue is empty\.$ (perl regex) Code: antonius.queueing.queues[matches[2]] = {}Results of disembowel testing | Knight limb counter | GMCP AB files
Couple of additional notes:
If you just delete "antonius." from the entire thing, I think it should still work without any issues caused by that namespace not existing. The "||" will need to be changed to whatever your command separator happens to be. This line:
--if ssc.inslowcuringmode() then send(command) return end
is commented out because it calls a function from my own curing system, but the "ssc" part could easily be replaced with "svo" and then uncommenting the line would be fine.
Results of disembowel testing | Knight limb counter | GMCP AB files
To add to the queue, I simply do:
antonius.queueing.queue("eqbal","add","mountjump "..dir,true)How do I get rid of any existing eqbal using command and replace it with the mountjump?The code that handles that is this section of the queue function:
if useseqbal or replaceeqbal then -- if we have one already queued, replace it if balpos ~= -1 then antonius.queueing.queues[queue][balpos] = commobj send("queue replace " .. queue .. " " .. balpos .. " " .. command, false) else -- otherwise, just insert at the end table.insert(antonius.queueing.queues[queue], commobj) send("queue " .. position .. " " .. queue .. " " .. command, false) end elseSo if you did antonius.queueing.queue("eqbal", "add", "kick Antonius", true); and then called antonius.queueing.queue("eqbal", "add", "mountjump northeast", true); before the kick had happened (i.e. it was still queued), it would replace the "kick Antonius" command with the "mountjump northeast" command.
Results of disembowel testing | Knight limb counter | GMCP AB files
Next question, is it possible, with the script as it exists now, to add multiple entries which consume balance and it to work through them as balance is recovered?
Results of disembowel testing | Knight limb counter | GMCP AB files
<div>antonius.queueing.doadd = function(action, ppd) -- add balance consuming actions to pending queue local prio = ppd or #antonius.queueing.queues.pending+1 if not table.contains(antonius.queueing.queues.pending,action:upper()) then table.insert(antonius.queueing.queues.pending,prio,action:upper()) end end antonius.queueing.executePending = function() -- move actions from pending to main queue local canadd = true if #antonius.queueing.queues.pending == 0 then return false end for k, v in pairs(antonius.queueing.queues["eqbal"]) do if v.usesbal == true then canadd = false break end end print("Can add: "..string.format("%s", tostring(canadd))) --debug echo if canadd == true then --[[ antonius.queueing.queue("eqbal","add",antonius.queueing.queues.pending[1],true) --probably not the right command table.remove(antonius.queueing.queues.pending[1]) ]]-- end end<br></div>