Skip to content

Commit 51a3956

Browse files
committed
Move to Minecrift 1.8.1 method of two stage patching, client.md5 generation
1 parent 9481b42 commit 51a3956

39 files changed

+1144
-142
lines changed

applychanges.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,32 +53,35 @@ def merge_tree(root_src_dir, root_dst_dir):
5353
shutil.copy(src_file, dst_dir)
5454

5555

56-
def applychanges(mcp_dir):
56+
def applychanges(mcp_dir, patch_dir = "patches", backup = True, copyOriginal=True, mergeInNew=True ):
5757
print("Applying Changes...")
5858

5959
mod_src_dir = os.path.join(mcp_dir, "src","minecraft")
6060
mod_bak_dir = os.path.join(mcp_dir, "src","minecraft-bak")
6161
org_src_dir = os.path.join(mcp_dir, "src",".minecraft_orig")
6262

63-
if os.path.exists(mod_src_dir):
63+
if backup and os.path.exists(mod_src_dir):
6464
print("Backing up src/minecraft to src/minecraft-bak")
6565
shutil.rmtree( mod_bak_dir, True )
6666
shutil.move( mod_src_dir, mod_bak_dir )
67-
shutil.copytree( org_src_dir, mod_src_dir, ignore=lambda p,f: [".git"] )
67+
if copyOriginal:
68+
shutil.copytree( org_src_dir, mod_src_dir, ignore=lambda p,f: [".git"] )
6869

6970
#apply patches
70-
apply_patches( mcp_dir, os.path.join( base_dir, "patches"), mod_src_dir )
71+
apply_patches( mcp_dir, os.path.join( base_dir, patch_dir ), mod_src_dir )
7172
#merge in the new classes
72-
merge_tree( os.path.join( base_dir, "src" ), mod_src_dir )
73+
if mergeInNew:
74+
merge_tree( os.path.join( base_dir, "src" ), mod_src_dir )
7375

7476
if __name__ == '__main__':
7577
parser = OptionParser()
7678
parser.add_option('-m', '--mcp-dir', action='store', dest='mcp_dir', help='Path to MCP to use', default=None)
79+
parser.add_option('-p', '--patch-dir', action='store', dest='patch_dir', help='Path to base patch dir', default='patches')
7780
options, _ = parser.parse_args()
7881

7982
if not options.mcp_dir is None:
80-
applychanges(os.path.abspath(options.mcp_dir))
83+
applychanges(os.path.abspath(options.mcp_dir), options.patch_dir)
8184
elif os.path.isfile(os.path.join('..', 'runtime', 'commands.py')):
82-
applychanges(os.path.abspath('..'))
85+
applychanges(os.path.abspath('..'), options.patch_dir)
8386
else:
84-
applychanges(os.path.abspath(mcp_version))
87+
applychanges(os.path.abspath(mcp_version), options.patch_dir)

build.py

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from tempfile import mkstemp
66
from shutil import move
77
from os import remove, close
8-
from install import download_deps, download_native, download_file, mkdir_p
8+
from install import download_deps, download_native, download_file, mkdir_p, replacelineinfile
99
from minecriftversion import mc_version, of_file_name, of_json_name, minecrift_version_num, minecrift_build, of_file_extension, of_file_md5, mcp_version, forge_version
1010

1111
try:
@@ -137,25 +137,6 @@ def create_install(mcp_dir):
137137
cwd=os.path.join(base_dir,"installer","launch4j"),
138138
bufsize=-1).communicate()
139139
os.unlink( "launch4j.xml" )
140-
141-
def replacelineinfile(file_path, pattern, subst):
142-
#Create temp file
143-
fh, abs_path = mkstemp()
144-
new_file = open(abs_path,'w')
145-
old_file = open(file_path)
146-
for line in old_file:
147-
if pattern in line:
148-
new_file.write(subst)
149-
else:
150-
new_file.write(line)
151-
#close temp file
152-
new_file.close()
153-
close(fh)
154-
old_file.close()
155-
#Remove original file
156-
remove(file_path)
157-
#Move new file
158-
move(abs_path, file_path)
159140

