333 lines
No EOL
12 KiB
Python
333 lines
No EOL
12 KiB
Python
import os, os.path, sys
|
|
import urllib, zipfile
|
|
import shutil, glob, fnmatch
|
|
import subprocess, logging, re
|
|
import csv, shutil
|
|
import pprint
|
|
|
|
forge_dir = os.path.dirname(os.path.abspath(__file__))
|
|
mcp_dir = os.path.abspath('..')
|
|
src_dir = os.path.join(mcp_dir, 'src')
|
|
sys.path.append(mcp_dir)
|
|
|
|
def reset_logger():
|
|
log = logging.getLogger()
|
|
while len(log.handlers) > 0:
|
|
log.removeHandler(log.handlers[0])
|
|
|
|
version_reg = re.compile(r'(([a-z]+)Version[\s]+=[\s]+)(\d+);')
|
|
def load_version(build=0):
|
|
info = {'major' : -1,
|
|
'minor' : -1,
|
|
'revision' : -1,
|
|
'build' : -1
|
|
}
|
|
hook_file = os.path.join(forge_dir, 'common/net/minecraftforge/common/ForgeVersion.java'.replace('/', os.sep))
|
|
with open(hook_file, 'r') as fh:
|
|
buf = fh.read()
|
|
|
|
def proc(match):
|
|
try:
|
|
info[match.group(2)] = int(match.group(3))
|
|
except:
|
|
pass
|
|
return match.group(0)
|
|
|
|
buf = version_reg.sub(proc, buf)
|
|
info['build'] = build
|
|
return info
|
|
|
|
def inject_version(src_file, build=0):
|
|
version = load_version(build)
|
|
|
|
tmp_file = src_file + '.tmp'
|
|
with open(src_file, 'r') as fh:
|
|
buf = fh.read()
|
|
|
|
def mapname(match):
|
|
try:
|
|
return '%s%s;' % (match.group(1), version[match.group(2)])
|
|
except KeyError:
|
|
pass
|
|
return match.group(0)
|
|
|
|
buf = version_reg.sub(mapname, buf).replace('\r\n', '\n')
|
|
|
|
with open(tmp_file, 'wb') as fh:
|
|
fh.write(buf)
|
|
shutil.move(tmp_file, src_file)
|
|
|
|
def zip_folder(path, key, zip):
|
|
files = os.listdir(path)
|
|
for file in files:
|
|
file_path = os.path.join(path, file)
|
|
file_key = os.path.join(key, file)
|
|
if os.path.isdir(file_path):
|
|
zip_folder(file_path, file_key, zip)
|
|
else:
|
|
print file_key
|
|
zip.write(file_path, file_key)
|
|
|
|
def zip_create(path, key, zip_name):
|
|
zip = zipfile.ZipFile(zip_name, 'w', zipfile.ZIP_DEFLATED)
|
|
if os.path.isdir(path):
|
|
zip_folder(path, key, zip)
|
|
else:
|
|
zip.write(path, key)
|
|
zip.close()
|
|
|
|
def apply_forge_patches(fml_dir, mcp_dir, forge_dir, src_dir, copy_files=True):
|
|
sys.path.append(fml_dir)
|
|
from fml import copytree, apply_patches
|
|
|
|
has_client = os.path.isdir(os.path.join(src_dir, 'minecraft'))
|
|
has_server = os.path.isdir(os.path.join(src_dir, 'minecraft_server'))
|
|
|
|
#patch files
|
|
print 'Applying Minecraft Forge patches'
|
|
sys.stdout.flush()
|
|
if has_client:
|
|
if os.path.isdir(os.path.join(forge_dir, 'patches', 'minecraft')):
|
|
apply_patches(mcp_dir, os.path.join(forge_dir, 'patches', 'minecraft'), src_dir)
|
|
if os.path.isdir(os.path.join(forge_dir, 'patches', 'common')):
|
|
apply_patches(mcp_dir, os.path.join(forge_dir, 'patches', 'common'), src_dir, '/common/', '/minecraft/')
|
|
if copy_files and os.path.isdir(os.path.join(forge_dir, 'client')):
|
|
copytree(os.path.join(forge_dir, 'client'), os.path.join(src_dir, 'minecraft'))
|
|
|
|
if has_server:
|
|
if os.path.isdir(os.path.join(forge_dir, 'patches', 'minecraft_server')):
|
|
apply_patches(mcp_dir, os.path.join(forge_dir, 'patches', 'minecraft_server'), src_dir)
|
|
if os.path.isdir(os.path.join(forge_dir, 'patches', 'common')):
|
|
apply_patches(mcp_dir, os.path.join(forge_dir, 'patches', 'common'), src_dir, '/common/', '/minecraft_server/')
|
|
if copy_files and os.path.isdir(os.path.join(forge_dir, 'server')):
|
|
copytree(os.path.join(forge_dir, 'server'), os.path.join(src_dir, 'minecraft_server'))
|
|
|
|
if os.path.isdir(os.path.join(forge_dir, 'patches', 'common')):
|
|
apply_patches(mcp_dir, os.path.join(forge_dir, 'patches', 'common'), src_dir)
|
|
if copy_files and os.path.isdir(os.path.join(forge_dir, 'common')):
|
|
copytree(os.path.join(forge_dir, 'common'), os.path.join(src_dir, 'common'))
|
|
|
|
def get_conf_copy(mcp_dir, forge_dir):
|
|
#Lets grab the files we dont work on
|
|
for file in ['astyle.cfg', 'version.cfg', 'patches/minecraft_ff.patch', 'patches/minecraft_server_ff.patch', 'newids.csv']:
|
|
dst_file = os.path.normpath(os.path.join(forge_dir, 'conf', file))
|
|
src_file = os.path.normpath(os.path.join(mcp_dir, 'conf', file))
|
|
if os.path.exists(dst_file):
|
|
os.remove(dst_file)
|
|
shutil.copy(src_file, dst_file)
|
|
print 'Grabbing: ' + src_file
|
|
|
|
common_srg = gen_merged_srg(mcp_dir, forge_dir)
|
|
common_exc = gen_merged_exc(mcp_dir, forge_dir)
|
|
common_map = gen_shared_searge_names(common_srg, common_exc)
|
|
#ToDo use common_map to merge the remaining csvs, client taking precidense, setting the common items to side '2' and editing commands.py in FML to have 'if csv_side == side || csv_side == '2''
|
|
gen_merged_csv(common_map, os.path.join(mcp_dir, 'conf', 'fields.csv'), os.path.join(forge_dir, 'conf', 'fields.csv'))
|
|
gen_merged_csv(common_map, os.path.join(mcp_dir, 'conf', 'methods.csv'), os.path.join(forge_dir, 'conf', 'methods.csv'))
|
|
gen_merged_csv(common_map, os.path.join(mcp_dir, 'conf', 'params.csv'), os.path.join(forge_dir, 'conf', 'params.csv'), main_key='param')
|
|
|
|
def gen_merged_srg(mcp_dir, forge_dir):
|
|
print 'Generating merged Retroguard data'
|
|
srg_client = os.path.join(mcp_dir, 'conf', 'client.srg')
|
|
srg_server = os.path.join(mcp_dir, 'conf', 'server.srg')
|
|
|
|
if not os.path.isfile(srg_client) or not os.path.isfile(srg_server):
|
|
print 'Could not find client and server srg files in "%s"' % mcp_dir
|
|
return False
|
|
|
|
client = {'PK:': {}, 'CL:': {}, 'FD:': {}, 'MD:': {}}
|
|
with open(srg_client, 'r') as fh:
|
|
for line in fh:
|
|
pts = line.rstrip('\r\n').split(' ')
|
|
if pts[0] == 'MD:':
|
|
client[pts[0]][pts[1] + ' ' + pts[2]] = pts[3] + ' ' + pts[4]
|
|
else:
|
|
client[pts[0]][pts[1]] = pts[2]
|
|
|
|
server = {'PK:': {}, 'CL:': {}, 'FD:': {}, 'MD:': {}}
|
|
with open(srg_server, 'r') as fh:
|
|
for line in fh:
|
|
pts = line.rstrip('\r\n').split(' ')
|
|
if pts[0] == 'MD:':
|
|
server[pts[0]][pts[1] + ' ' + pts[2]] = pts[3] + ' ' + pts[4]
|
|
else:
|
|
server[pts[0]][pts[1]] = pts[2]
|
|
|
|
common = {'PK:': {}, 'CL:': {}, 'FD:': {}, 'MD:': {}}
|
|
for type in common:
|
|
for key, value in client[type].items():
|
|
if key in server[type]:
|
|
if value == server[type][key]:
|
|
client[type].pop(key)
|
|
server[type].pop(key)
|
|
common[type][key] = value
|
|
|
|
for type in common:
|
|
for key, value in client[type].items():
|
|
common[type][key] = value #+ ' #C'
|
|
|
|
for type in common:
|
|
for key, value in server[type].items():
|
|
common[type][key] = value #+ ' #S'
|
|
|
|
#Print joined retroguard files
|
|
with open(os.path.join(forge_dir, 'conf', 'joined.srg'), 'w') as f:
|
|
for type in ['PK:', 'CL:', 'FD:', 'MD:']:
|
|
for key in sorted(common[type]):
|
|
f.write('%s %s %s\n' % (type, key, common[type][key]))
|
|
|
|
return common
|
|
|
|
def gen_merged_exc(mcp_dir, forge_dir):
|
|
print 'Generating merged MCInjector config'
|
|
exc_client = os.path.join(mcp_dir, 'conf', 'client.exc')
|
|
exc_server = os.path.join(mcp_dir, 'conf', 'server.exc')
|
|
|
|
client = {}
|
|
with open(exc_client, 'r') as fh:
|
|
for line in fh:
|
|
if not line.startswith('#'):
|
|
pts = line.rstrip('\r\n').split('=')
|
|
client[pts[0]] = pts[1]
|
|
|
|
server = {}
|
|
with open(exc_server, 'r') as fh:
|
|
for line in fh:
|
|
if not line.startswith('#'):
|
|
pts = line.rstrip('\r\n').split('=')
|
|
server[pts[0]] = pts[1]
|
|
|
|
common = {}
|
|
for key, value in client.items():
|
|
if key in server:
|
|
if value != server[key]:
|
|
print 'Error: Exec for shared function does not match client and server:'
|
|
print 'Function: ' + key
|
|
print 'Client: ' + value
|
|
print 'Server: ' + server[value]
|
|
if value != '|':
|
|
common[key] = value
|
|
client.pop(key)
|
|
server.pop(key)
|
|
else:
|
|
if value != '|':
|
|
common[key] = value
|
|
|
|
joined = dict(common.items() + server.items())
|
|
|
|
#Print joined mcinjector files
|
|
with open(os.path.join(forge_dir, 'conf', 'joined.exc'), 'w') as f:
|
|
for key in sorted(joined):
|
|
f.write('%s=%s\n' % (key, joined[key]))
|
|
|
|
return common
|
|
|
|
def gen_shared_searge_names(common_srg, common_exc):
|
|
field = re.compile(r'field_[0-9]+_[a-zA-Z_]+$')
|
|
method = re.compile(r'func_[0-9]+_[a-zA-Z_]+')
|
|
param = re.compile(r'p_[\w]+_\d+_')
|
|
|
|
print 'Gathering list of common searge names'
|
|
|
|
searge = []
|
|
|
|
for key, value in common_srg['FD:'].items():
|
|
m = field.search(value)
|
|
if not m is None:
|
|
if not m.group(0) in searge:
|
|
searge.append(m.group(0))
|
|
|
|
for key, value in common_srg['MD:'].items():
|
|
m = method.search(value)
|
|
if not m is None and not '#' in value:
|
|
if not m.group(0) in searge:
|
|
searge.append(m.group(0))
|
|
|
|
for key, value in common_exc.items():
|
|
m = param.findall(value)
|
|
if not m is None:
|
|
for p in m:
|
|
if not p in searge:
|
|
searge.append(p)
|
|
|
|
return searge
|
|
|
|
def gen_merged_csv(common_map, in_file, out_file, main_key='searge'):
|
|
reader = csv.DictReader(open(in_file, 'r'))
|
|
print 'Generating merged csv for %s' % os.path.basename(in_file)
|
|
sides = {'client': [], 'server': [], 'common': []}
|
|
added = []
|
|
for row in reader:
|
|
side = int(row['side'])
|
|
if row[main_key] in common_map:
|
|
if not row[main_key] in added:
|
|
row['side'] = '2'
|
|
sides['common'].append(row)
|
|
added.append(row[main_key])
|
|
elif side == 0:
|
|
sides['client'].append(row)
|
|
else:
|
|
sides['server'].append(row)
|
|
|
|
writer = csv.DictWriter(open(out_file, 'wb'), fieldnames=reader.fieldnames)
|
|
writer.writeheader()
|
|
for key in ['client', 'server', 'common']:
|
|
for row in sorted(sides[key], key=lambda row: row[main_key]):
|
|
writer.writerow(row)
|
|
|
|
def setup_forge_mcp(mcp_dir, forge_dir, dont_gen_conf=True):
|
|
mcp_conf = os.path.join(mcp_dir, 'conf')
|
|
mcp_conf_bak = os.path.join(mcp_dir, 'conf.bak')
|
|
forge_conf = os.path.join(forge_dir, 'conf')
|
|
|
|
if os.path.isdir(mcp_conf_bak):
|
|
print 'Removing old conf backup folder'
|
|
shutil.rmtree(mcp_conf_bak)
|
|
|
|
if not dont_gen_conf:
|
|
get_conf_copy(mcp_dir, forge_dir)
|
|
|
|
print 'Backing up MCP Conf'
|
|
os.rename(mcp_conf, mcp_conf_bak)
|
|
|
|
print 'Copying Forge conf'
|
|
shutil.copytree(forge_conf, mcp_conf)
|
|
|
|
def build_forge_dev(mcp_dir, forge_dir, fml_dir, build_num=0):
|
|
version = load_version(build_num)
|
|
print '=================================== Build %d.%d.%d.%d Start =================================' % (version['major'], version['minor'], version['revision'], version['build'])
|
|
|
|
src_dir = os.path.join(mcp_dir, 'src')
|
|
if os.path.isdir(src_dir):
|
|
shutil.rmtree(src_dir)
|
|
|
|
sys.path.append(fml_dir)
|
|
from fml import copytree
|
|
|
|
print 'src_work -> src'
|
|
copytree(os.path.join(mcp_dir, 'src_work'), src_dir)
|
|
print '\nCopying Client Code'
|
|
copytree(os.path.join(forge_dir, 'client'), os.path.join(src_dir, 'minecraft'), -1)
|
|
print '\nCopying Server Code'
|
|
copytree(os.path.join(forge_dir, 'server'), os.path.join(src_dir, 'minecraft_server'), -1)
|
|
print '\nCopying Common Code'
|
|
copytree(os.path.join(forge_dir, 'common'), os.path.join(src_dir, 'common'), -1)
|
|
print
|
|
inject_version(os.path.join(src_dir, 'common/net/minecraftforge/common/ForgeVersion.java'.replace('/', os.sep)), build_num)
|
|
|
|
error_level = 0
|
|
try:
|
|
sys.path.append(mcp_dir)
|
|
from runtime.recompile import recompile
|
|
|
|
os.chdir(mcp_dir)
|
|
reset_logger()
|
|
recompile(None)
|
|
reset_logger()
|
|
os.chdir(forge_dir)
|
|
|
|
except SystemExit, e:
|
|
print 'Recompile Exception: %d ' % e.code
|
|
error_level = e.code
|
|
|
|
print '=================================== Build Finished %d =================================' % error_level
|
|
return error_level |