Jump to content

[1.5.2] TileEntity problems.


DoorCloser

Recommended Posts

Hey guys. Last time i visited this page i was a little bit rude to you guys. Sorry for that though. But now i have some more questions and problems in coding :) My TileEntity spawns ok, but always faced in one direction. How to make it faced to me always i put it.  I tried to put that code in my BlockName file:

public void onBlockPlacedBy(World par1World, int par2, int par3, int par4, EntityLiving par5EntityLiving, ItemStack par6ItemStack)
    {
        int var7 = MathHelper.floor_double((double)(par5EntityLiving.rotationYaw * 4.0F / 360.0F) + 2.5D) & 3;
        par1World.setBlockMetadataWithNotify(par2, par3, par4, var7, 2);
    }

 

So my TileEntity still spawns faced in one direction, but i think i know what the problem. Block have no Textures so i dont see it changes it's facing direction. TileEntity doesnt rotate because i have to do something in TileEntity file, i guess? Could anybody help?

Link to comment
Share on other sites

Or your TileEntitySpecialRenderer, if you're using one.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

Indeed, rotation doesn't have anything to do with the TileEntity, it's stored in metadata.

In your

getIcon

method in your Block you have to return the appropriate texture for the given side and metadata, where metadata represents the rotation.

Look at the furnace for an example.

 

That what you mean?

 

public Icon getIcon(int par1, int par2)
    {
        return par1 == 1 ? this.furnaceIconTop : (par1 == 0 ? this.furnaceIconTop : (par1 != par2 ? this.blockIcon : this.furnaceIconFront));
    }

 

 

My TileEntity Actually looks like this.

 

 

 

If i put that code for top, side, bottom and etc textures, it will sit correctly?

 

Link to comment
Share on other sites

Or your TileEntitySpecialRenderer, if you're using one.

 

Which you are.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

Indeed, rotation doesn't have anything to do with the TileEntity, it's stored in metadata.

In your

getIcon

method in your Block you have to return the appropriate texture for the given side and metadata, where metadata represents the rotation.

Look at the furnace for an example.

 

So if i use TileEntitySpecialRenderer extended in my TileEntityNameRenderer, then what i suppose to type and where? thx

Link to comment
Share on other sites

You probably have to rotate your model with

glRotate

.

GL11.glRotatef(meta * (-90), 0.0F, 0.0F, 1.0F);

You mean this? I already had this. Not a solution...

 

Then either:

 

a) meta isn't getting set correctly

b) meta is getting 0'd somewhere

c) you aren't reading the meta correctly

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

Code from

BlockFurnace