160141
def main(mcp_dir):
161142
print 'Using mcp dir: %s' % mcp_dir

getchanges.bat

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
1-
echo Building patches...
21
@echo off
3-
python getchanges.py
2+
python getchanges.py %*

getchanges.py

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@ def create_patch( target_dir, src_file, mod_file, label, patch_file ):
2727
process = subprocess.Popen(cmd, cwd=target_dir, bufsize=-1, stdout=subprocess.PIPE)
2828
stdout, stderr = process.communicate()
2929
if stdout:
30-
with open( patch_file, 'w') as out:
31-
out.write( stdout )
30+
with open( patch_file, 'wb') as out:
31+
out.write( stdout.replace('\r\n','\n').replace('\r','\n') )
3232

33-
def main(mcp_dir):
33+
def main(mcp_dir, patch_dir = "patches"):
3434
new_src_dir = os.path.join( base_dir , "src" )
35-
patch_base_dir = os.path.join( base_dir , "patches" )
35+
patch_base_dir = os.path.join( base_dir , patch_dir )
3636

3737
try:
3838
shutil.rmtree( new_src_dir )
@@ -81,16 +81,37 @@ def main(mcp_dir):
8181
if os.path.exists( new_file ):
8282
os.remove( new_file )
8383
shutil.copy(mod_file, new_dir)
84+
85+
removeEmptyFolders(patch_base_dir)
86+
removeEmptyFolders(new_src_dir)
87+
88+
def removeEmptyFolders(path):
89+
if not os.path.isdir(path):
90+
return
91+
92+
# remove empty subfolders
93+
files = os.listdir(path)
94+
if len(files):
95+
for f in files:
96+
fullpath = os.path.join(path, f)
97+
if os.path.isdir(fullpath):
98+
removeEmptyFolders(fullpath)
99+
100+
# if folder empty, delete it
101+
files = os.listdir(path)
102+
if len(files) == 0:
103+
os.rmdir(path)
84104

85105

86106
if __name__ == '__main__':
87107
parser = OptionParser()
88108
parser.add_option('-m', '--mcp-dir', action='store', dest='mcp_dir', help='Path to MCP to use', default=None)
109+
parser.add_option('-p', '--patch-dir', action='store', dest='patch_dir', help='Patch dir base name to use', default='patches')
89110
options, _ = parser.parse_args()
90111

91112
if not options.mcp_dir is None:
92-
main(os.path.abspath(options.mcp_dir))
113+
main(os.path.abspath(options.mcp_dir), options.patchdir)
93114
elif os.path.isfile(os.path.join('..', 'runtime', 'commands.py')):
94-
main(os.path.abspath('..'))
115+
main(os.path.abspath('..'), options.patchdir)
95116
else:
96-
main(os.path.abspath(mcp_version))
117+
main(os.path.abspath(mcp_version), options.patch_dir)

getcompilechanges.bat

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@echo off
2+
python getchanges.py -p "mcppatches/patches"

getcompilechanges.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#!/bin/bash
2+
python getchanges.py -p "mcppatches/patches"

install.py

Lines changed: 161 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
import shutil, tempfile, json
55
import errno
66
import platform
7+
import shutil
8+
import time
9+
from shutil import move
10+
from tempfile import mkstemp
11+
from os import remove, close
712
from minecriftversion import mc_version, of_file_name, of_json_name, minecrift_version_num, minecrift_build, of_file_extension, of_file_md5, mcp_version, mc_file_md5
813
from hashlib import md5 # pylint: disable-msg=E0611
914
from optparse import OptionParser
@@ -14,6 +19,9 @@
1419

1520
preferredarch = ''
1621
nomerge = False
22+
nopatch = False
23+
clean = False
24+
force = False
1725

