Automatic 'login' script

Additional botting resources. Addons may be either for the game itself or for the RoM bot.
Forum rules
Only post additional bot resources here. Please do not ask unrelated questions.
Message
Author
dx876234
Posts: 188
Joined: Sat Jul 24, 2010 6:13 am

Re: Automatic 'login' script

#61 Post by dx876234 » Mon Jun 10, 2013 7:59 am

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

User avatar
rock5
Posts: 12173
Joined: Tue Jan 05, 2010 3:30 am
Location: Australia

Re: Automatic 'login' script

#62 Post by rock5 » Mon Jun 10, 2013 8:35 am

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?
  • Please consider making a small donation to me to support my continued contributions to the bot and this forum. Thank you. Donate
  • I check all posts before reading PMs. So if you want a fast reply, don't PM me but post a topic instead. PM me for private or personal topics only.
  • How to: copy and paste in micromacro
    ________________________
    Quote:
    • “They say hard work never hurt anybody, but I figure, why take the chance.”
          • Ronald Reagan

dx876234
Posts: 188
Joined: Sat Jul 24, 2010 6:13 am

Re: Automatic 'login' script

#63 Post by dx876234 » Tue Jun 11, 2013 2:13 am

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

dx876234
Posts: 188
Joined: Sat Jul 24, 2010 6:13 am

Re: Automatic 'login' script

#64 Post by dx876234 » Tue Jun 11, 2013 3:28 am

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

User avatar
rock5
Posts: 12173
Joined: Tue Jan 05, 2010 3:30 am
Location: Australia

Re: Automatic 'login' script

#65 Post by rock5 » Tue Jun 11, 2013 4:24 am

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.
  • Please consider making a small donation to me to support my continued contributions to the bot and this forum. Thank you. Donate
  • I check all posts before reading PMs. So if you want a fast reply, don't PM me but post a topic instead. PM me for private or personal topics only.
  • How to: copy and paste in micromacro
    ________________________
    Quote:
    • “They say hard work never hurt anybody, but I figure, why take the chance.”
          • Ronald Reagan

dx876234
Posts: 188
Joined: Sat Jul 24, 2010 6:13 am

Re: Automatic 'login' script

#66 Post by dx876234 » Tue Jun 11, 2013 8:40 am

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

User avatar
rock5
Posts: 12173
Joined: Tue Jan 05, 2010 3:30 am
Location: Australia

Re: Automatic 'login' script

#67 Post by rock5 » Tue Jun 11, 2013 10:35 am

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
  • Please consider making a small donation to me to support my continued contributions to the bot and this forum. Thank you. Donate
  • I check all posts before reading PMs. So if you want a fast reply, don't PM me but post a topic instead. PM me for private or personal topics only.
  • How to: copy and paste in micromacro
    ________________________
    Quote:
    • “They say hard work never hurt anybody, but I figure, why take the chance.”
          • Ronald Reagan

dx876234
Posts: 188
Joined: Sat Jul 24, 2010 6:13 am

Re: Automatic 'login' script

#68 Post by dx876234 » Tue Jun 11, 2013 11:43 am

Agree, need support for both versions.

-dx

C3PO
Posts: 109
Joined: Sun Jul 10, 2011 2:45 pm

Re: Automatic 'login' script

#69 Post by C3PO » Wed Jun 26, 2013 2:48 am

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.

BillDoorNZ
Posts: 446
Joined: Wed Aug 03, 2011 7:37 pm

Re: Automatic 'login' script

#70 Post by BillDoorNZ » Wed Jun 26, 2013 3:21 am

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

C3PO
Posts: 109
Joined: Sun Jul 10, 2011 2:45 pm

Re: Automatic 'login' script

#71 Post by C3PO » Wed Jun 26, 2013 6:52 am

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?

User avatar
rock5
Posts: 12173
Joined: Tue Jan 05, 2010 3:30 am
Location: Australia

Re: Automatic 'login' script

#72 Post by rock5 » Wed Jun 26, 2013 8:19 am

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.
  • Please consider making a small donation to me to support my continued contributions to the bot and this forum. Thank you. Donate
  • I check all posts before reading PMs. So if you want a fast reply, don't PM me but post a topic instead. PM me for private or personal topics only.
  • How to: copy and paste in micromacro
    ________________________
    Quote:
    • “They say hard work never hurt anybody, but I figure, why take the chance.”
          • Ronald Reagan

C3PO
Posts: 109
Joined: Sun Jul 10, 2011 2:45 pm

Re: Automatic 'login' script

#73 Post by C3PO » Wed Jun 26, 2013 9:59 am

oh its not a problem, if I know that I can disable it again.

thx for the fast replies

C3PO
Posts: 109
Joined: Sun Jul 10, 2011 2:45 pm

Re: Automatic 'login' script

#74 Post by C3PO » Mon Jul 01, 2013 5:36 am

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

User avatar
rock5
Posts: 12173
Joined: Tue Jan 05, 2010 3:30 am
Location: Australia

Re: Automatic 'login' script

#75 Post by rock5 » Mon Jul 01, 2013 10:28 am

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
  • Please consider making a small donation to me to support my continued contributions to the bot and this forum. Thank you. Donate
  • I check all posts before reading PMs. So if you want a fast reply, don't PM me but post a topic instead. PM me for private or personal topics only.
  • How to: copy and paste in micromacro
    ________________________
    Quote:
    • “They say hard work never hurt anybody, but I figure, why take the chance.”
          • Ronald Reagan

C3PO
Posts: 109
Joined: Sun Jul 10, 2011 2:45 pm

Re: Automatic 'login' script

#76 Post by C3PO » Tue Jul 23, 2013 11:30 am

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 ...

User avatar
rock5
Posts: 12173
Joined: Tue Jan 05, 2010 3:30 am
Location: Australia

Re: Automatic 'login' script

#77 Post by rock5 » Tue Jul 23, 2013 11:50 am

The latest version of fastlogin fises that. Try updating.
  • Please consider making a small donation to me to support my continued contributions to the bot and this forum. Thank you. Donate
  • I check all posts before reading PMs. So if you want a fast reply, don't PM me but post a topic instead. PM me for private or personal topics only.
  • How to: copy and paste in micromacro
    ________________________
    Quote:
    • “They say hard work never hurt anybody, but I figure, why take the chance.”
          • Ronald Reagan

hagenleu
Posts: 28
Joined: Sun Jan 02, 2011 11:20 am

Re: Automatic 'login' script

#78 Post by hagenleu » Wed Jul 24, 2013 10:30 am

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:

Code: Select all

rom/login acc:1 char:1 path:tier2
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
Attachments
mm error.jpg

User avatar
lolita
Posts: 139
Joined: Thu Oct 20, 2011 5:39 am
Location: Serbia

Re: Automatic 'login' script

#79 Post by lolita » Wed Jul 24, 2013 11:37 am

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
Life is a journey, not destination :D

Alleexx
Posts: 120
Joined: Sun May 15, 2011 4:28 am
Location: Sweden

Re: Automatic 'login' script

#80 Post by Alleexx » Tue Jul 30, 2013 6:11 am

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

Post Reply

Who is online

Users browsing this forum: Bing [Bot] and 8 guests