that should be of interest for you:

    /**
     * Called whenever the block is added into the world. Args: world, x, y, z
     */
    public void onBlockAdded(World par1World, int par2, int par3, int par4)
    {
        super.onBlockAdded(par1World, par2, par3, par4);
        this.setDefaultDirection(par1World, par2, par3, par4);
    }

    /**
     * set a blocks direction
     */
    private void setDefaultDirection(World par1World, int par2, int par3, int par4)
    {
        if (!par1World.isRemote)
        {
            int l = par1World.getBlockId(par2, par3, par4 - 1);
            int i1 = par1World.getBlockId(par2, par3, par4 + 1);
            int j1 = par1World.getBlockId(par2 - 1, par3, par4);
            int k1 = par1World.getBlockId(par2 + 1, par3, par4);
            byte b0 = 3;

            if (Block.opaqueCubeLookup[l] && !Block.opaqueCubeLookup[i1])
            {
                b0 = 3;
            }

            if (Block.opaqueCubeLookup[i1] && !Block.opaqueCubeLookup[l])
            {
                b0 = 2;
            }

            if (Block.opaqueCubeLookup[j1] && !Block.opaqueCubeLookup[k1])
            {
                b0 = 5;
            }

            if (Block.opaqueCubeLookup[k1] && !Block.opaqueCubeLookup[j1])
            {
                b0 = 4;
            }

            par1World.setBlockMetadataWithNotify(par2, par3, par4, b0, 2);
        }
    }

    /**
     * Called when the block is placed in the world.
     */
    public void onBlockPlacedBy(World par1World, int par2, int par3, int par4, EntityLivingBase par5EntityLivingBase, ItemStack par6ItemStack)
    {
        int l = MathHelper.floor_double((double)(par5EntityLivingBase.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3;

        if (l == 0)
        {
            par1World.setBlockMetadataWithNotify(par2, par3, par4, 2, 2);
        }

        if (l == 1)
        {
            par1World.setBlockMetadataWithNotify(par2, par3, par4, 5, 2);
        }

        if (l == 2)
        {
            par1World.setBlockMetadataWithNotify(par2, par3, par4, 3, 2);
        }

        if (l == 3)
        {
            par1World.setBlockMetadataWithNotify(par2, par3, par4, 4, 2);
        }

        if (par6ItemStack.hasDisplayName())
        {
            ((TileEntityFurnace)par1World.getBlockTileEntity(par2, par3, par4)).setGuiDisplayName(par6ItemStack.getDisplayName());
        }
    }

 

EDIT: I noticed that you're asking about 1.5.2; I'll look into it ASAP.

EDIT 2: 1.5.2 won't decompile for me...

Before you even think about modding,

Link to comment
Share on other sites

EDIT: I noticed that you're asking about 1.5.2; I'll look into it ASAP.

EDIT 2: 1.5.2 won't decompile for me...

 

You need to tweak fml.py to have different URLs.

 

Here's my fml.py that worked for Forge 871 (its basically the same as the last non-gradle 1.6.4) so it should work for you.

 

 

import os, os.path, sys
import urllib, zipfile, json, urllib2
import shutil, glob, fnmatch
import subprocess, logging, re, shlex
import csv, ConfigParser
from hashlib import md5  # pylint: disable-msg=E0611
from hashlib import sha1  # pylint: disable-msg=E0611
from pprint import pprint
from zipfile import ZipFile
from pprint import pprint
from contextlib import closing

#==========================================================================
#                      Utility Functions
#==========================================================================
def config_get_section(config, section):
    dict = {}
    options = config.options(section)
    for option in options:
        try:
            dict[option] = config.get(section, option)
        except:
            dict[option] = None
    return dict

def read_mc_versions(fml_dir, version=None, work_dir=None):
    ###########################################################################################################
    #Read mc_versions.cfg from the fml folder for the specified version, or the default 
    #version if none is specified.
    #
    #Should return a dictionary with the following keys:
    # 'new_laucher' True if the version uses the new launcher structure for assets/libraries
    # 'client_url' URL path to the minecraft client jar
    # 'client_md5' MD5 checksum of the client jar
    # 'server_url' URL path to the minecraft server jar
    # 'server_md5' MD5 checksum of the server jar
    # 'json_url' URL path to the json file for this version, or 'None' if new_launcher is false
    # 'mcp_ver' Human readable version for MCP to use for this version of Minecraft
    # 'mcp_url' URL path for MCP to download, or 'None' if there isn't one avalible
    # 'mcp_md5' MD5 checksum of the MCP archive
    # 'mcp_file' File path to the MCP archive
    #
    # If work_dir is specified the following keys also contain values:
    #   'natives_dir' File path to native libraries used by Minecraft
    #   'library_dir' File path to 'libraries' folder
    #       if 'new_launcher' is false this points to work_dir/bin/ and will not be used as maven style folder structure
    #       if 'new_launcher' is true this points to work_dir/libraraies/ and will use the maven style folder structure
    #   'client_file' File path for the client minecraft.jar
    #   'server_file' File path to the server minecraft jar
    #   'json_file' 
    #       if 'new_launcher' is false, this is 'None'
    #       if 'new_launcher' is true, this is the path to the version json file on disc.
    #   'asset_dir' Folder containering all assets/resources used by minecraft
    #
    #   Note: Because a file is give a path it does NOT mean that it exists! So alway check before using
    ############################################################################################################################
    
    versions_file = os.path.join(fml_dir, 'mc_versions.cfg')
    if not os.path.isfile(versions_file):
        print 'Could not find mc_versions.cfg in FML directory.'
        sys.exit(1)
    
    config = ConfigParser.ConfigParser()
    config.read(versions_file)
    
    default = config_get_section(config, 'default')
    if version is None:
        version = default['current_ver']
    
    if not config.has_section(version):
        print 'Error: Invalid minecraft version, could not find \'%s\' in mc_versions.cfg' % version
        sys.exit(1)
    
    mc_info = config_get_section(config, version)
    mc_info['downloads'] = []
    mc_info['version'] = version
    if not 'client_url' in mc_info.keys():
        mc_info['new_launcher'] = True
        base_url = 'http://s3.amazonaws.com/Minecraft.Download/versions/%s' % version
        mc_info['client_url'] = '%s/%s.jar' % (base_url, version)
        mc_info['json_url']   = '%s/%s.json' % (base_url, version)
        mc_info['server_url'] = '%s/minecraft_server.%s.jar' % (base_url, version)
        if not work_dir is None:
            version_dir = os.path.join(work_dir, 'versions', version)
            mc_info['natives_dir'] = os.path.join(version_dir, '%s-natives' % version)
            mc_info['library_dir'] = os.path.join(work_dir, 'libraries')
            mc_info['client_file'] = os.path.join(version_dir, '%s.jar' % version)
            mc_info['json_file']   = os.path.join(version_dir, '%s.json' % version)
            mc_info['server_file'] = os.path.join(work_dir, 'minecraft_server.%s.jar' % version)
            mc_info['asset_dir']   = os.path.join(work_dir, 'assets')
    else:
        mc_info['new_launcher'] = False
        mc_info['json_url'] = None
        if not work_dir is None:
            mc_info['natives_dir'] = os.path.join(work_dir, 'bin', 'natives')
            mc_info['library_dir'] = os.path.join(work_dir, 'bin')
            mc_info['client_file'] = os.path.join(work_dir, 'bin', 'minecraft.jar')
            mc_info['json_file']   = None
            mc_info['server_file'] = os.path.join(work_dir, 'minecraft_server.jar')
            mc_info['asset_dir']   = os.path.join(work_dir, 'resources')
            for lib in default['libraries'].split(' '):
                mc_info['libraries'].append({
                    'url'     : default['base_url'] + lib,
                    'file'    : os.path.join(work_dir, 'bin', lib),
                    'extract' : None,
                    'md5'     : None
                    })
            for native in default['natives'].split(' '):
                mc_info['libraries'].append({
                    'url_ex'  : default['base_url'] + lib,
                    'file'    : os.path.join(work_dir, 'bin', lib),
                    'extract' : { 'exclude' : ['META-INF/'] },
                    'md5'     : None
                    })
    
    if not mc_info['mcp_url'].startswith('http'):
        mc_info['mcp_url'] = None
    mc_info['mcp_file'] = os.path.join(fml_dir, 'mcp%s.zip' % mc_info['mcp_ver'])
            
    if not work_dir is None:
        for x in ['natives_dir', 'library_dir', 'asset_dir']:
            if not os.path.isdir(mc_info[x]):
                os.makedirs(mc_info[x])
        for x in ['client_file', 'server_file', 'json_file', 'mcp_file']:
            if mc_info[x] is None:
                continue
            dir = os.path.dirname(mc_info[x])
            if not os.path.isdir(dir):
                os.makedirs(dir)
        
    return mc_info

def download_file(url, target, hash=None, root=None, prefix=''):
    name = os.path.basename(target)
    
    if not root is None:
        name = os.path.abspath(target)
        name = name[len(os.path.abspath(root)) + 1:]
    
    dir = os.path.dirname(target)
    if not os.path.isdir(dir):
        os.makedirs(dir)
    
    if os.path.isfile(target) and not hash == None:
        t_hash = get_md5(target)
        if len(hash) == 40:
            t_hash = get_sha1(target)
        if not t_hash == hash:
            print '%s%s Modified, removing' % (prefix, name)
            os.remove(target)
    
    if not os.path.isfile(target):
        try:
            urllib.urlretrieve(url, target)
            if not hash == None:
                t_hash = get_md5(target)
                if len(hash) == 40:
                    t_hash = get_sha1(target)
                if not t_hash == hash:
                    print '%sDownload of %s failed hash check, deleting %s %s' % (prefix, name, t_hash, hash)
                    os.remove(target)
                    return False
            if prefix == '':
                print 'Downloaded %s' % name
            else:
                print '%s%s Done' % (prefix, name)
        except Exception as e:
            print e
            print '%sDownload of %s failed, download it manually from \'%s\' to \'%s\'' % (prefix, target, url, target)
            return False
    return True
    
def get_headers(url):
    #Connects to the given URL and requests just the headers, No data
    #Used when talking to Minecraft's asset/library server to gather server side MD5's
    #Returns a dictionary of all headers
    class HeadRequest(urllib2.Request):
        def get_method(self):
            return 'HEAD'
    response = urllib2.urlopen(HeadRequest(url))
    array = [line.rstrip('\r\n') for line in response.info().headers]
    dict = {}
    for line in array:
        pts = line.split(':', 1)
        pts[1] = pts[1].strip()
        #Strip the first and last "s if the stirng is surrounded with them
        if pts[1][0] == '"' and pts[1][-1] == '"':
            pts[1] = pts[1][1:-1]
        dict[pts[0]] = pts[1]
    
    return dict    
    
def get_md5(file):
    #Returns the MD5 digest of the specified file, or None if the file doesnt exist
    if not os.path.isfile(file):
        return None
    with closing(open(file, 'rb')) as fh:
        return md5(fh.read()).hexdigest() 
        
def get_sha1(file):
    #Returns the MD5 digest of the specified file, or None if the file doesnt exist
    if not os.path.isfile(file):
        return None
    with closing(open(file, 'rb')) as fh:
        return sha1(fh.read()).hexdigest()   

def fix_patch(in_file, out_file, find=None, rep=None):
    #Fixes the following issues in the patch file if they exist:
    #  Normalizes the path seperators for the current OS
    #  Normalizes the line endings
    # Returns the path that the file wants to apply to
    
    in_file = os.path.normpath(in_file)
    if out_file is None:
        tmp_file = in_file + '.tmp'
    else:
        out_file = os.path.normpath(out_file)
        tmp_file = out_file
        dir_name = os.path.dirname(out_file)
        if dir_name:
            if not os.path.exists(dir_name):
                os.makedirs(dir_name)
                
    file = 'not found'
    with open(in_file, 'rb') as inpatch:
        with open(tmp_file, 'wb') as outpatch:
            for line in inpatch:
                line = line.rstrip('\r\n')
                if line[:3] in ['+++', '---', 'Onl', 'dif']:
                    if not find == None and not rep == None:
                        line = line.replace('\\', '/').replace(find, rep).replace('/', os.sep)
                    else:
                        line = line.replace('\\', '/').replace('/', os.sep)
                    outpatch.write(line + os.linesep)
                else:
                    outpatch.write(line + os.linesep)
                if line[:3] == '---':
                    file = line[line.find(os.sep, line.find(os.sep)+1)+1:]
                    
    if out_file is None:
        shutil.move(tmp_file, in_file)
    return file
        
def apply_patch(patch, target, mcp_dir):
    temp = os.path.abspath('temp.patch')
    cmd = 'patch -i "%s" ' % temp
    
    if os.name == 'nt':
        applydiff = os.path.abspath(os.path.join(mcp_dir, 'runtime', 'bin', 'applydiff.exe'))
        cmd = '"%s" -uf -i "%s"' % (applydiff, temp)
        
    if os.sep == '\\':
        cmd = cmd.replace('\\', '\\\\')
    cmd = shlex.split(cmd)
    
    fix_patch(patch, temp)
    
    process = subprocess.Popen(cmd, cwd=os.path.join(mcp_dir, 'runtime'), bufsize=-1)
    process.communicate()

    if os.path.isfile(temp):
        os.remove(temp)

def file_backup(file, md5=None):
    #Takes a backup of the passed in file
    #Verifying the md5 sum if it's specified
    #At the end of this things should be in one of two states:
    # 1) file and file.backup exist, both are valid and match the md5 provided
    # 2) neither file or file.backup exist, as they both failed the md5 check
    
    base = os.path.dirname(file)
    name = os.path.basename(file)
    bck = os.path.join(base, name + '.backup')
    src = os.path.join(base, name)
    
    if not os.path.isfile(src) and not os.path.isfile(bck):
        return
    
    if os.path.isfile(bck):
        if get_md5(bck) == md5 or md5 is None:
            if os.path.isfile(src):
                os.remove(src)
            shutil.move(bck, src)
        else:
            os.remove(bck)
    
    if os.path.isfile(src):
        if not get_md5(src) == md5 and not md5 is None:
            print 'Modified %s detected, removing' % os.path.basename(src)
            os.remove(src)
        else:
            shutil.copy(src, bck) 

def normaliselines(file):
    #Normalises the lines of the specified file to linux \n line endings
    file = os.path.normpath(file)
    tmp = file + '.tmp'

    with open(file, 'rb') as in_file:
        with open(tmp, 'wb') as out_file:
            out_file.write(in_file.read().replace('\r\n', '\n'))

    shutil.move(tmp, file)

def load_srg(srg_file, reverse=False):
    #Loads a Retroguard .srg file into a dictonary
    #If reverse if true, the mappings are reversed
    with open(srg_file, 'r') as fh:
        lines = fh.readlines()
    srg = {'CL:': {}, 'MD:': {}, 'FD:': {}, 'PK:': {}}
    
    for line in lines:
        line = line.strip()
        if len(line) == 0: continue
        if line[0] == '#': continue
        args = line.split(' ')
        type = args[0]
        
        if type == 'PK:' or type == 'CL:' or type == 'FD:':
            srg[type][args[1]] = args[2]
        elif type == 'MD:':
            srg[type][args[1] + ' ' + args[2]] = args[3] + ' ' + args[4]
        else:
            assert 'Unknown type %s' % line

    if reverse:
        for type,map in srg.items():
            srg[type] = dict([[v,k] for k,v in map.items()])
    return srg

def extract_zip(src, dst, prefix=None, filter=[]):
    # Extract a zip rchive to the specified folder,
    # Filtering out anything that matches the supplied filters
    
    def is_filtered(name, excludes):
        for ex in excludes:
            if name.startswith(ex):
                return True
        return name.endswith('/')
                    
    zip = ZipFile(src)
    for name in zip.namelist():
        if is_filtered(name, filter):
            continue
        out_file = os.path.join(dst, os.sep.join(name.split('/')))
        
        if not os.path.isfile(out_file):                    
            dir = os.path.dirname(out_file)
            if not os.path.isdir(dir):
                os.makedirs(dir)
        
            if not prefix is None:
                print '%sExtracting %s' % (prefix, name)
            out = open(out_file, 'wb')
            out.write(zip.read(name))
            out.flush()
            out.close()
    zip.close()

def merge_tree(root_src_dir, root_dst_dir, prefix=None):
    #Merges the source directory into the dest directory, 
    #will overwrite anything the currently exists
    for src_dir, dirs, files in os.walk(root_src_dir):
        dst_dir = src_dir.replace(root_src_dir, root_dst_dir)
        clean_dir = src_dir.replace(root_src_dir, '')[1:]
        if not os.path.exists(dst_dir):
            os.mkdir(dst_dir)
        for file_ in files:
            src_file = os.path.join(src_dir, file_)
            dst_file = os.path.join(dst_dir, file_)
            if os.path.exists(dst_file):
                os.remove(dst_file)
            shutil.copy(src_file, dst_dir)
            if not prefix is None:
                print('%s%s%s'% (prefix, clean_dir, file_))

def read_file(file):
    if not os.path.exists(file):
        return None
    buf = None
    with closing(open(file, 'r')) as fh:
        buf = fh.read()
    return buf

def runcmd(cmd, echo=True, commands=None):
    forklist = cmdsplit(cmd)
    process = subprocess.Popen(forklist, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, bufsize=-1)
    output, _ = process.communicate()    
    
    if echo and not commands is None:
        for line in output.splitlines():
            commands.logger.info(line)

    if process.returncode:
        if not echo and not commands is None:
            for line in output.splitlines():
                commands.logger.info(line)
        return False
    return True

def cmdsplit(args):
    if os.sep == '\\':
        args = args.replace('\\', '\\\\')
    return shlex.split(args)    

def kill_signatures(jar_file):
    # Removes everything in a jar file's META-INF folder, typically used to remove signature data
    dir = os.path.dirname(jar_file)
    name = os.path.basename(jar_file)
    tmp_jar = os.path.join(dir, '%s.temp' % name)
    
    if not os.path.isfile(jar_file):
        return
    
    if os.path.isfile(tmp_jar):
        os.remove(tmp_jar)
    
    shutil.move(jar_file, tmp_jar)
    
    print('Stripping META-INF from %s' % jar_file)
    
    with closing(zipfile.ZipFile(tmp_jar, mode='a')) as zip_in:
        with closing(zipfile.ZipFile(jar_file, 'w', zipfile.ZIP_DEFLATED)) as zip_out:
            for i in zip_in.filelist:
                if not i.filename.startswith('META-INF'):
                    c = zip_in.read(i.filename)
                    zip_out.writestr(i.filename, c)
                else:
                    print('    Skipping: %s' % i.filename)
    os.remove(tmp_jar)

def apply_patches(mcp_dir, patch_dir, target_dir, find=None, rep=None):
    # Attempts to apply a directory full of patch files onto a target directory.
    sys.path.append(mcp_dir)
    
    temp = os.path.abspath('temp.patch')
    cmd = cmdsplit('patch -p2 -i "%s" ' % temp)
    
    if os.name == 'nt':
        applydiff = os.path.abspath(os.path.join(mcp_dir, 'runtime', 'bin', 'applydiff.exe'))
        cmd = cmdsplit('"%s" -uf -p2 -i "%s"' % (applydiff, temp))
    
    for path, _, filelist in os.walk(patch_dir, followlinks=True):
        for cur_file in fnmatch.filter(filelist, '*.patch'):
            patch_file = os.path.normpath(os.path.join(patch_dir, path[len(patch_dir)+1:], cur_file))
            target_file = os.path.join(target_dir, fix_patch(patch_file, temp, find, rep))
            process = subprocess.Popen(cmd, cwd=target_dir, bufsize=-1)
            process.communicate()

    if os.path.isfile(temp):
        os.remove(temp)    

#Taken from: http://stackoverflow.com/questions/7545299/distutil-shutil-copytree
def _mkdir(newdir):
    """works the way a good mkdir should 
        - already exists, silently complete
        - regular file in the way, raise an exception
        - parent directory(ies) does not exist, make them as well
    """
    if os.path.isdir(newdir):
        pass
    elif os.path.isfile(newdir):
        raise OSError("a file with the same name as the desired " \
                      "dir, '%s', already exists." % newdir)
    else:
        head, tail = os.path.split(newdir)
        if head and not os.path.isdir(head):
            _mkdir(head)
        #print "_mkdir %s" % repr(newdir)
        if tail:
            os.mkdir(newdir)
#Taken from: http://stackoverflow.com/questions/7545299/distutil-shutil-copytree
def copytree(src, dst, verbose=0, symlinks=False):
    """Recursively copy a directory tree using copy2().

    The destination directory must not already exist.
    If exception(s) occur, an Error is raised with a list of reasons.

    If the optional symlinks flag is true, symbolic links in the
    source tree result in symbolic links in the destination tree; if
    it is false, the contents of the files pointed to by symbolic
    links are copied.

    XXX Consider this example code rather than the ultimate tool.

    """
    
    if verbose == -1:
        verbose = len(os.path.abspath(dst)) + 1
    names = os.listdir(src)
    # os.makedirs(dst)
    _mkdir(dst) # XXX
    errors = []
    for name in names:
        srcname = os.path.join(src, name)
        dstname = os.path.join(dst, name)
        try:
            if symlinks and os.path.islink(srcname):
                linkto = os.readlink(srcname)
                os.symlink(linkto, dstname)
            elif os.path.isdir(srcname):
                copytree(srcname, dstname, verbose, symlinks)
            else:
                shutil.copy2(srcname, dstname)
                if verbose > 0:
                    print os.path.abspath(dstname)[verbose:]
            # XXX What about devices, sockets etc.?
        except (IOError, os.error), why:
            errors.append((srcname, dstname, str(why)))
        # catch the Error from the recursive copytree so that we can
        # continue with other files
        except Exception, err:
            errors.extend(err.args[0])
    try:
        shutil.copystat(src, dst)
    except WindowsError:
        # can't copy file access times on Windows
        pass
        
#==========================================================================
#                      MCP Related Functions
#==========================================================================
def download_mcp(fml_dir, mcp_dir, version=None):
    if os.path.isfile(os.path.join(mcp_dir, 'runtime', 'commands.py')):
        print 'MCP Detected already, not downloading'
        return True
        
    if os.path.isdir(mcp_dir):
        print 'Old MCP Directory exists, but MCP was not detected, please delete MCP directory at \'%s\'' % mcp_dir
        sys.exit(1)

    mc_info = read_mc_versions(fml_dir, version=version)
    
    print('Checking MCP zip (may take time to download)')
    if not download_file(mc_info['mcp_url'], mc_info['mcp_file'], mc_info['mcp_md5']):
        sys.exit(1)
        
    if not os.path.isdir(mcp_dir):
        _mkdir(mcp_dir)
        
    print 'Extracting MCP to \'%s\'' % mcp_dir
    extract_zip(mc_info['mcp_file'], mcp_dir, filter=['eclipse']) #, prefix='    ')
    
    #If we're not on windows, lets set the executable flag on all shell scripts and astyle-osx
    if os.name != 'nt':
        for path, _, filelist in os.walk(mcp_dir):
            for cur_file in fnmatch.filter(filelist, '*.sh'):
              file_name = os.path.join(path, cur_file)
              process = subprocess.Popen(cmdsplit('chmod +x "%s"' % file_name), stdout=subprocess.PIPE, stderr=subprocess.STDOUT, bufsize=-1)
              output, _ = process.communicate()
             
        process = subprocess.Popen(cmdsplit('chmod +x "%s/runtime/bin/astyle-osx"' % mcp_dir), stdout=subprocess.PIPE, stderr=subprocess.STDOUT, bufsize=-1)
        output, _ = process.communicate()

    #As a helper to build servers, or people who don't wish to download all libraris and assets every time.
    #Copy all data from 'mcp_data' to the mcp directory
    data_dir = os.path.join(fml_dir, 'mcp_data')
    if os.path.isdir(data_dir):
        print 'Moving mcp_data to MCP'
        merge_tree(data_dir, mcp_dir)##, prefix='    ')
    
    return True
    
def setup_mcp(fml_dir, mcp_dir, gen_conf=True):
    #Modifies MCP to the state FML needs it in for recompile/reobf/etc to work as we intend it.
    #Does not decompile minecraft in this stage!
    
    print('Setting up MCP')
    runtime = os.path.join(mcp_dir, 'runtime', 'commands.py')
    file_backup(runtime)
    
    patch = os.path.join(fml_dir, 'commands.patch')
    
    if not os.path.isfile(patch):
        raise Exception('Commands.py patch not found %s' % patch)
        return
        
    print('Patching commands.py')
    apply_patch(patch, runtime, mcp_dir=mcp_dir)
    
    try:
        sys.path.append(mcp_dir)
        from runtime.commands import commands_sanity_check
        commands_sanity_check()
    except ImportError as ex:
        print('Could not verify commands.py patch integrity, this typically means that you are not in a clean MCP environment.')
        print('Download a clean version of MCP %s and try again' % mcp_version)
        print(ex)
        sys.exit(1)
    
    mcp_conf = os.path.join(mcp_dir, 'conf')
    mcp_conf_bak = os.path.join(mcp_dir, 'conf.bak')
    fml_conf = os.path.join(fml_dir, 'conf')
    
    if gen_conf:
        if os.path.isdir(mcp_conf_bak):
            print 'Reverting old conf backup folder'
            shutil.rmtree(mcp_conf)
            os.rename(mcp_conf_bak, mcp_conf)

        create_merged_conf(mcp_dir, fml_dir)

        print 'Backing up MCP Conf'
        os.rename(mcp_conf, mcp_conf_bak)
    else:
        shutil.rmtree(mcp_conf)
    
    print 'Copying FML conf'
    shutil.copytree(fml_conf, mcp_conf)
    
    create_renamed_conf(mcp_dir, fml_dir)
    
    #update workspace
    if not os.path.isfile(os.path.join(fml_dir, 'fmlbuild.properties-sample')):
        mcp_eclipse = os.path.join(mcp_dir, 'eclipse')
        
        if os.path.isdir(os.path.join(mcp_eclipse, 'Client')) and os.path.isdir(os.path.join(mcp_eclipse, 'Server')):
            shutil.rmtree(mcp_eclipse)
            
        if not os.path.isdir(mcp_eclipse) and os.path.isdir(os.path.join(fml_dir, 'eclipse')):
            print 'Fixing MCP Workspace'
            copytree(os.path.join(fml_dir, 'eclipse'), mcp_eclipse)        

def whereis(filename, rootdir):
    # Snagged from MCP
    if not os.path.exists(rootdir):
        return []
    #logging.info('> Searching for %s in %s', filename, rootdir)
    results = []
    for path, _, filelist in os.walk(rootdir):
        if filename in filelist:
            results.append(path)
    return results
        
def find_java():
    # Snagged from MCP so we can gather this info without setting up it's Command object
    results = []
    if os.name == 'nt':
        if not results:
            import _winreg
            for flag in [_winreg.KEY_WOW64_64KEY, _winreg.KEY_WOW64_32KEY]:
                try:
                    k = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, r'Software\JavaSoft\Java Development Kit', 0, _winreg.KEY_READ | flag)
                    version, _ = _winreg.QueryValueEx(k, 'CurrentVersion')
                    k.Close()
                    k = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, r'Software\JavaSoft\Java Development Kit\%s' % version, 0, _winreg.KEY_READ | flag)
                    path, _ = _winreg.QueryValueEx(k, 'JavaHome')
                    k.Close()
                    path = os.path.join(str(path), 'bin')
                    if (runcmd('"%s" -version' % os.path.join(path, 'javac'))):
                        results.append(path)
                except (OSError):
                    pass
        if not results:
            if (runcmd('javac -version')):
                results.append('')
        if not results and 'ProgramW6432' in os.environ:
            results.extend(whereis('javac.exe', os.environ['ProgramW6432']))
        if not results and 'ProgramFiles' in os.environ:
            results.extend(whereis('javac.exe', os.environ['ProgramFiles']))
        if not results and 'ProgramFiles(x86)' in os.environ:
            results.extend(whereis('javac.exe', os.environ['ProgramFiles(x86)']))
    else:
        if not results:
            if (runcmd('javac -version')):
                results.append('')
        if not results:
            results.extend(whereis('javac', '/usr/bin'))
        if not results:
            results.extend(whereis('javac', '/usr/local/bin'))
        if not results:
            results.extend(whereis('javac', '/opt'))
    if not results:
        print('Java JDK is not installed ! Please install java JDK from http://java.oracle.com')
        sys.exit(1)
        
    return { 
        'javac' : '"%s"' % os.path.join(results[0], 'javac'),
        'java'  : '"%s"' % os.path.join(results[0], 'java')
    }