1826
try:
1927
WindowsError
@@ -96,7 +104,7 @@ def is_non_zero_file(fpath):
96104
def download_deps( mcp_dir, download_mc ):
97105

98106
mcp_exists = True
99-
if not os.path.exists(mcp_dir+"/runtime/commands.py "):
107+
if not os.path.exists(mcp_dir+"/runtime/commands.py"):
100108
mcp_exists = False
101109
try:
102110
mcp_zip_file = os.path.join( base_dir,mcp_version+".zip" )
@@ -116,15 +124,39 @@ def download_deps( mcp_dir, download_mc ):
116124
print "No %s directory or zip file found. Please copy the %s.zip file into %s and re-run the command." % (mcp_dir, mcp_dir, base_dir)
117125
exit(1)
118126

127+
# Patch mcp.cfg for additional mem
119128
print("Patching mcp.cfg. Ignore \"FAILED\" hunks")
120129
apply_patch( mcp_dir, os.path.join("mcppatches", "mcp.cfg.patch"), os.path.join(mcp_dir,"conf"))
121130

122-
client_md5 = os.path.join("mcppatches","client.md5")
123-
target_client_md5 = os.path.join(mcp_dir,"temp","client.md5")
124-
if not os.path.exists(target_client_md5):
125-
mkdir_p( os.path.join(mcp_dir,"temp") )
126-
print 'Updating client.md5: copying %s to %s' % (client_md5, target_client_md5)
127-
shutil.copy(client_md5,target_client_md5)
131+
# Patch mcp.cfg with minecraft jar md5
132+
mcp_cfg_file = os.path.join(mcp_dir,"conf","mcp.cfg")
133+
replacelineinfile( mcp_cfg_file, "MD5Client =", "MD5Client = %s\n" % mc_file_md5, True ); # Multiple 'MD5Client' entries - hack to get first one currently
134+
#replacelineinfile( mcp_cfg_file, "MD5Server =", "MD5Server = %s\n" % mc_server_file_md5, True );
135+
136+
# patch joined.srg if necessary
137+
mcp_joined_srg = os.path.join(mcp_dir,"conf","joined.srg")
138+
patch_joined_srg = os.path.join(base_dir,"mcppatches","joined.srg")
139+
if os.path.exists(patch_joined_srg):
140+
print 'Updating joined.srg: copying %s to %s' % (patch_joined_srg, mcp_joined_srg)
141+
shutil.copy(patch_joined_srg,mcp_joined_srg)
142+
143+
# Patch fffix.py
144+
fffix_patch_path = os.path.join(base_dir, "mcppatches", "fffix.py.patch")
145+
if os.path.exists(fffix_patch_path):
146+
print("Patching fffix.py. Ignore \"FAILED\" hunks")
147+
apply_patch( mcp_dir, os.path.join("mcppatches", "fffix.py.patch"), os.path.join(mcp_dir,"runtime","pylibs"))
148+
149+
# Patch Start.java with minecraft version
150+
start_java_file = os.path.join(base_dir,"mcppatches","Start.java")
151+
target_start_java_file = os.path.join(mcp_dir,"conf","patches","Start.java")
152+
print 'Updating Start.java: copying %s to %s' % (start_java_file, target_start_java_file)
153+
shutil.copy(start_java_file,target_start_java_file)
154+
replacelineinfile( target_start_java_file, "args = concat(new String[] {\"--version\", \"mcp\"", " args = concat(new String[] {\"--version\", \"mcp\", \"--accessToken\", \"0\", \"--assetsDir\", \"assets\", \"--assetIndex\", \"%s\", \"--userProperties\", \"{}\"}, args);\n" % mc_version );
155+
156+
# Setup the appropriate mcp file versions
157+
mcp_version_cfg = os.path.join(mcp_dir,"conf","version.cfg")
158+
replacelineinfile( mcp_version_cfg, "ClientVersion =", "ClientVersion = %s\n" % mc_version );
159+
replacelineinfile( mcp_version_cfg, "ServerVersion =", "ServerVersion = %s\n" % mc_version );
128160

