Page 4 of 10
Re: Automatic 'login' script
Posted: Mon Jun 10, 2013 7:59 am
by dx876234
There is a race condition in the window reservation which results in random login failures, particularly when starting multiple windows simultaneously.
This is due to the reserveActiveWindow() using a "check file" loop followed by a make file which is absolutely not atomic, ie two logins can compete for the lock. Although it sounds like a rare condition I get into it approx every 3rd time starting my 6 client script.
I would recommend using the mkdir command instead, this is atomic.
So loop on mkdir, if successful u got the lock, else loop again with appropriate timeout of course, The dead process test can be done by checking the creation time of the directory, pretty much same as done w. the file today.
Just my 5 cents
Best regards
DX
Re: Automatic 'login' script
Posted: Mon Jun 10, 2013 8:35 am
by rock5
If you are having problems then I welcome your feedback as I didn't get to stress test it.
I think I understand what you are saying. If 2 MMs exit the loop at the same time then one will succeed and the other will fail. I assumed that if 1 starts writing to the file that it would somehow become locked to other processes writing to it, but I just checked, 2 MMs can be writing to the file at the same time. So something has to be done to make it more reliable.
I'm not sure how mkdir comes into it. How would you record which MM has the active control? How do you read the creation time of a file from MM?
The idea I had was, after it writes to the file it reads it, maybe after a small pause. If it still has control then it continues. If another processes pid is recorded then it returns to the loop to wait again.
What do you think?
Re: Automatic 'login' script
Posted: Tue Jun 11, 2013 2:13 am
by dx876234
No matter how u twist and turn it u cant make a locking mechanism in Lua file module, its simply not atomic and u will get race condition, u can make the chances small but not remove them totally. The mkdir/rmdir Windows commands (and underlying api) are atomic on the other hand, they either fail or complete and return code indicates state so we can use them for making a locking mechanisms without race conditions.
Since lua doesnt have much of a "check attributes of files and directories" api (except in lfs) we need to keep your timeout mechanism with a separate file for overriding the lock in case of stale locks.
I also modified the backoff rest to be random for more gracefully backoff.
I typically use Lua module lfs for this but thats not a good idea here as its an external "c" module, so attached is my suggestion. I've tested it as far as I can with servers down
regards
dx
EDIT: Damn, the timeout mechanism will still have a race, what if we read the timeout file, find it stale and remove it, but in between another process has done the same - then we have a race. So, the timeout file should have a separate lock i guess..which again opens up for deadlocks lol
EDIT: Ops forgot to make the timeout file....
Code: Select all
local function lockdir(lockPath)
return os.execute("mkdir "..string.fixPath(lockPath, false).." 2> nul")
end
local function unlockdir(lockPath)
os.execute("rmdir "..string.fixPath(lockPath, false))
end
local function reserveActiveWindow()
local lockPath = getExecutionPath().."/../micromacro.lck"
local lock = lockdir(lockPath)
-- Wait for if other bot needs active window
local printed = false
while lock ~= 0 do
file = io.open(getExecutionPath().."/../micromacro.pid", "r");
if file then
raw = file:read() or ""
file:close()
apid, atime = string.match(raw,"pid:(.*) time:(.*)")
apid = tonumber(apid)
atime = tonumber(atime)
if apid == nil or apid == pid or os.time()-tonumber(atime) > 60 then
releaseActiveWindow()
else
if not printed then
printf("Waiting for another bot to release the active window.")
printed = true
else
printf(".")
end
end
end
yrest(math.random(3000))
lock = lockdir(lockPath)
end
if printed then printf("\n") end
end
local function releaseActiveWindow()
os.remove(getExecutionPath().."/../micromacro.pid")
unlockdir(getExecutionPath().."/../micromacro.lck")
end
Re: Automatic 'login' script
Posted: Tue Jun 11, 2013 3:28 am
by dx876234
New locking, take 2
-dx
Code: Select all
local function lockdir(lockPath)
return (os.execute("mkdir "..string.fixPath(lockPath, false).." 2> nul") == 0)
end
local function unlockdir(lockPath)
os.execute("rmdir "..string.fixPath(lockPath, false))
end
local function setTimeout(pidPath)
file, err = io.open(pidPath, "w");
if( not file ) then
error(err, 0);
end
file:write("pid:"..getHwnd().." time:"..os.time())
file:close()
end
local function getTimeout(pidPath)
file = io.open(pidPath, "r");
if file then
raw = file:read() or ""
file:close()
apid, atime = string.match(raw,"pid:(.*) time:(.*)")
apid = tonumber(apid)
atime = tonumber(atime)
if apid and atime then
return apid, atime
end
end
return nil, nil
end
local function releaseActiveWindow()
os.remove(getExecutionPath().."/../micromacro.pid")
unlockdir(getExecutionPath().."/../micromacro.lck")
end
local function reserveActiveWindow()
local lockPath = getExecutionPath().."/../micromacro.lck"
local pidPath = getExecutionPath().."/../micromacro.pid"
local lock = lockdir(lockPath)
local pid = getHwnd()
-- Wait for if other bot needs active window
local printed = false
while not lock do
local atime, atime = getTimeout(pidPath)
-- If nil, we prolly interupted another process between creating and writing
if apid and atime then
if apid == pid or os.time()-tonumber(atime) > 60 then
printf("\nLock stale, cleaning up.")
releaseActiveWindow()
else
if not printed then
printf("Waiting for another bot to release the active window.")
printed = true
else
printf(".")
end
end
end
yrest(math.random(3000))
lock = lockdir(lockPath)
end
if printed then printf("\n") end
-- Timestamp the active window
setTimeout(pidPath)
end
Re: Automatic 'login' script
Posted: Tue Jun 11, 2013 4:24 am
by rock5
I was testing the mkdir command. It returns 3 values. The first one is nil or true. It never equals 0 so the locking function always returns false. I wonder if the returned values might depend on the system. Also the directory name needs to be surrounded by quotes for paths with spaces.
This worked for me.
Successfully created the directory.
Code: Select all
Command> print(os.execute("mkdir \""..string.fixPath(getExecutionPath().."/../mi
cromacro.lck\"", false).." 2> nul") == true)
true
Directory already exists so failed
Code: Select all
Command> print(os.execute("mkdir \""..string.fixPath(getExecutionPath().."/../mi
cromacro.lck\"", false).." 2> nul") == true)
false
If we can rely on only one process creating the folder do we even need the pid file? Or maybe we do, to check the age.
Re: Automatic 'login' script
Posted: Tue Jun 11, 2013 8:40 am
by dx876234
Well, the lock might be stale if a process gets killed while holding the lock, its a rare event but might happen. Another way would be to put in a timer and remove lock if its not gone in 60s, assuming all multi-login sequences will be faster than that. Assuming a login uses 10s this leaves room for 6 client logins, ppl who do more prolly know enough to increase the limit.
The return value was different, I get as below. Im using Windows7 64b and Lua 5.1 (5.2 missing so much support for extensions)
Command> print(os.execute("mkdir tt"))
0
Command> print(os.execute("mkdir tt"))
A subdirectory or file tt already exists.
1
Command> print(type(os.execute("mkdir tt")))
number
Command>
-dx
Re: Automatic 'login' script
Posted: Tue Jun 11, 2013 10:35 am
by rock5
Here are my exact same commands.
Code: Select all
Command> print(os.execute("mkdir tt"))
true exit 0
Command> print(os.execute("mkdir tt"))
A subdirectory or file tt already exists.
nil exit 1
Command> print(type(os.execute("mkdir tt")))
A subdirectory or file tt already exists.
nil
I'm using 5.2 though. I don't know if something changed in MM.
Just found and old version of 1.04. The display is the same as yours.
It would definitely have to support the latest MM. We could easily support both by doing.
Code: Select all
local function lockdir(lockPath)
local code = os.execute("mkdir \""..string.fixPath(lockPath, false).."\" 2> nul")
return (code == 0 or code == true)
end
Re: Automatic 'login' script
Posted: Tue Jun 11, 2013 11:43 am
by dx876234
Agree, need support for both versions.
-dx
Re: Automatic 'login' script
Posted: Wed Jun 26, 2013 2:48 am
by C3PO
Hello,
I always get stuck while it should select the char (1-8). I figured out that the function gameState returns 0 instead of 2.
Re: Automatic 'login' script
Posted: Wed Jun 26, 2013 3:21 am
by BillDoorNZ
C3PO wrote:Hello,
I always get stuck while it should select the char (1-8). I figured out that the function gameState returns 0 instead of 2.
you didnt happen to disable the zoom that happens when you get to the character selection screen did you? from memory there is a setting in one of the interface/login/*.lua files to do this. when it is set, the gameState returns 0 instead of 2
Re: Automatic 'login' script
Posted: Wed Jun 26, 2013 6:52 am
by C3PO
I'm not sure if I understand what you mean ...
Should I set fastLoginNoZoom to false? is it that what you wanted to tell me?
Re: Automatic 'login' script
Posted: Wed Jun 26, 2013 8:19 am
by rock5
That's what he meant, yes. It needs to zoom in. This was reported before. I don't think I came up with fix for it. It shouldn't be a problem though, it zooms in pretty quickly.
Re: Automatic 'login' script
Posted: Wed Jun 26, 2013 9:59 am
by C3PO
oh its not a problem, if I know that I can disable it again.
thx for the fast replies
Re: Automatic 'login' script
Posted: Mon Jul 01, 2013 5:36 am
by C3PO
Hi, it's me again
I have 2 questions:
- is it possible to minimize the rom-window within the wp-script?
is it possible to close all windows, or better to end the processes (MM and RoM)
thanks
Re: Automatic 'login' script
Posted: Mon Jul 01, 2013 10:28 am
by rock5
C3PO wrote:minimize the rom-window within the wp-script?
Code: Select all
showWindow(getWin(), sw.minimize);
C3PO wrote:is it possible to close all windows
Do you mean minimize all games? You would have to search for the other clients that the current bot is not attached to.
Code: Select all
windows = findWindowList("*", "Radiant Arcana")
for k,window in pairs(windows) do
showWindow(window, sw.minimize);
end
C3PO wrote:or better to end the processes (MM and RoM)
TASKKILL works well enough
Code: Select all
pid = findProcessByWindow(window)
os.execute("TASKKILL /PID " .. pid .. " /F")
The same could be done with MM consoles but you would have to make sure that the console doing the closing is the last one.
Code: Select all
windows = findWindowList("*", "ConsoleWindowClass") -- Note this will match Window command consoles too.
for k,window in pairs(windows) do
if window ~= getHwnd() -- Does not equal current mm window
pid = findProcessByWindow(window)
os.execute("TASKKILL /PID " .. pid .. " /F")
end
end
-- end current mm window
pid = findProcessByWindow(getHwnd())
os.execute("TASKKILL /PID " .. pid .. " /F")
I think that covers everything.
For more information check out the 'process' section of the micromacro wiki.
http://www.solarstrike.net/wiki/index.php5?title=Manual
Re: Automatic 'login' script
Posted: Tue Jul 23, 2013 11:30 am
by C3PO
Hello,
I've got another problem... From time to time the script hangs up because the Choose Server Frame is displayed. Am I doing something wrong or is there a solution for that ...
Re: Automatic 'login' script
Posted: Tue Jul 23, 2013 11:50 am
by rock5
The latest version of fastlogin fises that. Try updating.
Re: Automatic 'login' script
Posted: Wed Jul 24, 2013 10:30 am
by hagenleu
Hi Rock5 (long time no see!)
I successfully setup your fast login (108 char version) and bot is running as intendend (no error from the first to the last character in the account).
Also successfully setup this automatic login script;
from micromacro window with the following string bot run with no error:
But when i try to make a bat file tier2.bat with the following code:
Code: Select all
START micromacro.exe scripts\rom\login acc:1 char:1 path:tier2
micromacro give me the error in the attached image.
I'm sure i'm mistaking the sintax, but i can't found the right one, can you give it a look and tell me in what i'm wrong?
thx
Re: Automatic 'login' script
Posted: Wed Jul 24, 2013 11:37 am
by lolita
As rock5 said in first post
rock5 wrote:
Examples:
- From the Micromacro console
Code: Select all
rom/login acc:48 char:2 client:rom4u path:cot_tele
- Or starting multiple clients from a batch file
Code: Select all
FOR /F "tokens=1 delims=" %%A in ('cd') do SET folder=%%A
START ../../micromacro.exe "%folder%/login.lua" acc:45 char:1 client:rom4u path:path1
START ../../micromacro.exe "%folder%/login.lua" acc:46 char:1 client:rom4u path:path2
START ../../micromacro.exe "%folder%/login.lua" acc:47 char:1 client:rom4u path:path3
so in your case batch file would be
Code: Select all
FOR /F "tokens=1 delims=" %%A in ('cd') do SET folder=%%A
START ../../micromacro.exe "%folder%/login.lua" acc:1 char:1 client:rom path:tier2
Re: Automatic 'login' script
Posted: Tue Jul 30, 2013 6:11 am
by Alleexx
I have 2 runes of magic clients. One for manual play and one with ultra model files. This works great when I'm starting the clients manually and then start the bot but weird things happen when I try to do it with login script.
Even if the ultra model files are not installed on my manual client, when I start it with the bot it starts without textures anyways. When I start it manually it works though. I have checked the shortcuts and they are correct. When I start my model client for manual play and then start the non-model client with the bot the textures works. So somehow the bot manages to start a client with model files that doesn't exist in that folder.
Also any time I start a client with the bot the settings in game resets. As example it always changes graphics from low to medium.
The clients are installed in C:\Program Files\Runes of Magic\Client.exe and C:\Program Files (x86)\Runes Of Magic\Client.exe