forked from poiuyqwert/PyMS
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathPyAI.pyw
More file actions
159 lines (150 loc) · 7.53 KB
/
Copy pathPyAI.pyw
File metadata and controls
159 lines (150 loc) · 7.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#!/usr/bin/env python
# pylint: disable=consider-using-f-string
from PyMS.Utilities.Compatibility import check_compat
check_compat('PyAI')
def main(): # type: () -> None
from PyMS.PyAI.PyAI import PyAI, LONG_VERSION
from PyMS.FileFormats.AIBIN import AIBIN
from PyMS.FileFormats.AIBIN.CodeHandlers.DataContext import DataContext
from PyMS.FileFormats.AIBIN.CodeHandlers.AISourceCodeHandlers import AIDefsSourceCodeHandler
from PyMS.FileFormats.AIBIN.CodeHandlers.AILexer import AILexer
from PyMS.FileFormats.AIBIN.CodeHandlers.AISerializeContext import AISerializeContext
from PyMS.FileFormats.AIBIN.CodeHandlers.AIParseContext import AIParseContext, AIParseSettings
from PyMS.FileFormats import DAT
from PyMS.FileFormats import TBL
from PyMS.Utilities import Assets
from PyMS.Utilities.PyMSError import PyMSError
from PyMS.Utilities import IO
from PyMS.Utilities.CodeHandlers import Formatters, DefinitionsHandler
import os, optparse, sys
from dataclasses import dataclass
@dataclass
class Options(optparse.Values):
decompile = True
units = Assets.mpq_file_path('arr', 'units.dat')
upgrades = Assets.mpq_file_path('arr', 'upgrades.dat')
techdata = Assets.mpq_file_path('arr', 'techdata.dat')
stattxt = Assets.mpq_file_path('rez', 'stat_txt.tbl')
scripts = None # type: str | None
aiscript = None # type: str | None
bwscript = None # type: str | None
hidewarns = False
deffile = None # type: str | None
gui = None # type: str | None
if not sys.argv or (len(sys.argv) == 1 and os.path.basename(sys.argv[0]).lower() in ['','pyai.py','pyai.pyw','pyai.exe']):
gui = PyAI()
gui.startup()
else:
p = optparse.OptionParser(usage='usage: PyAI [options] <inp|aiscriptin bwscriptin> [out|aiscriptout bwscriptout]', version='PyAI %s' % LONG_VERSION)
p.add_option('-d', '--decompile', action='store_true', dest='decompile', help="Decompile AI's from aiscript.bin and/or bwscript.bin [default]")
p.add_option('-c', '--compile', action='store_false', dest='decompile', help="Compile AI's to an aiscript.bin and/or bwscript.bin")
p.add_option('-u', '--units', help="Specify your own units.dat file for unit data lookups [default: PyMS\\MPQ\\arr\\units.dat]")
p.add_option('-g', '--upgrades', help="Specify your own upgrades.dat file for upgrade data lookups [default: PyMS\\MPQ\\arr\\upgrades.dat]")
p.add_option('-t', '--techdata', help="Specify your own techdata.dat file for technology data lookups [default: PyMS\\MPQ\\arr\\techdata.dat]")
p.add_option('-s', '--scripts', help="A list of AI Script ID's to decompile (seperated by commas) [default: All]")
p.add_option('-a', '--aiscript', help="Used to signify the base aiscript.bin file to compile on top of")
p.add_option('-b', '--bwscript', help="Used to signify the base bwscript.bin file to compile on top of (aiscript required if bwscript is used)")
p.add_option('-x', '--stattxt', help="Used to signify the stat_txt.tbl file to use [default: PyMS\\MPQ\\rez\\stat_txt.tbl]")
p.add_option('-w', '--hidewarns', action='store_true', help="Hides any warning produced by compiling your code [default: Off]")
p.add_option('-f', '--deffile', help="Specify an External Definition file containing variables to be used when interpreting/decompiling [default: None]")
p.add_option('--gui', help="Opens a file with the GUI")
opt = Options()
_, args = p.parse_args(values=opt)
if opt.gui:
gui = PyAI(opt.gui)
gui.startup()
else:
if not len(args) in [2,3]:
p.error('Invalid amount of arguments')
path = os.path.dirname(args[0])
if not path:
path = os.path.abspath('')
if len(args) != 3:
if opt.decompile:
if len(args) < 2:
p.error('Invalid amount of arguments, missing bwscript.bin')
args.append('%s%s%s' % (os.path.join(path,os.extsep.join(os.path.basename(args[0]).split(os.extsep)[:-1])), os.extsep, 'txt'))
else:
if len(args) < 2:
args.append('%s%s%s' % (os.path.join(path,os.extsep.join(os.path.basename(args[0]).split(os.extsep)[:-1])), os.extsep, 'bin'))
args.append('%s%s%s' % (os.path.join(path,'bw' + os.extsep.join(os.path.basename(args[0]).split(os.extsep)[:-1])), os.extsep, 'bin'))
warnings = []
try:
print("Loading units.dat '%s'..." % opt.units)
unitsdat = DAT.UnitsDAT()
unitsdat.load(opt.units)
print("- Loading finished successfully\nLoading upgrades.dat '%s'..." % opt.upgrades)
upgradesdat = DAT.UpgradesDAT()
upgradesdat.load(opt.upgrades)
print("- Loading finished successfully\nLoading techdata.dat '%s'..." % opt.techdata)
techdat = DAT.TechDAT()
techdat.load(opt.techdata)
print("- Loading finished successfully\nLoading stat_txt.tbl '%s'..." % opt.stattxt)
tbl = TBL.TBL()
tbl.load(opt.stattxt)
print('- Loading finished successfully')
data_context = DataContext(stattxt_tbl=tbl, units_dat=unitsdat, upgrades_dat=upgradesdat, techdata_dat=techdat)
definitions_handler = DefinitionsHandler.DefinitionsHandler()
parse_settings = AIParseSettings()
if opt.deffile:
print("Loading external definitions file '%s'..." % opt.deffile)
handler = AIDefsSourceCodeHandler()
with IO.InputText(opt.deffile) as f:
code = f.read()
lexer = AILexer(code)
parse_context = AIParseContext(lexer, parse_settings, definitions_handler, data_context)
handler.parse(parse_context)
parse_context.finalize()
print('- Loading finished successfully')
if opt.decompile:
ids = None # type: list[str] | None
if opt.scripts:
ids = []
for i in opt.scripts.split(','):
if len(i) != 4:
print('Invalid ID: %s' % i)
return
ids.append(i)
aibin = AIBIN.AIBIN()
print("Loading aiscript.bin '%s' and bwscript.bin '%s'..." % (args[0], args[1]))
aibin.load(args[0], args[1])
print(" - Loading finished successfully\nWriting AI Scripts to '%s'..." % args[2])
# TODO: Customize formatters
formatters = Formatters.Formatters(
block = Formatters.HyphenBlockFormatter(),
command = Formatters.ParensCommandFormatter(),
comment = Formatters.HashCommentFormatter(),
)
with open(args[2], 'w', encoding='utf-8') as f:
serialize_context = AISerializeContext(f, definitions_handler, formatters, data_context)
aibin.decompile(serialize_context, ids)
print(" - '%s' written succesfully" % args[2])
else:
aibin = AIBIN.AIBIN()
if opt.aiscript:
if opt.bwscript:
print("Loading base aiscript.bin '%s' and bwscript.bin '%s'..." % (os.path.abspath(opt.aiscript), os.path.abspath(opt.bwscript)))
else:
print("Loading base aiscript.bin '%s'..." % os.path.abspath(opt.aiscript))
aibin.load(opt.aiscript, opt.bwscript)
print(" - Loading finished successfully\nLoading script '%s'..." % args[0])
with IO.InputText(args[0]) as f:
code = f.read()
print(" - Loading finished successfully\nCompiling script '%s'..." % args[0])
lexer = AILexer(code)
parse_context = AIParseContext(lexer, parse_settings, definitions_handler, data_context)
aibin.compile(parse_context)
warnings = parse_context.warnings
print(" - '%s' compiled successfully\nSaving file '%s' to aiscript.bin '%s' and bwscript.bin '%s'..." % (args[0], args[0], args[1], args[2]))
aibin.save(args[1], args[2])
print(" - aiscript.bin '%s' and bwscript.bin '%s' written succesfully" % (args[1], args[2]))
if not opt.hidewarns:
for warning in warnings:
print(repr(warning))
except PyMSError as e:
if warnings and not opt.hidewarns:
for warning in warnings:
print(repr(warning))
print(repr(e))
if __name__ == '__main__':
main()