#==================================================================================
#                     MCP Conf Merger Code
#==================================================================================
def create_merged_conf(mcp_dir, fml_dir):
    print('Creating merged conf')
    #Creates the merged conf folder from MCP's conf folder to fml_dir/conf
    
    #Lets grab the files we dont work on
    for file in ['version.cfg', 'joined.exc']:
        dst_file = os.path.join(fml_dir, 'conf', file)
        src_file = os.path.join(mcp_dir, 'conf', file)
        if not os.path.isdir(os.path.dirname(dst_file)):
            os.makedirs(os.path.dirname(dst_file))
        if os.path.exists(dst_file):
            os.remove(dst_file)
        shutil.copy(src_file, dst_file)
        normaliselines(dst_file)
        print('    Copying %s' % os.path.normpath(src_file))

    print('    Generating merged Retroguard data')
    common_srg = create_merged_srg(mcp_dir, fml_dir)
    print('    Reading merged MCInjector config')
    common_exc = load_merged_exc(mcp_dir, fml_dir)
    print('    Gathering list of common searge names')
    common_map = create_shared_searge_names(common_srg, common_exc)
    
    for x in [['fields.csv', 'searge'], ['methods.csv', 'searge'], ['params.csv', 'param']]:
        print('    Generating merged csv for %s' % x[0])
        create_merged_csv(common_map, os.path.join(mcp_dir, 'conf', x[0]),  os.path.join(fml_dir, 'conf', x[0]), main_key=x[1])
    