129161
jars = os.path.join(mcp_dir,"jars")
130162

@@ -348,6 +380,28 @@ def main(mcp_dir):
348380
print 'Preferred architecture: %sbit - preferring %sbit native extraction (use -a 32 or -a 64 to change)' % (preferredarch, preferredarch)
349381
if nomerge is True:
350382
print 'NO Optifine merging'
383+
if nopatch is True:
384+
print 'SKIPPING Apply patches'
385+
386+
if clean == True:
387+
print 'Cleaning...'
388+
if force == False:
389+
print ''
390+
print 'WARNING:'
391+
print 'The clean option will delete all folders created by MCP, including the'
392+
print 'src folder which may contain changes you made to the code, along with any'
393+
print 'saved worlds from the client or server.'
394+
print 'Minecrift downloaded dependencies will also be removed and re-downloaded.'
395+
print 'Patches will be left alone however.'
396+
answer = raw_input('If you really want to clean up, enter "Yes" ')
397+
if answer.lower() not in ['yes']:
398+
print 'You have not entered "Yes", aborting the clean up process'
399+
sys.exit(1)
400+
print 'Cleaning mcp dir...'
401+
reallyrmtree(mcp_dir)
402+
print 'Cleaning lib dir...'
403+
reallyrmtree(os.path.join(base_dir,'lib'))
404+
351405
print("\nDownloading dependencies...")
352406
download_deps( mcp_dir, True )
353407

@@ -358,7 +412,7 @@ def main(mcp_dir):
358412
print ' Merging\n %s\n into\n %s' % (optifine, minecraft_jar)
359413
zipmerge( minecraft_jar, optifine )
360414
else:
361-
print("Skipping Optifine merge...")
415+
print("Skipping Optifine merge!")
362416

363417
print("Decompiling...")
364418
src_dir = os.path.join(mcp_dir, "src","minecraft")
@@ -372,17 +426,111 @@ def main(mcp_dir):
372426

373427
os.chdir( base_dir )
374428

429+
# Create original decompile src dir
375430
org_src_dir = os.path.join(mcp_dir, "src",".minecraft_orig")
376431
if os.path.exists( org_src_dir ):
377432
shutil.rmtree( org_src_dir, True )
378433
shutil.copytree( src_dir, org_src_dir )
379434

380-
applychanges( mcp_dir )
381435

