Skip to content

Instantly share code, notes, and snippets.

@anotherdirtbag
Created April 14, 2020 04:17
Show Gist options
  • Save anotherdirtbag/aaa3df8d51037e1d823f4e069d674fcf to your computer and use it in GitHub Desktop.
Save anotherdirtbag/aaa3df8d51037e1d823f4e069d674fcf to your computer and use it in GitHub Desktop.
python script that allows parsing, editing, and saving Stellaris by Paradox config .txt files
import os
import re
def main():
modpath = os.path.join(r'C:\Users\sokka\Documents\Paradox Interactive\Stellaris\mod\better_queue')
installpath = os.path.join(r'C:\Games\Stellaris')
scrfile = os.path.join(r'common\buildings', '01_pop_assembly_buildings.txt')
#scrfile = os.path.join(r'common\colony_automation', '00_capital_automation.txt')
outfile = os.path.join(modpath, scrfile)
if not os.path.exists( os.path.dirname(outfile) ):
os.makedirs(os.path.dirname(outfile))
os.chdir( modpath)
filedata = filterfile(os.path.join(installpath, scrfile))
fileelements = StellarList(_isroot=True) #the root list
result = fileelements.loads(filedata)
if len(result) > 0:
print("something went wrong")
else:
print("it worked!")
newfiledata = fileelements.dumps()
with open(outfile, 'w') as outfiledata:
outfiledata.write(newfiledata)
getelemkeyop = re.compile(r'[\t\ ]*([\w\d_]+)[\t\ ]*([<>=]{,2})\s*')
getelemval = re.compile(r'[\t\ ]*([@\w\d_]+)\s*')
class StellarElement:
key: str
value: str # use None if no value
operand: str # for '<', '<='. if None assumes '='
def __init__(self):
self.value = None
self.operand = None
def dumps(self, tablevel):
data = '\t'*tablevel + self.key
if self.value:
if self.operand:
data += ' ' + self.operand + ' ' + self.value
else:
data += ' = ' + self.value
data += '\n'
return data
def loads(self, filestream):
keyopmatch = getelemkeyop.match( filestream)
if keyopmatch:
self.key = keyopmatch.group(1)
opmatch = keyopmatch.group(2)
filestream = filestream[keyopmatch.end():]
if opmatch:
if opmatch != '=':
self.operand = opmatch
valmatch = getelemval.match( filestream)
if valmatch:
self.value = valmatch.group(1)
filestream = filestream[valmatch.end():]
return filestream
else:
return None
getkey = re.compile(r'[\t\ ]*([\w\d_]+)\s*=\s*\{\s*')
endlist = re.compile(r'\s*\}\s*')
class StellarList:
key: str
value: list
isroot: bool
def __init__(self, _isroot=False):
self.key = None
self.value = list()
self.isroot = _isroot
def dumps(self, tablevel=0):
if not self.isroot:
data = '\t'*tablevel + self.key + ' = {\n'
tablevel += 1
else:
data = ''
for elem in self.value:
data += elem.dumps(tablevel)
if not self.isroot:
tablevel -= 1
data += '\t'*tablevel + '}\n'
return data
def loads(self, filestream):
if not self.isroot:
keymatch = getkey.match(filestream) # must use match not search
if not keymatch:
return None # not a list
self.key = keymatch.group(1)
filestream = filestream[keymatch.end():]
# start reading elements until } is found
endmatch = endlist.match(filestream)
while( not endmatch and len(filestream) > 0):
newelem = StellarList()
newfs = newelem.loads( filestream)
if newfs is None: # not a list, try an element
newelem = StellarElement()
newfs = newelem.loads( filestream)
if newfs is None:
print( filestream)
raise ValueError('>>List and Elem detection failed')
self.value.append( newelem )
filestream = newfs
endmatch = endlist.match(filestream)
if endmatch:
filestream = filestream[endmatch.end():]
return filestream
elif len(filestream) == 0:
return filestream
else:
print( filestream)
raise ValueError('>>List and Elem detection failed')
return ''
def filterfile(file_path):
with open( file_path, 'r') as filestream:
data = filestream.read()
data = re.sub(r'#.*', '', data) # Remove comments
data = re.sub(r'([\w\d_])[\t\ ]+([_\w\d])', r'\1\n\2', data) # add newline between key = value key = value
data = re.sub(r'\n{2,}', '\n', data) # Remove excessive new lines
data = re.sub(r'^\s+', '', data) # Remove all starting whitespace
return data
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment