• You've discovered RedGuides, an EverQuest multi-boxing and scripting community 🧙‍♀️⚙️. We want you to play several EQ characters at once, come join us and say hello! 👋

  • A TLP without truebox has thawed (Very Vanilla ready)
    Frostreaver

Question - Lua spams (due to lag?)

Soandso2

Well-known member
Joined
Mar 13, 2023
RedCents
937¢
Alright, at the risk of being banned for spamming the forum with questions, I must ask why my Lua spams me.

I guess it doesnt really matter, really, but it annoys me. I think I know why this happens, but in case my theory is wrong, or I am implementing my code incorrectly, I am asking this here. Also, I have kind of been asking this question before, but as part of larger questions and it seems to go unnoticed.

By the way, I have had the same issue in macroscript before I started with Lua.
1) me is a shortened version of mq.TLO.Me (and similar with spell)
2) utils.haveBuff and utils.goodToGo are utility functions (the first simplifies checking if you have a buff or not, and the second one is borrowed from LeRogue)
Lua:
local function useClicky(clickyName)
    if findItem(clickyName).ID() > 0 and findItem(clickyName).TimerReady() == 0 then
        mq.cmdf('/useitem "%s"',clickyName)
        printf("[%s] \amClicky:: %s",os.date('%H:%M:%S'),clickyName)
        if findItem(clickyName).CastTime() > 0 then
            mq.delay(findItem(clickyName).CastTime() + 300)
        end
    else
        printf("[%s] \amClicky:: Could not use %s",os.date('%H:%M:%S'),clickyName)
    end
end

while true do
    if me.Combat() then
        if spell("Blessing of Unity").Stacks() and not utils.haveBuff("Blessing of Unity") and findItem("Miniature Horn of Unity").TimerReady() == 0 and me.Casting.ID() == nil and utils.goodToGo() then
            useClicky("Miniature Horn of Unity")
        end
    end
end

When the following runs in combat, why do I often see 2 or 3 messages (with the same timestamp) that the clicky was used?
Now, I wrote above that I had a theory myself and this is it. There is a lag between server-client or a delay between EverQuest and MacroQuest. When the command to use the item comes, it takes some time for the client to react and the script runs so fast that it manages to think "oh, lets do this because it seems to be a-ok". Is this assumption correct? I have even added a delay after the useitem command to counter this, but it does not help. Or is my code somehow broken? If so, how to remedy this?
 
Alright, at the risk of being banned for spamming the forum with questions, I must ask why my lua spams me.

I guess it doesnt really matter, really, but it annoys me. I think I know why this happens, but in case my theory is wrong, or I am implementing my code incorrectly, I am asking this here. Also, I have kind of been asking this question before, but as part of larger questions and it seems to go unnoticed.

By the way, I have had the same issue in macroscript before I started with Lua.
1) me is a shortened version of mq.TLO.Me (and similar with spell)
2) utils.haveBuff and utils.goodToGo are utility functions (the first simplifies if you have a buff or not, the second one is borrowed from LeRogue)
Lua:
local function useClicky(clickyName)
    if findItem(clickyName).ID() > 0 and findItem(clickyName).TimerReady() == 0 then
        mq.cmdf('/useitem "%s"',clickyName)
        printf("[%s] \amClicky:: %s",os.date('%H:%M:%S'),clickyName)
        if findItem(clickyName).CastTime() > 0 then
            mq.delay(findItem(clickyName).CastTime() + 300)
        end
    else
        printf("[%s] \amClicky:: Could not use %s",os.date('%H:%M:%S'),clickyName)
    end
end

while true do
    if me.Combat() then
        if spell("Blessing of Unity").Stacks() and not utils.haveBuff("Blessing of Unity") and findItem("Miniature Horn of Unity").TimerReady() == 0 and me.Casting.ID() == nil and utils.goodToGo() then
            useClicky("Miniature Horn of Unity")
        end
    end
end

When the following runs in combat, why do I often see 2 or 3 messages that the clicky was used? Now, this is where I have my idea. There is a lag between server-client or a delay between EverQuest and MacroQuest. When the command to use the item comes, it takes some time for the client to react and the script runs so fast that it manages to think "oh, lets do this because it seems to be a-ok". Is this assumption correct? Or is my code somehow broken? If so, how to remedy this?
many automations uses a timer that gets set when you do something like use an ability, cast a spell, or use an item. this timer is then used to delay before trying to do other things
 
many automations uses a timer that gets set when you do something like use an ability, cast a spell, or use an item. this timer is then used to delay before trying to do other things
Well, I have mq.delay(findItem(clickyName).CastTime() + 300) in the code. Is this wrong or simply not enough?
 
Well, I have mq.delay(findItem(clickyName).CastTime() + 300) in the code. Is this wrong or simply not enough?
well test it. sometimes even if i *know* something, I want to test it in cause what i "know" is incorrect.

Lua:
local function main()

    printf('before delay  : %s"', mq.gettime())
    mq.delay(300)
    printf('after 300 delay : %s', mq.gettime())
end
while true do
    main()
end

the mq.gettime() is in milliseconds