436+
if nopatch == False:
437+
compile_error_patching_done = False
438+
439+
# Patch stage 1: apply only the patches needed to correct the
440+
# optifine merge decompile errors
441+
mcp_patch_dir = os.path.join( base_dir, "mcppatches", "patches" )
442+
if os.path.exists( mcp_patch_dir ):
443+
print("Patching Optifine merge decompile errors...")
444+
applychanges( mcp_dir, patch_dir="mcppatches/patches", backup=False, copyOriginal=False, mergeInNew=False )
445+
compile_error_patching_done = True
446+
447+
# Address problem files - copy over directly
448+
problem_file_dir = os.path.join( base_dir, "mcppatches", "problemfiles" )
449+
if os.path.exists( problem_file_dir ):
450+
print("Addressing problem files...")
451+
xp_problem_file = os.path.join(problem_file_dir, "xp.java")
452+
shutil.copy( xp_problem_file, os.path.join( mcp_dir, "src", "minecraft", "net", "minecraft", "src", "xp.java" ) )
453+
chunkrenderdispatcher_problem_file = os.path.join(problem_file_dir, "ChunkRenderDispatcher.java")
454+
shutil.copy( chunkrenderdispatcher_problem_file, os.path.join( mcp_dir, "src", "minecraft", "net", "minecraft", "client", "renderer", "chunk", "ChunkRenderDispatcher.java" ) )
455+
compile_error_patching_done = True
456+
457+
# Update the client md5
458+
if compile_error_patching_done == True:
459+
print("Updating client.md5...")
460+
os.chdir(mcp_dir)
461+
from runtime.updatemd5 import updatemd5
462+
updatemd5( None, True, True, False )
463+
os.chdir( base_dir )
464+
465+
# Now re-create the .minecraft_orig with the new buildable state
466+
if os.path.exists( org_src_dir ):
467+
shutil.rmtree( org_src_dir, True )
468+
shutil.copytree( src_dir, org_src_dir )
469+
470+
# Patch stage 2: Now apply our main Minecrift patches, only
471+
# changes needed for Minecrift functionality
472+
print("Applying full Minecrift patches...")
473+
applychanges( mcp_dir )
474+
else:
475+
print("Apply patches skipped!")
476+
477+
def reallyrmtree(path):
478+
if not sys.platform.startswith('win'):
479+
if os.path.exists(path):
480+
shutil.rmtree(path)
481+
else:
482+
i = 0
483+
try:
484+
while os.stat(path) and i < 20:
485+
shutil.rmtree(path, onerror=rmtree_onerror)
486+
i += 1
487+
except OSError:
488+
pass
489+
490+
# raise OSError if the path still exists even after trying really hard
491+
try:
492+
os.stat(path)
493+
except OSError:
494+
pass
495+
else:
496+
raise OSError(errno.EPERM, "Failed to remove: '" + path + "'", path)
382497

498+
def rmtree_onerror(func, path, _):
499+
if not os.access(path, os.W_OK):
500+
os.chmod(path, stat.S_IWUSR)
501+
time.sleep(0.5)
502+
try:
503+
func(path)
504+
except OSError:
505+
pass
506+
507+
def replacelineinfile(file_path, pattern, subst, firstmatchonly=False):
508+
#Create temp file
509+
fh, abs_path = mkstemp()
510+
new_file = open(abs_path,'wb')
511+
old_file = open(file_path,'rb')
512+
hit = False
513+
for line in old_file:
514+
if pattern in line and not (firstmatchonly == True and hit == True):
515+
new_file.write(subst)
516+
hit = True
517+
else:
518+
new_file.write(line)
519+
#close temp file
520+
new_file.close()
521+
close(fh)
522+
old_file.close()
523+
#Remove original file
524+
remove(file_path)
525+
#Move new file
526+
move(abs_path, file_path)
527+
383528
if __name__ == '__main__':
384529
parser = OptionParser()
385530
parser.add_option('-o', '--no-optifine', dest='nomerge', default=False, action='store_true', help='If specified, no optifine merge will be carried out')
531+
parser.add_option('-c', '--clean', dest='clean', default=False, action='store_true', help='Cleans the mcp dir, and REMOVES ALL SOURCE IN THE MCPxxx/SRC dir. Re-downloads dependencies')
532+
parser.add_option('-f', '--force', dest='force', default=False, action='store_true', help='Forces any changes without prompts')
533+
parser.add_option('-n', '--no-patch', dest='nopatch', default=False, action='store_true', help='If specified, no patches will be applied at the end of installation')
386534
parser.add_option('-m', '--mcp-dir', action='store', dest='mcp_dir', help='Path to MCP to use', default=None)
387535
parser.add_option('-a', '--architecture', action='store', dest='arch', help='Architecture to use (\'32\' or \'64\'); prefer 32 or 64bit dlls', default=None)
388536
options, _ = parser.parse_args()
@@ -395,8 +543,12 @@ def main(mcp_dir):
395543

396544
if preferredarch is '':
397545
preferredarch = osArch()
546+
398547

399548
nomerge = options.nomerge
549+
nopatch = options.nopatch
550+
clean = options.clean
551+
force = options.force
400552

401553
if not options.mcp_dir is None:
402554
main(os.path.abspath(options.mcp_dir))

0 commit comments

Comments
 (0)