def create_merged_srg(mcp_dir, fml_dir):
    #Merges two .srg files together to create one master mapping.
    #  When issues are encountered, they are reported but the client srg is trusted over the server
    client_file = os.path.join(mcp_dir, 'conf', 'client.srg')
    server_file = os.path.join(mcp_dir, 'conf', 'server.srg')
    
    if not os.path.isfile(client_file) or not os.path.isfile(server_file):
        print('    Could not find client and server srg files in "%s"' % mcp_dir)
        return False
        
    client = load_srg(client_file)
    server = load_srg(server_file)    
    
    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' # Tag the client only entries
            
    for type in common:
        for key, value in server[type].items():
            common[type][key] = value + ' #S' # Tag the server only entries
            
    if not fml_dir is None:
        #Print joined retroguard files
        with open(os.path.join(fml_dir, 'conf', 'joined.srg'), 'wb') 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 load_merged_exc(mcp_dir, fml_dir):
    #Reads the exc file into a dictionary
    joined = {}
    with open(os.path.join(mcp_dir, 'conf', 'joined.exc'), 'r') as fh:
        for line in fh:
            if not line.startswith('#'):
                pts = line.rstrip('\r\n').split('=')
                joined[pts[0]] = pts[1]
    
    return joined    
    
def create_shared_searge_names(common_srg, common_exc):
    #Creates an array of all srg names that are common on both the client and server
    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+_')
    
    searge = []
    
    for key, value in common_srg['FD:'].items():
        m = field.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_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 create_merged_csv(common_map, in_file, out_file, main_key='searge'):
    #Filter throw the csv and condense 'shared' mappings into one entry of side 2
    fields = []
    data = []
    with closing(open(in_file, 'r')) as fh:
        reader = csv.DictReader(fh)
        fields = reader.fieldnames
        data = [r for r in reader]
        
    side = [
        [r for r in data if r['side'] == '0' and not r[main_key] in common_map],
        [r for r in data if r['side'] == '1' and not r[main_key] in common_map],
        sorted([r for r in data if r[main_key] in common_map], key=lambda row: row['side'])
    ]
    
    added = []
    common = []
    for row in side[2]:
        if not row[main_key] in added:
            row['side'] = '2'
            added.append(row[main_key])
            common.append(row)
            
    with closing(open(out_file, 'wb')) as fh:
        writer = csv.DictWriter(fh, fieldnames=fields, lineterminator='\n')
        writer.writeheader()
        for row in sorted(side[0] + side[1] + common, key=lambda row: row[main_key]):
            writer.writerow(row)    