this is *very* spammy.

300 is going to be .3 seconds

but yes, you need to increase your delay a bit clickies can especially have a delay when you press to when they go to activate - which is annoying. some items you can actually even interrupt trying to cast another item while it is casting - something pretty unusual (but mq speed is pretty amazing)
 
you have a mainloop that goes 50000mph, you need to put a delay in the main loop, or a check for when to go casting, and me.combat is only checking if you have auto attack on or not.
 
well test it. sometimes even if i *know* something, I want to test it in cause what i "know" is incorrect.

Lua:
local function main()

    printf('before delay  : %s"', mq.gettime())
    mq.delay(300)
    printf('after 300 delay : %s', mq.gettime())
end
while true do
    main()
end

the mq.gettime() is in milliseconds

this is *very* spammy.

300 is going to be .3 seconds

but yes, you need to increase your delay a bit clickies can especially have a delay when you press to when they go to activate - which is annoying. some items you can actually even interrupt trying to cast another item while it is casting - something pretty unusual (but mq speed is pretty amazing)
Alright, I will increase the delay and see if that helps.
And then it seems that my assumption that there is (or at least can be) a delay between the macroquest command and when EQ understands that it was given a command to do something is right. Kinda feels good for a noob like me. ;)
 
Not familiar with Lua in general. But the difference between a delay and a timer is fairly significant.

You can delay for any amount of arbitrary time, the same as you can have a timer for an arbitrary amount of time.
But in your case it looks like you're going down the right track. Which is to wait until the item doesn't have a wait timer to cast it again, however you also need a way to wait after you've clicked the item for the item to recognized it's been clicked and the game to assign it a timer etc. Some items won't get the timer assigned until you're done casting.

consider making something like a "global I did something" timer and giving it a half second wait or similar. You'll want to play with the value until you find a sweet spot.
Then any time you cast a spell, use a clicky, etc you'd want to wait until the timer has been depleted before trying again regardless of any cast time, or clicky ready type situation.

Generally speaking it could look something like the following.

Code:
//Outside of main loop
Make a global timer and set the value to whatever the length of time you want to wait is.

//MainLoop
while (1) {
    If (!globalTimer) {
        if (allmycheckspass) {
            YourOwnUseItemFunction(ItemToUse);
        }
    }
}

YourOwnUseItemFunction(ItemToUse) {
    /useitem "ItemToUse"
    /setTimer to default value
}

That's obviously not real code. It's the concept of code. The idea being that you have a function that does the thing you want, like useitem, and by using the function it will both click the item and automatically set the timer in question so that when the main loop rolls around again it will see the timer has a value and wait. Once the wait has been completed it will then resume as normal. This will allow EQ to report that you've clicked the item, you're currently casting, and then eventually that the clicky does in fact have a timer you must wait for before you can use it again. You could then use the the same timer for many actions to be your "anti-spam". So you could useitem, or /cast #, or /alt act, etc. also, a delay in macros stops code from continuing to process because it's waiting for the delay prior to continuing. A timer will just give you a wait to skip chunks of code that are doing a specific action or a set of actions but still allow you to consider other things unrelated. Like say the item in question has a cast time and you're a healer, you could use the timer to prevent you from spam using the item, but also check to see if you need to duck off a currently being casted spell with a long wait time in order to cast a quick cast heal on a given player to prevent their death.
 
Well, added a much longer delay after the item spell had been cast but it still does not work. I see the clicky function execute and then a whole FOUR seconds later it tries to execute again on an item that has a half second cast time. Is that reasonable or normal?

I am not fully certain that I understand the difference between delay and timer here. As I understand things, after the command to click the item has been initiated, I wait for (castTime + 2000) which is no less than 2 full seconds for an instaclick item. (I removed line 5 and now always add a delay after a click) And still I get an attempt to click the item again. The spam is significantly decreased but how long delay could there be?
 
A delay is blocking. A timer is not. You fire off some ability and reset its timer and move on. You don't try to fire that ability again as long as that timer hasn't expired. So instead of delaying for some period, you just check whether that timer has expired and if not then move on to the next thing.

You have things like mq.gettime() and os.time() that give you current time in millisecond or seconds.
 
aquietone is correct.

a delay will wait at the line where the delay is placed until the time given to the delay has expired.
a timer is something you create, and then use to prevent some specific thing from happening. But the logic continues to process anything not blocked by the timer.

Without being familiar with the language it puts me at a disadvantage to provide an accurate example. While I understand how one could be implemented, I do not know the correct syntax to implement one so that you have a solid example from which to show the concept in action.

You could also go as far as making some assumptions. Such as instead of your function

Lua:
local function useClicky(clickyName)
    if findItem(clickyName).ID() > 0 and findItem(clickyName).TimerReady() == 0 then
        mq.cmdf('/useitem "%s"',clickyName)
        printf("[%s] \amClicky:: %s",os.date('%H:%M:%S'),clickyName)
        if findItem(clickyName).CastTime() > 0 then
            mq.delay(findItem(clickyName).CastTime() + 300)
        end
    else
        printf("[%s] \amClicky:: Could not use %s",os.date('%H:%M:%S'),clickyName)
    end
