Jump to content

Multiple Login Saver System With Account Slots


Recommended Posts

  • Active+ Member

Hi, i made some changes on this system so that it now can show multiple accounts slots and add/delete accounts easily
I'm not an experienced programmer by any means, so bugs might happen and the code isn't the most efficient and clean, so if anyone has a suggestion let me know!

https://metin2.dev/topic/20529-multiple-login-saver-system

First i recommend installing his system first because i will only be listing the changes i made and this wont work without his system installed first
Also, i will only show the steps to have 2 slots account, but they can easily be replicated to have multiple accounts.
Implemented and Tested on TMP4 Server Files but most likely will work on any other server files.

 

Be extremely careful with tabulations, i would recommend using Visual Studio Code or something similar to avoid problems with it

 

Small video:
.gif

Icons used for save and delete account button (it doesn't have on hover and on click icons so you will have to add them yourself)
Download -> 

This is the hidden content, please
 or 
This is the hidden content, please
 

 

So lets start

First delete the root/uiSelectCredentials.py  and uiscript/accountlistwindow files that wont be needed anymore
root/introwindow.py (This is configured for my own interface so you will have to change positions according to yours)

Spoiler
	#Acc 0
	{
		"name": "Acc0",
		"type": "button",
		"x" : -160, "y" : -50,
		"vertical_align": "center",
		"horizontal_align" : "center",
		"text": "|cffc8aa80",
		"default_image" : BUTTON_CHITRA + "login_0.tga",
		"over_image" : BUTTON_CHITRA + "login_1.tga",
		"down_image" : BUTTON_CHITRA + "login_2.tga",
	},
	{
		"name" : "DelAccount0",
		"type" : "button",
		"x" : -210, "y" : -50,
		"vertical_align": "center",
		"horizontal_align" : "center",
		"text": "|cffc8aa80",
		"default_image" : BUTTON_CHITRA + "del_button.tga",
	},
	{
		"name" : "saveAccount0",
		"type" : "button",
		"x" : -230, "y" : -50,
		"vertical_align": "center",
		"horizontal_align" : "center",
		"text": "|cffc8aa80",
		"default_image" : BUTTON_CHITRA + "saveButton.tga",
	},
	#Acc 1
	{
		"name" : "Acc1",
		"type" : "button",
		"x" : -160,
		"y" : -20,
		"vertical_align" : "center",
		"horizontal_align" : "center",
		"text": "|cffc8aa80",
		"default_image" : BUTTON_CHITRA + "login_0.tga",
		"over_image" : BUTTON_CHITRA + "login_1.tga",
		"down_image" : BUTTON_CHITRA + "login_2.tga",
	},
	{
		"name" : "DelAccount1",
		"type" : "button",
		"x" : -210, "y" : -20,
		"vertical_align": "center",
		"horizontal_align" : "center",
		"text": "|cffc8aa80",
		"default_image" : BUTTON_CHITRA + "del_button.tga",
	},
	{
		"name" : "saveAccount1",
		"type" : "button",
		"x" : -230, "y" : -20,
		"vertical_align": "center",
		"horizontal_align" : "center",
		"text": "|cffc8aa80",
		"default_image" : BUTTON_CHITRA + "saveButton.tga",
	},

 

 

root/intrologin.py (Remember you need to have the system from North implemented or you wont be able to find the correct lines)

Spoiler

REMEMBER, THIS IS ON PYTHON SO BE CAREFUL WITH TABULATIONS

On def Open(self) Find:

self.Show()

 

Add before:

self.LoadAccounts()

 

Find:

self.saveLoginButton        = GetObject("SaveLoginButton")
self.loadCredentialButton    = GetObject("LoadCredentials")
self.loginCredentialButton  = GetObject("LoginCredentials")

 

And replace with:

self.loginAcc0 = self.GetChild("Acc0")
self.loginAcc1 = self.GetChild("Acc1")

self.saveAcc0 = self.GetChild("saveAccount0")
self.saveAcc1 = self.GetChild("saveAccount1")

self.delAcc0 = self.GetChild("DelAccount0")
self.delAcc1 = self.GetChild("DelAccount1")

 

Next Find:

self.saveLoginButton.SetEvent(ui.__mem_func__(self.__OnClickSaveLoginButton))

self.loadCredentialButton.SetEvent(ui.__mem_func__(self.__OnClickLoadInfoButton))
self.loginCredentialButton.SetEvent(ui.__mem_func__(self.__OnClickLoginAutoButton))

 

And replace with:

self.saveAcc0.SetEvent(ui.__mem_func__(self.selectAcc0IndexSave))
self.saveAcc1.SetEvent(ui.__mem_func__(self.selectAcc1IndexSave))

self.delAcc0.SetEvent(ui.__mem_func__(self.selectAcc0IndexDel))
self.delAcc1.SetEvent(ui.__mem_func__(self.selectAcc1IndexDel))

self.loginAcc0.SetEvent(ui.__mem_func__(self.selectAcc0IndexLogin))
self.loginAcc1.SetEvent(ui.__mem_func__(self.selectAcc1IndexLogin))

 

Find def __OnClickLoginButton(self) and add before

	def LoadAccounts(self):
		file_objectRead = open("user//credentials", "r")
		credentials = file_objectRead.readlines()

		for i in credentials:
			ind = i.split(":")
			if ind[0] == '0':
				self.loginAcc0.SetText(ind[1])
			elif ind[0] == '1':
				self.loginAcc1.SetText(ind[1])
			elif ind[0] == '2':
				self.loginAcc2.SetText(ind[1])
			elif ind[0] == '3':
				self.loginAcc3.SetText(ind[1])

		file_objectRead.close()

 

Find def __OnClickLoginAutoButton and def __OnClickLoadInfoButton and def __OnClickSaveLoginButton and delete this functions, they are no longer needed (this step is optional and the it will work normally if u followed the steps correctly)

Find def encode(self, key, clear) and add before:

	def selectAcc0IndexSave(self):
		self.saveAccount(0)

	def selectAcc1IndexSave(self):
		self.saveAccount(1)

	def selectAcc0IndexDel(self):
		self.delAccount(0)

	def selectAcc1IndexDel(self):
		self.delAccount(1)

	def selectAcc0IndexLogin(self):
		self.loginAccount(0)

	def selectAcc1IndexLogin(self):
		self.loginAccount(1)

	def loginAccount(self, index):
		file_object = open("user//credentials", "r")
		credentials = file_object.readlines()

		for i in credentials:
			ind = i.split(":")
			if ind[0] == str(index):
				self.Connect("{}".format(ind[1]), "{}".format(self.decode(self.__ReadSavedPassword(),ind[2]) ))
				break

	def ClearAccounts(self):
		self.loginAcc0.SetText('')
		self.loginAcc1.SetText('')
		self.loginAcc2.SetText('')
		self.loginAcc3.SetText('')

	def saveAccount(self, index):
		id = self.idEditLine.GetText()
		pwd = self.pwdEditLine.GetText()
		keypw = self.__ReadSavedPassword()
		pwd = self.encode(keypw, pwd)

		if (len(id) == 0 or len(pwd) == 0):
			self.PopupNotifyMessage("Please type ID and Password.")
			return

		try:
			file_object = open("user//credentials", "a")
		except:
			file_object = open("user//credentials", "w")

		file_objectRead = open("user//credentials", "r")
		credentials = file_objectRead.readlines()
		file_object.close()
		file_object = open("user//credentials", "w")

		for i in credentials:
			ind = i.split(":")
			if ind[0] != str(index):
				file_object.write(i)

		file_object.write("{}:{}:{}\n".format(index,id,pwd))
		file_object.close()
		file_objectRead.close()
		self.PopupNotifyMessage("Conta Guardada.")
		self.ClearAccounts()
		self.LoadAccounts()

	def delAccount(self, index):
		try:
			file_object = open("user//credentials", "a")
		except:
			file_object = open("user//credentials", "w")

		file_objectRead = open("user//credentials", "r")
		credentials = file_objectRead.readlines()
		file_object.close()
		file_object = open("user//credentials", "w")

		for i in credentials:
			ind = i.split(":")
			if ind[0] != str(index):
				file_object.write(i)

		file_object.close()
		file_objectRead.close()

		self.PopupNotifyMessage("Conta Deletada.")
		self.ClearAccounts()
		self.LoadAccounts()

 

 

I think i'm not missing anything but if you find any error let me know and i will update the post.
Probably gonna try to do some changes on the code to make it easier to add more accounts, currently it's not that hard but can be better.

Feel free to leave suggestions and help improve this!

  • Metin2 Dev 29
  • Good 9
  • Love 1
  • Love 24
Link to comment
Share on other sites

Thank you 🙂 

Do you think would be possible to adapt this code for this version too?

So when you click F1 the first saved account will be loaded, if you click F2 will be loaded the second account, and the same thing for F3 and F4.

Now it's not working because the account are saved like this:
0 : idaccount1 : password

1 : idaccount2 : password

instead of :

idaccount1 : password

Do you know how the first index number could be ignored during the login?

 

	def OnKeyDown(self, key):
		# A fast method to login by keyboard shortcuts.
		# Create a keyboard range enum as tuple from F1 to F4.
		dikAvailableList = range(0x3B, 0x3E + 1)
		if not key in dikAvailableList:
			return

		try:
			# Creates a file object, which would be utilized to call other support methods associated with it.
			# Change old_open method with open if you get error.
			file = old_open('user//credentials', 'r')

			try:
				# Finds the given element in a list and returns its position.
				account_index = dikAvailableList.index(key)
				# Reads until EOF using readline() and returns a list containing the lines.
				account_data = file.readlines().__getitem__(account_index)
				# Returns a list of all the words in the string, using str as the separator.
				account_data = account_data.split(':')
				# Applies a function to all the items in an input list.
				account_data = map(lambda item: item.rstrip(), account_data)
				# Decode the password.
				account_data[-1] = self.decode(self.__ReadSavedPassword(), next(reversed(account_data)))

				# Connect to the server by using list [id, pw].
				self.Connect(*account_data)
			# Raised when a sequence subscript is out of range.
			except IndexError:
				pass

			# A closed file cannot be read or written any more.
			file.close()
		# Raised when an I/O operation fails for an I/O-related reason, e.g., “file not found” or “disk full”.
		except IOError:
			return

 

Edited by Cripplez
  • Metin2 Dev 1
Link to comment
Share on other sites

  • Active+ Member
22 minutes ago, Cripplez said:

Thank you 🙂 

Do you think would be possible to adapt this code for this version too?

So when you click F1 the first saved account will be loaded, if you click F2 will be loaded the second account, and the same thing for F3 and F4

	def OnKeyDown(self, key):
		# A fast method to login by keyboard shortcuts.
		# Create a keyboard range enum as tuple from F1 to F4.
		dikAvailableList = range(0x3B, 0x3E + 1)
		if not key in dikAvailableList:
			return

		try:
			# Creates a file object, which would be utilized to call other support methods associated with it.
			# Change old_open method with open if you get error.
			file = old_open('user//credentials', 'r')

			try:
				# Finds the given element in a list and returns its position.
				account_index = dikAvailableList.index(key)
				# Reads until EOF using readline() and returns a list containing the lines.
				account_data = file.readlines().__getitem__(account_index)
				# Returns a list of all the words in the string, using str as the separator.
				account_data = account_data.split(':')
				# Applies a function to all the items in an input list.
				account_data = map(lambda item: item.rstrip(), account_data)
				# Decode the password.
				account_data[-1] = self.decode(self.__ReadSavedPassword(), next(reversed(account_data)))

				# Connect to the server by using list [id, pw].
				self.Connect(*account_data)
			# Raised when a sequence subscript is out of range.
			except IndexError:
				pass

			# A closed file cannot be read or written any more.
			file.close()
		# Raised when an I/O operation fails for an I/O-related reason, e.g., “file not found” or “disk full”.
		except IOError:
			return

 

Yes and i think it can be done in a easier way than that, making use of the functions loginAccount, i'm currently trying to implement the Sash System on my server but as soon as i'm done with it, i will do that

 

But this code might work, i didnt test it, but give it a try and let me know!

Spoiler
def OnKeyDown(self, key):
  dikAvailableList = range(0x3B, 0x3E + 1)
  if not key in dikAvailableList:
    return
  
  account_index = dikAvailableList.index(key)
  self.loginAccount(account_index)

 

 

Edited by LethalArms
  • Good 1
Link to comment
Share on other sites

  • Active+ Member
15 minutes ago, Cripplez said:

Thank you again it is perfect!

just need to edit: loginAccount(account_index) -> self.loginAccount(account_index)

Fixed, glad to know it works, gonna add it on the original post thanks!

 

Also, you can easily make it show F1 - accountid, F2-accountid on the button like some servers have

 

on def LoadAccounts():

Find self.loginAcc0.SetText(ind[1])
Replace with self.loginAcc0.SetText('F1 - ' + ind[1])

Find self.loginAcc1.SetText(ind[1])
Replace with self.loginAcc1.SetText('F2 - ' + ind[1])

 

Edited by LethalArms
  • Good 1
Link to comment
Share on other sites

Announcements



×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.