def create_renamed_conf(mcp_dir, fml_dir):
    # Creates copies of the joined srg and exec files with the new Packaged names
    # Also updates the patches in the conf folder for the new packaged names
    print('Creating Repackaged data')
    pkg_file = os.path.join(fml_dir, 'conf', 'packages.csv')
    
    pkgs = {}
    if os.path.isfile(pkg_file):
        with closing(open(pkg_file)) as fh:
            reader = csv.DictReader(fh)
            for line in reader:
                pkgs[line['class']] = line['package']
                
    def repackage_class(pkgs, cls):
        if cls.startswith('net/minecraft/src/'):
            tmp = cls[18:]
            if tmp in pkgs.keys():
               return '%s/%s' % (pkgs[tmp], tmp)
        return cls
        
    for ext in ['srg', 'exc']:
        regnms = re.compile(r'net/minecraft/src/(\w+)')
        print('    Creating re-packaged %s' % ext)
        
        buf = read_file(os.path.join(mcp_dir, 'conf', 'joined.%s' % ext))
        def mapname(match):
            return repackage_class(pkgs, match.group(0))
        buf = regnms.sub(mapname, buf)
        
        with closing(open(os.path.join(mcp_dir, 'conf', 'packaged.%s' % ext), 'wb')) as outf:
            outf.write(buf)
    
    print('    Creating re-packaged MCP patches')
    
    def fix_patches(patch_in, patch_tmp):        
        regnms = re.compile(r'net\\minecraft\\src\\(\w+)')
        with closing(open(patch_in, 'r')) as fh:
            buf = fh.read()
            def mapname(match):
                return repackage_class(pkgs, match.group(0).replace('\\', '/')).replace('/', '\\')
            buf = regnms.sub(mapname, buf)
            
        with closing(open(patch_tmp, 'w')) as fh:
            fh.write(buf)
                        
        shutil.move(patch_tmp, patch_in)

    patch_dir = os.path.join(mcp_dir, 'conf', 'patches')
    fix_patches(os.path.join(patch_dir, 'minecraft_ff.patch'       ), os.path.join(patch_dir, 'tmp.patch'))
    fix_patches(os.path.join(patch_dir, 'minecraft_server_ff.patch'), os.path.join(patch_dir, 'tmp.patch'))

#==========================================================================
#                      MCP Decompile Process
#==========================================================================
def reset_logger():
    # Resets the logging handlers, if we don't do this, we get multi-prints from MCP
    log = logging.getLogger()
    while len(log.handlers) > 0:
        log.removeHandler(log.handlers[0])

count = 0
def cleanup_source(path):
    # We cleanup various things in MCP such as:
    # astyle differences:
    #  newline after case before case body
    #  newline after case body before new case
    # We also assign jad-style names to local variables in decompiled code.
    
    from rename_vars import rename_class
    path = os.path.normpath(path)
    regex_cases_before = re.compile(r'((case|default).+\r?\n)\r?\n', re.MULTILINE) #Fixes newline after case before case body
    regex_cases_after = re.compile(r'\r?\n(\r?\n[ \t]+(case|default))', re.MULTILINE) #Fixes newline after case body before new case
    
    def updatefile(src_file):
        global count
        tmp_file = src_file + '.tmp'
        count = 0
        with open(src_file, 'r') as fh:
            buf = fh.read()
            
        def fix_cases(match):
            global count
            count += 1
            return match.group(1)

        buf = regex_cases_before.sub(fix_cases, buf)
        buf = regex_cases_after.sub(fix_cases, buf)
        old = buf.replace('\r', '')
        buf = rename_class(old, MCP=True)

        if count > 0 or buf != old:
            with open(tmp_file, 'w') as fh:
                fh.write(buf)
            shutil.move(tmp_file, src_file)
            
    for path, _, filelist in os.walk(path, followlinks=True):
        sub_dir = os.path.relpath(path, path)
        for cur_file in fnmatch.filter(filelist, '*.java'):
            src_file = os.path.normpath(os.path.join(path, cur_file))
            updatefile(src_file)

