271 lines
15 KiB
Python
271 lines
15 KiB
Python
#------------------#
|
|
import os,requests,json,time,sys,psutil,string,platform,glob,getpass,shutil,hashlib,random,subprocess,math,zipfile,threading
|
|
#------------------#
|
|
class GMCLCore(object):
|
|
'''The Main Class of the Launcher Core'''
|
|
#-----------------------------------------------------------------------#
|
|
#Class Functions
|
|
def __init__(self,LauncherName=None,LauncherVersion=None,LauncherConfig=None):
|
|
'''The global variable set function'''
|
|
''':LauncherName The name of your launcher,the default value is "GMCLCore"'''
|
|
''':LauncherVersion The version of your launcher,the default value is the version of core'''
|
|
''':LauncherConfig The custom config you want to post in'''
|
|
CoreName="GMCLCore"
|
|
CoreVersion=("A0.2.0","Alpha")
|
|
LauncherName=CoreName if(LauncherName==None) else LauncherName
|
|
LauncherVersion=CoreVersion if(LauncherVersion==None) else LauncherVersion
|
|
LauncherConfig={} if(LauncherConfig==None) else LauncherConfig
|
|
self.__SystemConfig={
|
|
"Core":{
|
|
"Name":CoreName,
|
|
"Version":CoreVersion,
|
|
"Header":{'User-Agent':LauncherName+'/'+LauncherVersion[0]+' (('+CoreName+' '+CoreVersion[0]+';'+CoreVersion[1]+'))'},
|
|
"Functions":{
|
|
"Log":{
|
|
"AutoPrint":False,
|
|
"ErrorOutput":False
|
|
},
|
|
"Debug":False,
|
|
"Aria":False
|
|
},
|
|
"Users":[]
|
|
},
|
|
"Launcher":{
|
|
"Name":LauncherName,
|
|
"Version":LauncherVersion,
|
|
"Config":LauncherConfig,
|
|
}
|
|
}
|
|
self.__Log=[]
|
|
self.__AuthWay=""
|
|
self.Log("info","Successful.","__init__")
|
|
#-----------------------------------------------------------------------#
|
|
#Log Functions
|
|
def Log(self,Type,Text,Function="Anonymous Function",ErrorType="TypeError"):
|
|
'''The function which was used to manager the log output system'''
|
|
''':Type Type of the log info'''
|
|
''':Text The main text of log info'''
|
|
''':Function The function that cause the log,the default value is "Anonymous Function"'''
|
|
''':Type The type of the error,the default value is "TypeError",Support "TypeError","ValueError","UserWarning"'''
|
|
if(Text!=""):
|
|
if(Type=="deadly"):
|
|
self.__Log.append(("DEADLY_ERROR",time.strftime("%Y-%m-%d %H:%M:%S",time.localtime()),Function,Text,ErrorType))
|
|
if(self.__SystemConfig["Core"]["Functions"]["Log"]["ErrorOutput"]):
|
|
self.MakeDir('.'+self.__SystemConfig["Launcher"]["Name"]+"\\logs")
|
|
self.OutputLog('.'+self.__SystemConfig["Launcher"]["Name"]+"\\logs\\"+time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())+".txt")
|
|
if(ErrorType=="TypeError"):
|
|
raise TypeError(Text)
|
|
elif(ErrorType=="ValueError"):
|
|
raise ValueError(Text)
|
|
else:
|
|
raise UserWarning(Text)
|
|
elif(Type=="info" or "warn" or "error"):
|
|
self.__Log.append((Type.upper(),time.strftime("%Y-%m-%d %H:%M:%S",time.localtime()),Function,Text))
|
|
if(self.__SystemConfig["Core"]["Functions"]["Log"]["AutoPrint"]==True):
|
|
print("["+Type.upper()+"]["+time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())+"]["+Function+"]"+Text)
|
|
return (Type.upper(),Text)
|
|
else:
|
|
self.__Log.append(("OTHER",time.strftime("%Y-%m-%d %H:%M:%S",time.localtime()),Function,Text))
|
|
if(self.__SystemConfig["Core"]["Functions"]["Log"]["AutoPrint"]==True):
|
|
print("[OTHER]["+time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())+"]["+Function+"]"+Text)
|
|
return ("OTHER",Text)
|
|
def OutputLog(self,Path):
|
|
'''The function which was used to output text file of program logs'''
|
|
if(os.path.isdir(Path)):
|
|
return self.Log("warn","Exist duplication name dir.","OutputLog")
|
|
else:
|
|
self.Log("info","Successful.","OutputLog")
|
|
with open(Path,"w+") as FileObject:
|
|
FileObject.write(self.__SystemConfig["Launcher"]["Name"]+"/"+self.__SystemConfig["Launcher"]["Version"][0]+" "+self.__SystemConfig["Launcher"]["Version"][1]+" | "+self.__CoreName+"/"+self.__CoreVersion[0]+" "+self.__CoreVersion[1]+" Logs "+time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())+"\n")
|
|
for text in self.__Log:
|
|
FileObject.write("["+text[0]+"]["+text[1]+"]["+text[2]+"]"+text[3]+"\n")
|
|
def ReturnLog(self):
|
|
'''The function which was used to return the list of program logs'''
|
|
self.Log("info","Successful.","ReturnLog")
|
|
return self.__Log
|
|
def PrintLastLog(self):
|
|
'''The function which was used to print the last logs of program'''
|
|
self.Log("info","Successful.","PrintLastLog")
|
|
print("["+self.__Log[-1][0]+"]["+self.__Log[-1][1]+"]["+self.__Log[-1][2]+"]"+self.__Log[-1][3])
|
|
def PrintAllLog(self):
|
|
'''The function which was used to print all logs of program'''
|
|
self.Log("info","Successful.","PrintAllLog")
|
|
for text in self.__Log:
|
|
print("["+text[0]+"]["+text[1]+"]["+text[2]+"]"+text[3])
|
|
def EnableAutoLogPrint(self):
|
|
'''The function which was used to enable the function of log auto print'''
|
|
self.__SystemConfig["Core"]["Functions"]["Log"]["AutoPrint"]=True
|
|
self.Log("info","Successful.","EnableAutoLogPrint")
|
|
def DisableAutoLogPrint(self):
|
|
'''The function which was used to disable the function of log auto print'''
|
|
self.__SystemConfig["Core"]["Functions"]["Log"]["AutoPrint"]=False
|
|
self.Log("info","Successful.","DisableAutoLogPrint")
|
|
def EnableErrorLogOutput(self):
|
|
'''The function which was used to enable the function of error log output'''
|
|
self.__SystemConfig["Core"]["Functions"]["Log"]["ErrorOutput"]=True
|
|
self.Log("info","Successful.","EnableErrorLogOutput")
|
|
def DisableErrorLogOutput(self):
|
|
'''The function which was used to disable the function of error log output'''
|
|
self.__SystemConfig["Core"]["Functions"]["Log"]["ErrorOutput"]=False
|
|
self.Log("info","Successful.","DisableErrorLogOutput")
|
|
#-----------------------------------------------------------------------#
|
|
#Download Functions
|
|
def Download(self,DownloadFrom,DownloadTo):
|
|
'''The multi-thread download function'''
|
|
''':DownloadFrom The online url for the file'''
|
|
''':DownloadTo The local path for the file'''
|
|
if(DownloadFrom=="" or DownloadTo==""):
|
|
self.Log("warn","Wrong online address or local address for download.","Download")
|
|
else:
|
|
StartTime=time.time()
|
|
FileSize=int(requests.head(DownloadFrom,headers=self.__SystemConfig["Core"]["Header"]).headers['Content-Length'])
|
|
if(self.__SystemConfig["Core"]["Functions"]["Aria"]==True):
|
|
if(platform.system()=="Windows"):
|
|
if(os.path.isfile('.'+self.__SystemConfig["Launcher"]["Name"]+"\\rely\\"+"aria2c.exe")):
|
|
os.system('.'+self.__SystemConfig["Launcher"]["Name"]+"\\rely\\"+"aria2c.exe -o "+DownloadTo+" "+DownloadFrom+" -U \""+self.__SystemConfig["Core"]["Header"]['User-Agent']+"\"")
|
|
else:
|
|
self.Log("warn","Missed Aria.","Download")
|
|
self.DownloadAriaWin()
|
|
os.system('.'+self.__SystemConfig["Launcher"]["Name"]+"\\rely\\"+"aria2c.exe -o "+DownloadTo+" "+DownloadFrom+" -U \""+self.__SystemConfig["Core"]["Header"]['User-Agent']+"\"")
|
|
else:
|
|
os.system('.'+self.__SystemConfig["Launcher"]["Name"]+"\\rely\\"+"aria2c.exe -o "+DownloadTo+" "+DownloadFrom+" -U \""+self.__SystemConfig["Core"]["Header"]['User-Agent']+"\"")
|
|
else:
|
|
with open(DownloadTo,"wb") as FileObject:
|
|
FileObject.write(requests.get(DownloadFrom).content)
|
|
self.Log("info","Success.","Download")
|
|
return (str(time.time()-StartTime),FileSize // (time.time()-StartTime))
|
|
def DownloadAriaWin(self):
|
|
'''The function which was used to download Aria environment for windows'''
|
|
if(not os.path.isdir('.'+self.__SystemConfig["Launcher"]["Name"]+"\\rely")):
|
|
self.MakeDir('.'+self.__SystemConfig["Launcher"]["Name"]+"\\rely")
|
|
if(os.path.isdir("C:\\Program Files (x86)")):
|
|
with open('.'+self.__SystemConfig["Launcher"]["Name"]+"\\rely\\"+"aria2c.exe","wb") as FileObject:
|
|
FileObject.write(requests.get("https://resource.ghink.net/aria2c/win64/aria2c.exe",headers=self.__SystemConfig["Core"]["Header"]).content)
|
|
else:
|
|
with open('.'+self.__SystemConfig["Launcher"]["Name"]+"\\rely\\"+"aria2c.exe","wb") as FileObject:
|
|
FileObject.write(requests.get("https://resource.ghink.net/aria2c/win32/aria2c.exe",headers=self.__SystemConfig["Core"]["Header"]).content)
|
|
self.Log("info","Success.","DownloadAriaWin")
|
|
def EnableAria(self):
|
|
'''The function which was used to enable the function of Aria'''
|
|
self.__SystemConfig["Core"]["Functions"]["Aria"]=True
|
|
self.Log("info","Successful.","EnableAria")
|
|
def DisableAria(self):
|
|
'''The function which was used to disable the function of Aria'''
|
|
self.__SystemConfig["Core"]["Functions"]["Aria"]=False
|
|
self.Log("info","Successful.","DisbleAria")
|
|
#-----------------------------------------------------------------------#
|
|
#File and Dir Functions
|
|
def MakeDir(self,Path):
|
|
'''The function which was used to create a dir with determination'''
|
|
''':Path The path of the dir you want to create'''
|
|
if(not os.path.isdir(Path)):
|
|
os.makedirs(Path)
|
|
self.Log("info","Successful.","MakeDir")
|
|
else:
|
|
return self.Log("warn","Exist.","MakeDir")
|
|
def SearchFile(self,Path,Tag,Depth=1):
|
|
'''The function which was used to search files'''
|
|
''':Path The root path you want to search'''
|
|
''':Tag The name keyword of the file you want to search'''
|
|
''':Depth The depth of dir you want to search,you should set as "all" if you want to search all dirs,the default value is 1'''
|
|
List=[]
|
|
i=0
|
|
for root,dirs,files in os.walk(Path,topdown=True):
|
|
if Tag in files:
|
|
i+=1
|
|
List.append(root+'\\'+Tag)
|
|
if(i==Depth):
|
|
break
|
|
else:
|
|
pass
|
|
self.Log("info","Success.","SearchFile")
|
|
return List
|
|
#-----------------------------------------------------------------------#
|
|
#Game Environment Set Functions
|
|
def GetUUID(self,Account="Steve"):
|
|
'''The function which was used to generate UUID'''
|
|
''':Account Your account,the default value is "Steve"'''
|
|
if(self.__AuthWay=="offline"):
|
|
result="OfflinePlayer:"+Account
|
|
md5=hashlib.md5()
|
|
md5.update(result.encode(encoding='utf-8'))
|
|
self.Log("info","Success.","GetUUID")
|
|
return md5.hexdigest()
|
|
else:
|
|
return self.Log("warn","Wrong auth way","GetUUID")
|
|
def GetJavaPath(self,Depth=1):
|
|
'''The function which was used to search java'''
|
|
''':Depth The depth of dir you want to search,you should set as "all" if you want to search all dirs,the default value is 1'''
|
|
if(platform.system()=="Windows"):
|
|
self.Log("info","Success.","GetJavaPath")
|
|
return self.SearchFile('C:\\','javaw.exe',Depth)
|
|
elif(platform.system()=="Linux"):
|
|
self.Log("info","Success.","GetJavaPath")
|
|
return self.SearchFile('\\','java',Depth)
|
|
else:
|
|
self.Log("info","Success.","GetJavaPath")
|
|
return self.SearchFile('\\','java',Depth)
|
|
def SetAccount(self,Account="Steve",Password=""):
|
|
'''The function which was used to set game account data'''
|
|
''':Account Your account,the default value is "Steve"'''
|
|
''':Password Your password'''
|
|
if(self.__AuthWay=="online_mojang"):
|
|
if(Account.count("@")==1):
|
|
if(json.loads(requests.get("https://authserver.mojang.com/",headers=self.__SystemConfig["Core"]["Header"]).text)['status']=="OK"):
|
|
result=json.loads(requests.post("https://authserver.mojang.com/authenticate",'{"agent":{"name":"Minecraft","Version":1},"username":"'+Account+'","password":"'+Password+'"}',headers=self.__SystemConfig["Core"]["Header"]).text)
|
|
self.__Token=result['accessToken']
|
|
self.__UUID=result['selectedProfile']['id']
|
|
self.__ID=result['selectedProfile']['name']
|
|
self.Log("info","Success.","GetAccount")
|
|
else:
|
|
return self.Log("warn","Fail to request Mojang\'s auth server.","SetAccount")
|
|
else:
|
|
return self.Log("warn","Wrong Account.","SetAccount")
|
|
elif(self.__AuthWay=="offline"):
|
|
if(Account.count("@")==1):
|
|
return self.Log("warn","Wrong Account.","SetAccount")
|
|
else:
|
|
self.__ID=Account
|
|
self.__UUID=self.GetUUID(Account)
|
|
self.__Token=""
|
|
self.Log("info","Success.","GetAccount")
|
|
else:
|
|
pass
|
|
def SetAuthWay(self,AuthWay):
|
|
'''The auth way set function'''
|
|
''':AuthWay Your auth way,must be "offline" or "online"'''
|
|
if(AuthWay=="offline"):
|
|
self.__AuthWay="offline"
|
|
self.Log("info","Success.","SetAuthWay")
|
|
elif(AuthWay=="online"):
|
|
self.__AuthWay="online"
|
|
self.Log("info","Success.","SetAuthWay")
|
|
else:
|
|
return self.Log("warn","Wrong Auth Way.","SetAccount")
|
|
def SetRecomMem(self):
|
|
'''The recommendation memory value set function'''
|
|
self.__Memory = float(psutil.virtual_memory().free / 1024 ** 3) * 0.8
|
|
self.Log("info","Success.","SetRecomMem")
|
|
def SetJavaPath(self,path):
|
|
'''The java path set function'''
|
|
''':Path Your java path'''
|
|
if(path==None):
|
|
return self.Log("warn","Wrong local address for java.","SetJavaPath")
|
|
else:
|
|
if(os.path.exists(path)):
|
|
self.__JAVA=path
|
|
self.Log("info","Success.","SetJavaPath")
|
|
else:
|
|
return self.Log("warn","Wrong local address for java.","SetJavaPath")
|
|
def SetGameMem(self,Memory):
|
|
'''The game memory value set function'''
|
|
''':Memory The memory of the game,the unit is GiBytes'''
|
|
try:
|
|
self.__Memory=float(Memory)
|
|
self.Log("info","Success.","SetGameMem")
|
|
except:
|
|
return self.Log("warn","Wrong parameter for game memory.","SetGameMem")
|
|
#-----------------------------------------------------------------------#
|
|
#Game Resouces Functions
|
|
#-----------------------------------------------------------------------#
|
|
#Game Launch Function |