end

we do this
Lua:
local function useClicky(clickyName)
    if findItem(clickyName).ID() > 0 and findItem(clickyName).TimerReady() == 0 then
        mq.cmdf('/useitem "%s"',clickyName)
        printf("[%s] \amClicky:: %s",os.date('%H:%M:%S'),clickyName)
        mq.delay(findItem(clickyName).CastTime() + 300)
    else
        printf("[%s] \amClicky:: Could not use %s",os.date('%H:%M:%S'),clickyName)
    end
end
I've removed the additional check for findItem(clickyName).CastTime() > 0 as a requirement to implementing a delay. This likely would be a check to see if it's an instant cast, but due to how fast this processes code it'll flip around and hit the button a few times before it registers the TimerReady portion is no longer valid. So you WOULD want the 300 to be considered regardless. That means that there would be at least a 300ms wait after clicking it before clicking it again just using the delays even if the item is instant cast.
The delay may need to be adjusted to higher or lower to optimize the script for yourself and or others.

So while this doesn't incorporate a timer, it at least ensures there is a delay anytime you use a clicky which could alleviate some issues.
 
aquietone is correct.

a delay will wait at the line where the delay is placed until the time given to the delay has expired.
a timer is something you create, and then use to prevent some specific thing from happening. But the logic continues to process anything not blocked by the timer.

Without being familiar with the language it puts me at a disadvantage to provide an accurate example. While I understand how one could be implemented, I do not know the correct syntax to implement one so that you have a solid example from which to show the concept in action.

You could also go as far as making some assumptions. Such as instead of your function

Lua:
local function useClicky(clickyName)
    if findItem(clickyName).ID() > 0 and findItem(clickyName).TimerReady() == 0 then
        mq.cmdf('/useitem "%s"',clickyName)
        printf("[%s] \amClicky:: %s",os.date('%H:%M:%S'),clickyName)
        if findItem(clickyName).CastTime() > 0 then
            mq.delay(findItem(clickyName).CastTime() + 300)
        end
    else
        printf("[%s] \amClicky:: Could not use %s",os.date('%H:%M:%S'),clickyName)
    end
end

we do this
Lua:
local function useClicky(clickyName)
    if findItem(clickyName).ID() > 0 and findItem(clickyName).TimerReady() == 0 then
        mq.cmdf('/useitem "%s"',clickyName)
        printf("[%s] \amClicky:: %s",os.date('%H:%M:%S'),clickyName)
        mq.delay(findItem(clickyName).CastTime() + 300)
    else
        printf("[%s] \amClicky:: Could not use %s",os.date('%H:%M:%S'),clickyName)
    end
end
I've removed the additional check for findItem(clickyName).CastTime() > 0 as a requirement to implementing a delay. This likely would be a check to see if it's an instant cast, but due to how fast this processes code it'll flip around and hit the button a few times before it registers the TimerReady portion is no longer valid. So you WOULD want the 300 to be considered regardless. That means that there would be at least a 300ms wait after clicking it before clicking it again just using the delays even if the item is instant cast.
The delay may need to be adjusted to higher or lower to optimize the script for yourself and or others.

So while this doesn't incorporate a timer, it at least ensures there is a delay anytime you use a clicky which could alleviate some issues.
Yes, I realized that I did not have a delay at all after anything instant-cast so I had actually removed that part before reading this. That explains why I got seven billion "you cannot use this" or whatever when the script came to that part.

Secondly: the Lua in question does absolutely nothing except click items in, and out of, combat (made easy simply by checking if autoattack is on or not).

MainLoop->if in Combat -> Click "Combat items" else Click "Out of Combat items" EndMainLoop.

And since you cannot click more than one item at a time (physically impossible and you also have to wait for the cast time AND, as it seems, the time between physical click and the game to understand that you actually clicked something) does it matter if you have a delay that pauses the run for X amount of (milli)seconds or if you set a timer (that checks if you are gtg)?
I mean, I understand the difference between the two, but is there really a meaningful difference (in this case)? As I see it, there is no need to "Oh, I cant do this, let's go on to do something else" because there is no "something else" to do.

I did a manual test. I clicked my epic2, and there was a very visible delay (at least 1 second) between my mouse click and the moment when the item "greyed out" and the spell cast. I think I will go with the original solution and just increase the time after a click until I let the script continue the loop and see if that works. Otherwise, I will come back here and complain! (just kidding of course) :) Thanks for everyone's assistance, advice and patience. :woop:

Follow up question: is it possible for a poorly written macroscript/Lua to make the game itself lag out? The game lagged something horribly this morning, never seen anything like it. My computer did not lag, nor did macroquest, just the game. Mobs started to run away from me (I could see them move away on the map) but the target circle on the ground stayed put infront of me etc. I could see the mob's HP-bar go down, but I saw no combat animation on my toon at all and other strange things, like the guild hall portal lagging like heck, my merc zoning before I had zoned etc
 
Last edited:
Question - Lua spams (due to lag?)

Users who are viewing this thread

Back
Top
Cart