compile_tools = True
client_jar = None
def decompile_minecraft(fml_dir, mcp_dir, disable_at=False, disable_merge=False, enable_server=False, disable_client=False, disable_assets=False):
    # This is where the bulk of the decompile actually happens
    # Its a bit of a pain as we need to hook into MCP's Commands class to inject our transformers at certian times.
    global compile_tools
    global client_jar
    
    sys.path.append(mcp_dir)
    from runtime.decompile import decompile
    from runtime.cleanup import cleanup
    from runtime.commands import Commands, CLIENT, SERVER
    
    fml_dir = os.path.abspath(fml_dir)
    
    # Make sure the src directroy is dead
    src_dir = os.path.join(mcp_dir, 'src')        
    if os.path.isdir(src_dir):
        os.chdir(mcp_dir)
        cleanup(None, False, False)
        reset_logger()
        os.chdir(fml_dir)
        
    if os.path.isdir(src_dir):
        print 'Please make sure to backup your modified files, and say yes when it asks you to do cleanup.'
        sys.exit(1)
    
    compile_tools = True
    
    # Inject ourselves before RetroGuard if it's used
    def applyrg_shunt(self, side, reobf=False, applyrg_real=Commands.applyrg):
        transformers_hook(self, side)
        self.logger.info('> Really Applying Retroguard')
        applyrg_real(self, side, reobf)
    # Inject ourselves before SpecialSource if it's used
    def applyss_shunt(self, side, reobf=False, srg_names=False, in_jar=None, out_jar=None, keep_lvt=False, keep_generics=False, applyss_real=Commands.applyss):
        transformers_hook(self, side)
        self.logger.info('> Really Applying SpecialSource')
        applyss_real(self, side, reobf=reobf, srg_names=srg_names, in_jar=in_jar, out_jar=out_jar, keep_lvt=keep_lvt, keep_generics=keep_generics)
        
    # This is our pre-everything hook.
    # We do the following:
    # Verify if astyle is installed/accessible, if not then exit
    # We also compile and run our transformers:
    #   MCPMerge, This merges the runnable code from the server and client creating a single codebase that is complete.
    #   AccessTransformer: 
    #       This changes access levels of classes fields and methods based on a configuration map. 
    #       Allows up to keep out base edits down because we don't have to patch the access levels of everything.
    def transformers_hook(self, side):
        global compile_tools
        if not self.has_wine and not self.has_astyle:
            self.logger.error('!! Please install either wine or astyle for source cleanup !!')
            self.logger.error('!! This is REQUIRED by FML/Forge Cannot proceed !!')
            sys.exit(1)
        jars = {CLIENT: self.jarclient, SERVER: self.jarserver}
        kill_signatures(jars[side])
        
        dir_bin = os.path.join(fml_dir, 'bin')
        if not os.path.isdir(dir_bin):
            os.makedirs(dir_bin)
        
        class_path = os.pathsep.join([f for f in self.cpathclient + [dir_bin] if not f in jars.values()])
        dir_common  = os.path.join(fml_dir, 'common')
        dir_trans   = os.path.join(dir_common, 'cpw/mods/fml/common/asm/transformers'.replace('/', os.sep))
        java        = self.cmdjava.translate(None, '"')
        javac       = self.cmdjavac.translate(None, '"')
        cmd_compile = '"%s" -Xlint:-options -deprecation -g -source 1.6 -target 1.6 -classpath "{classpath}" -sourcepath "{sourcepath}" -d "{outpath}" "{target}"' % javac
        cmd_compile = cmd_compile.format(classpath=class_path, sourcepath=dir_common, outpath=dir_bin, target="{target}")
        
        #Compile AccessTransformer and MCPMerger if we havent already
        # Only needs to happen once, but we don't know if were gunna decompile both client and server so cant do it based off side
        if compile_tools:
            self.logger.info('> Compiling AccessTransformer')
            if not runcmd(cmd_compile.format(target=os.path.join(dir_trans, 'AccessTransformer.java')), commands=self, echo=False):
                sys.exit(1)
                
            self.logger.info('> Compiling MCPMerger')
            if not runcmd(cmd_compile.format(target=os.path.join(dir_trans, 'MCPMerger.java')), commands=self, echo=False):
                sys.exit(1)
                
            compile_tools = False
        
        # Merge the client and server jar, only needs to be run once so only do it on the client
        if side == CLIENT:
            if not disable_merge:
                self.logger.info('> Running MCPMerger')
                forkcmd = ('"%s" -classpath "{classpath}" cpw.mods.fml.common.asm.transformers.MCPMerger "{mergecfg}" "{client}" "{server}"' % java).format(
                    classpath=class_path, mergecfg=os.path.join(fml_dir, 'mcp_merge.cfg'), client=jars[CLIENT], server=jars[sERVER])
                    
                if not runcmd(forkcmd, echo=False, commands=self):
                    sys.exit(1)
            else:
                self.logger.info('> MCPMerge disabled')
        
        apply_ats(fml_dir, mcp_dir, class_path, jars[side], disable_at=disable_at, commands=self)
    
    #Check the original jars not the transformed jars
    def checkjars_shunt(self, side, checkjars_real = Commands.checkjars):
        self.jarclient = self.jarclient + '.backup'
        self.jarserver = self.jarserver + '.backup'
        ret = checkjars_real(self, side)
        self.jarclient = self.jarclient[:-7]
        self.jarserver = self.jarserver[:-7]
        return ret
    
    try:
        pre_decompile(mcp_dir, fml_dir, disable_assets=disable_assets)
        
        os.chdir(mcp_dir)
        Commands.applyrg = applyrg_shunt
        Commands.applyss = applyss_shunt
        Commands.checkjars = checkjars_shunt
        #decompile -d -n -r
        #         Conf  JAD    CSV    -r    -d    -a     -n    -p     -o     -l     -g     -c                 -s              --rg  --workDir --json(None=compute) --nocopy
        decompile(None, False, False, True, True, False, True, False, False, False, False, not disable_client, enable_server, False, os.path.join(mcp_dir,'jars'), None, True)
        reset_logger()
        os.chdir(fml_dir)
        post_decompile(mcp_dir, fml_dir)
        
    except SystemExit, e:
        print 'Decompile Exception: %d ' % e.code
        raise e   

    if not os.path.isdir(src_dir):
        print 'Something went wrong, src folder not found at: %s' % src_dir
        sys.exit(1)
        
    #cleanup_source
    cleanup_source(src_dir)
    
    os.chdir(mcp_dir)
    commands = Commands(verify=True,workdir=os.path.join(mcp_dir,'jars'))
    
    if not disable_client:
        updatemd5_side(mcp_dir, commands, CLIENT)
        reset_logger()
    
    if enable_server:
        updatemd5_side(mcp_dir, commands, CLIENT)
        reset_logger()
    
    os.chdir(fml_dir)

def updatemd5_side(mcp_dir, commands, side):
    sys.path.append(mcp_dir)
    from runtime.mcp import recompile_side, updatemd5_side
    from runtime.commands import SIDE_NAME
    
    recomp = recompile_side(commands, side)
    if recomp:
        commands.logger.info('> Generating %s md5s', SIDE_NAME[side])
        commands.gathermd5s(side, skip_fml=True)

def pre_decompile(mcp_dir, fml_dir, disable_assets=False):
    download_minecraft(mcp_dir, fml_dir)
    
    if not disable_assets:
        download_assets(mcp_dir)

def post_decompile(mcp_dir, fml_dir):
    if False:
        print('hi')

def apply_fml_patches(fml_dir, mcp_dir, src_dir, copy_files=True):
    #Delete /minecraft/cpw to get rid of the Side/SideOnly classes used in decompilation
    cpw_mc_dir = os.path.join(src_dir, 'minecraft', 'cpw')
    if os.path.isdir(cpw_mc_dir):
        shutil.rmtree(cpw_mc_dir)
        
    #patch files
    print('Applying Forge ModLoader patches')
    sys.stdout.flush()

    if os.path.isdir(os.path.join(fml_dir, 'patches', 'minecraft')):
        apply_patches(mcp_dir, os.path.join(fml_dir, 'patches', 'minecraft'), src_dir)
    if copy_files and os.path.isdir(os.path.join(fml_dir, 'client')):
        copytree(os.path.join(fml_dir, 'client'), os.path.join(src_dir, 'minecraft'))
    if copy_files and os.path.isdir(os.path.join(fml_dir, 'common')):
        copytree(os.path.join(fml_dir, 'common'), os.path.join(src_dir, 'minecraft'))

    #delete argo
    if os.path.isdir(os.path.join(src_dir, 'minecraft', 'argo')):
        shutil.rmtree(os.path.join(src_dir, 'minecraft', 'argo'))

def finish_setup_fml(fml_dir, mcp_dir, enable_server=False, disable_client=False, disable_rename=False):
    sys.path.append(mcp_dir)
    from runtime.updatenames import updatenames
    from runtime.updatemd5 import updatemd5
    from runtime.updatemcp import updatemcp
    
    os.chdir(mcp_dir)
    if not disable_rename:
        updatenames(None, True, not disable_client, enable_server)
        reset_logger()
    updatemd5(None, True, not disable_client, enable_server)
    reset_logger()
    os.chdir(fml_dir)
#==========================================================================
#                      Download Functions!
#==========================================================================    
def download_minecraft(mcp_dir, fml_dir, version=None):
    mc_info = read_mc_versions(fml_dir, version=version, work_dir=os.path.join(mcp_dir, 'jars'))

    failed = False
    
    if mc_info['new_launcher']:
        if os.path.isdir(os.path.join(fml_dir, 'jsons')):
            json_file = os.path.join(fml_dir, 'jsons', '%s-dev.json' % mc_info['version'])
        else:
            json_file = os.path.join(fml_dir, 'fml.json')
        
        version_json = None
        try:
            version_json = json.load(open(json_file))
        except Exception as e:
            print 'Failed to load version json: %s' % json_file
            sys.exit(1)
        
        failed = download_libraries(mcp_dir, version_json['libraries'], mc_info['natives_dir']) or failed
        if os.path.isfile(mc_info['json_file']):
            os.remove(mc_info['json_file'])
        shutil.copy(json_file, mc_info['json_file'])
    else:
        failed = not download_list(mc_info['downloads']) or failed
    
    # Remove any invalid files
    for type in ['client', 'server']:
        print("Backing up %s"%type)
        file_backup(mc_info['%s_file' % type], mc_info['%s_md5' % type])
        failed = not download_file(mc_info['%s_url' % type], mc_info['%s_file' % type], mc_info['%s_md5' % type]) or failed
        file_backup(mc_info['%s_file' % type], mc_info['%s_md5' % type])
    
    if failed:
        print 'Something failed verifying minecraft files, see log for details.'
        sys.exit(1)

def download_libraries(mcp_dir, libraries, natives_dir):
    # Will attempt to download a list of maven style libraries from the default Minecraft website
    # or a custom website if the library specifies it
    # This list should be in the format of the new launcher's version.json file
    # Under the entry 'libraries'
    lib_dir = os.path.join(mcp_dir, 'jars', 'libraries')
    default_url = 'https://libraries.minecraft.net'
    
    downloads = []
    failed = False
    
    for lib in libraries:
        name = lib['name'].split(':')
        domain  = name[0].split('.')
        root    = name[1]
        version = name[2]
        path = domain + [root, version]
        extract = None
        root_url = default_url
        if 'extract' in lib.keys():
            extract = lib['extract']
        if 'url' in lib.keys():
            root_url = lib['url']
        
        file_names = ['%s-%s.jar' % (root, version)]
        
        if 'natives' in lib.keys():
            file_names = []
            for k,v in lib['natives'].items():
                file_names.append('%s-%s-%s.jar' % (root, version, v))
                
        if 'children' in lib.keys():
            for child in lib['children']:
                file_names.append('%s-%s-%s.jar' % (root, version, child))
                
        for file_name in file_names:
            url = '%s/%s/%s' % (root_url, '/'.join(path), file_name)
            file_path = os.path.join(lib_dir, os.sep.join(path), file_name)
            headers = get_headers(url)
            if headers is None:
                print('Could not retreive headers for library: %s ( %s )' % (lib['name'], url))
                failed = True
            else:
                hash = None
                if hash is None: # Could be a mojang repo, try sha
                    try:
                        hash = urllib2.urlopen(url + '.sha1').read().split(' ')[0].replace('\r', '').replace('\n', '')
                        if not len(hash) == 40:
                            hash = None
                            print('Could not retrieve sha1 for library %s ( %s.sha1 )' % (file_name, url))
                            failed = True
                    except (HTTPError):
                        failed = True
                        pass
                if hash is None: # Could be a normal maven repo, check for .md5 file
                    try:
                        hash = urllib2.urlopen(url + '.md5').read().split(' ')[0].replace('\r', '').replace('\n', '')
                        if not len(hash) == 32:
                            hash = None
                            print('Could not retrieve md5 for library %s ( %s.md5 )' % (file_name, url))
                            failed = True
                    except (HTTPError):
                        failed = True
                        pass
                downloads.append({
                    'url' : url,
                    'file' : file_path,
                    'md5'  : hash,
                    'size' : headers['Content-Length'],
                    'extract' : extract
                })
    
    return download_list(downloads, natives_dir) or failed
    
def download_list(list, natives_dir):
    #Downloads a list of files and urls. Verifying md5s if avalible. 
    #Skipping already existing and valid files.
    #Also extracts files that are specified to be extracted to the natives folder
    missing = []
    for dl in list:
        if os.path.isfile(dl['file']):
            if dl['md5'] is None or not get_md5(dl['file']) == dl['md5']:
                missing.append(dl)
        else:
            missing.append(dl)
            
    if len(missing) == 0:
        return False
        
    print 'Downloading %s libraries' % len(missing)
    failed = False
    for dl in missing:
        if download_file(dl['url'], dl['file'], dl['md5'], prefix='    '):
            if not dl['extract'] is None:
                excludes = []
                if 'exclude' in dl['extract'].keys():
                    excludes = dl['extract']['exclude']
                extract_zip(dl['file'], natives_dir, prefix='        ', filter=excludes)
        else:
            print('    Failed to download %s from %s' % (os.path.basename(dl['file']), dl['url']))
            failed = True
        
    return failed

def download_assets(mcp_dir):
    from json import loads
    asset_dir = os.path.join(mcp_dir, 'jars', 'assets')
    base_url = 'http://resources.download.minecraft.net'
    
    print('Gathering assets list from %s' % base_url)
    
    files = []
    failed = False
    
    try:
        url = urllib.urlopen('https://s3.amazonaws.com/Minecraft.Download/indexes/legacy.json').read()
        json = loads(url)
        
        for name, info in json['objects'].items():
            file = os.path.join(asset_dir, os.sep.join(name.split('/')))
            sha1 = info['hash']
            
            if os.path.isfile(file):
                if get_sha1(file) == sha1:
                    continue
                
            files.append({
                'file' : file,
                'url'  : '%s/%s/%s' % (base_url, sha1[0:2], sha1),
                'size' : info['size'],
                'md5'  : sha1
            })
    except Exception as e:
        print 'Error gathering asset list:'
        pprint(e)
        sys.exit(1)
    
    if len(files) == 0:
        print('    No new assets need to download')
        return
        
    print('    Downloading %s assets' % len(files))
    for file in files:
        failed = not download_file(file['url'], file['file'], file['md5'], root=asset_dir, prefix='        ') or failed
    
    if failed:
        print('    Downloading assets failed, please review log for more details')
    
#==========================================================================
#                            Transformers
#==========================================================================
def apply_ats(fml_dir, mcp_dir, class_path, target, disable_at=False, commands=None):
    def log(msg):
        if commands is None:
            print(msg)
        else:
            commands.logger.info(msg)
            
    cmds = find_java()
    if cmds is None:
        log('>Could not run Access Transformer, Java not found!')
        sys.exit(1)
        
    if not disable_at:
        log('> Running AccessTransformer')
        forkcmd = ('"%s" -classpath "{classpath}" cpw.mods.fml.common.asm.transformers.AccessTransformer "{jar}" "{fmlconfig}"' % cmds['java']).format(
            classpath=class_path, jar=target, fmlconfig=os.path.join(fml_dir, 'common', 'fml_at.cfg'))
            
        forge_cfg = os.path.join(fml_dir, '..', 'common', 'forge_at.cfg')
        if os.path.isfile(forge_cfg):
            log('    Forge config detected')
            forkcmd += ' "%s"' % forge_cfg

        for dirname, dirnames, filenames in os.walk(os.path.join(fml_dir, '..', 'accesstransformers')):
            for filename in filenames:
                accesstransformer = os.path.join(dirname, filename)
                if os.path.isfile(accesstransformer):              
                    log('    Access Transformer "%s" detected' % filename)
                    forkcmd += ' "%s"' % accesstransformer
        
        if not runcmd(forkcmd, echo=False, commands=commands):
            sys.exit(1)
    else:
        log('> Access Transformer disabled')

 

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

Code from

BlockFurnace

that should be of interest for you:

    /**
     * Called whenever the block is added into the world. Args: world, x, y, z
     */
    public void onBlockAdded(World par1World, int par2, int par3, int par4)
    {
        super.onBlockAdded(par1World, par2, par3, par4);
        this.setDefaultDirection(par1World, par2, par3, par4);
    }

    /**
     * set a blocks direction
     */
    private void setDefaultDirection(World par1World, int par2, int par3, int par4)
    {
        if (!par1World.isRemote)
        {
            int l = par1World.getBlockId(par2, par3, par4 - 1);
            int i1 = par1World.getBlockId(par2, par3, par4 + 1);
            int j1 = par1World.getBlockId(par2 - 1, par3, par4);
            int k1 = par1World.getBlockId(par2 + 1, par3, par4);
            byte b0 = 3;

            if (Block.opaqueCubeLookup[l] && !Block.opaqueCubeLookup[i1])
            {
                b0 = 3;
            }

            if (Block.opaqueCubeLookup[i1] && !Block.opaqueCubeLookup[l])
            {
                b0 = 2;
            }

            if (Block.opaqueCubeLookup[j1] && !Block.opaqueCubeLookup[k1])
            {
                b0 = 5;
            }

            if (Block.opaqueCubeLookup[k1] && !Block.opaqueCubeLookup[j1])
            {
                b0 = 4;
            }

            par1World.setBlockMetadataWithNotify(par2, par3, par4, b0, 2);
        }
    }

    /**
     * Called when the block is placed in the world.
     */
    public void onBlockPlacedBy(World par1World, int par2, int par3, int par4, EntityLivingBase par5EntityLivingBase, ItemStack par6ItemStack)
    {
        int l = MathHelper.floor_double((double)(par5EntityLivingBase.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3;

        if (l == 0)
        {
            par1World.setBlockMetadataWithNotify(par2, par3, par4, 2, 2);
        }

        if (l == 1)
        {
            par1World.setBlockMetadataWithNotify(par2, par3, par4, 5, 2);
        }

        if (l == 2)
        {
            par1World.setBlockMetadataWithNotify(par2, par3, par4, 3, 2);
        }

        if (l == 3)
        {
            par1World.setBlockMetadataWithNotify(par2, par3, par4, 4, 2);
        }

        if (par6ItemStack.hasDisplayName())
        {
            ((TileEntityFurnace)par1World.getBlockTileEntity(par2, par3, par4)).setGuiDisplayName(par6ItemStack.getDisplayName());
        }
    }

 

EDIT: I noticed that you're asking about 1.5.2; I'll look into it ASAP.

EDIT 2: 1.5.2 won't decompile for me...

 

So, it decompiled? Can you help me?

Link to comment
Share on other sites

Since Forge 1.5.2 wouldn't work, I had to use MCP. The code in

BlockFurnace

that relates to your problem is pretty much the same in 1.6.4, but try putting this code in your block class:

    /**
     * Called whenever the block is added into the world. Args: world, x, y, z
     */
    public void onBlockAdded(World par1World, int par2, int par3, int par4)
    {
        super.onBlockAdded(par1World, par2, par3, par4);
        this.setDefaultDirection(par1World, par2, par3, par4);
    }

    /**
     * set a blocks direction
     */
    private void setDefaultDirection(World par1World, int par2, int par3, int par4)
    {
        if (!par1World.isRemote)
        {
            int var5 = par1World.getBlockId(par2, par3, par4 - 1);
            int var6 = par1World.getBlockId(par2, par3, par4 + 1);
            int var7 = par1World.getBlockId(par2 - 1, par3, par4);
            int var8 = par1World.getBlockId(par2 + 1, par3, par4);
            byte var9 = 3;

            if (Block.opaqueCubeLookup[var5] && !Block.opaqueCubeLookup[var6])
            {
                var9 = 3;
            }

            if (Block.opaqueCubeLookup[var6] && !Block.opaqueCubeLookup[var5])
            {
                var9 = 2;
            }

            if (Block.opaqueCubeLookup[var7] && !Block.opaqueCubeLookup[var8])
            {
                var9 = 5;
            }

            if (Block.opaqueCubeLookup[var8] && !Block.opaqueCubeLookup[var7])
            {
                var9 = 4;
            }

            par1World.setBlockMetadataWithNotify(par2, par3, par4, var9, 2);
        }
    }

    /**
     * Called when the block is placed in the world.
     */
    public void onBlockPlacedBy(World par1World, int par2, int par3, int par4, EntityLiving par5EntityLiving, ItemStack par6ItemStack)
    {
        int var7 = MathHelper.floor_double((double)(par5EntityLiving.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3;

        if (var7 == 0)
        {
            par1World.setBlockMetadataWithNotify(par2, par3, par4, 2, 2);
        }

        if (var7 == 1)
        {
            par1World.setBlockMetadataWithNotify(par2, par3, par4, 5, 2);
        }

        if (var7 == 2)
        {
            par1World.setBlockMetadataWithNotify(par2, par3, par4, 3, 2);
        }

        if (var7 == 3)
        {
            par1World.setBlockMetadataWithNotify(par2, par3, par4, 4, 2);
        }
    }

Before you even think about modding,

Link to comment
Share on other sites

Since Forge 1.5.2 wouldn't work, I had to use MCP. The code in

BlockFurnace

that relates to your problem is pretty much the same in 1.6.4, but try putting this code in your block class:

    /**
     * Called whenever the block is added into the world. Args: world, x, y, z
     */
    public void onBlockAdded(World par1World, int par2, int par3, int par4)
    {
        super.onBlockAdded(par1World, par2, par3, par4);
        this.setDefaultDirection(par1World, par2, par3, par4);
    }

    /**
     * set a blocks direction
     */
    private void setDefaultDirection(World par1World, int par2, int par3, int par4)
    {
        if (!par1World.isRemote)
        {
            int var5 = par1World.getBlockId(par2, par3, par4 - 1);
            int var6 = par1World.getBlockId(par2, par3, par4 + 1);
            int var7 = par1World.getBlockId(par2 - 1, par3, par4);
            int var8 = par1World.getBlockId(par2 + 1, par3, par4);
            byte var9 = 3;

            if (Block.opaqueCubeLookup[var5] && !Block.opaqueCubeLookup[var6])
            {
                var9 = 3;
            }

            if (Block.opaqueCubeLookup[var6] && !Block.opaqueCubeLookup[var5])
            {
                var9 = 2;
            }

            if (Block.opaqueCubeLookup[var7] && !Block.opaqueCubeLookup[var8])
            {
                var9 = 5;
            }

            if (Block.opaqueCubeLookup[var8] && !Block.opaqueCubeLookup[var7])
            {
                var9 = 4;
            }

            par1World.setBlockMetadataWithNotify(par2, par3, par4, var9, 2);
        }
    }

    /**
     * Called when the block is placed in the world.
     */
    public void onBlockPlacedBy(World par1World, int par2, int par3, int par4, EntityLiving par5EntityLiving, ItemStack par6ItemStack)
    {
        int var7 = MathHelper.floor_double((double)(par5EntityLiving.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3;

        if (var7 == 0)
        {
            par1World.setBlockMetadataWithNotify(par2, par3, par4, 2, 2);
        }

        if (var7 == 1)
        {
            par1World.setBlockMetadataWithNotify(par2, par3, par4, 5, 2);
        }

        if (var7 == 2)
        {
            par1World.setBlockMetadataWithNotify(par2, par3, par4, 3, 2);
        }

        if (var7 == 3)
        {
            par1World.setBlockMetadataWithNotify(par2, par3, par4, 4, 2);
        }
    }

 

Nope. Still spawning in one direction.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.