diff --git a/build/.gitignore b/build/.gitignore new file mode 100644 index 00000000..0705049e --- /dev/null +++ b/build/.gitignore @@ -0,0 +1,3 @@ +libpandadna/ +built/ +*.pdb diff --git a/build/base.dg b/build/base.dg new file mode 100644 index 00000000..8157b37c Binary files /dev/null and b/build/base.dg differ diff --git a/build/data/NiraiStart.py b/build/data/NiraiStart.py new file mode 100644 index 00000000..b8d89099 --- /dev/null +++ b/build/data/NiraiStart.py @@ -0,0 +1,76 @@ +from panda3d.core import * +import __builtin__, os +import rc4 + +import niraidata + +# Config +prc = niraidata.CONFIG +key, prc = prc[:32], prc[32:] +rc4.rc4_setkey(key) +prc = rc4.rc4(prc) + +for line in prc.split('\n'): + line = line.strip() + if line: + loadPrcFileData('nirai config', line) + +del prc + +# DC +__builtin__.dcStream = StringStream() + +dc = niraidata.DC +key, dc = dc[:32], dc[32:] +rc4.rc4_setkey(key) +dc = rc4.rc4(dc) + +dcStream.setData(dc) +del dc +rc4.rc4_setkey('\0\0\0\0') + +# Resources +# TO DO: sign and verify the phases to prevent edition + +vfs = VirtualFileSystem.getGlobalPtr() +mfs = (3, 3.5, 4, 5, 5.5, 6, 7, 8, 9, 10, 11, 12, 13) +abort = False + +for mf in mfs: + filename = 'resources/default/phase_%s.mf' % mf + if not os.path.isfile(filename): + print 'Phase %s not found' % filename + abort = True + break + + mf = Multifile() + mf.openRead(filename) + + if not vfs.mount(mf, '../resources', 0): + print 'Unable to mount %s' % filename + abort = True + break + +# Packs +pack = os.environ.get('TT_STRIDE_CONTENT_PACK') +if pack and pack != 'default': + print 'Loading content pack', pack + for file in glob.glob('resources/%s/*.mf' % pack): + mf = Multifile() + mf.openReadWrite(Filename(file)) + names = mf.getSubfileNames() + for name in names: + ext = os.path.splitext(name)[1] + if ext not in ('.jpg', '.jpeg', '.ogg', '.rgb'): + mf.removeSubfile(name) + + mf.flush() + + if not vfs.mount(mf, '../resources', 0): + print 'Unable to mount %s' % filename + abort = True + break + +if not abort: + # Run + import toontown.toonbase.ClientStart diff --git a/build/make.py b/build/make.py new file mode 100644 index 00000000..92291b53 --- /dev/null +++ b/build/make.py @@ -0,0 +1,199 @@ +from panda3d.core import * + +import argparse, marshal, struct +import glob, sys, os +import rc4 + +parser = argparse.ArgumentParser() +parser.add_argument('--compile-cxx', '-c', action='store_true', + help='Compile the CXX codes and generate Nirai.exe into built.') +parser.add_argument('--make-nri', '-n', action='store_true', + help='Generate stride NRI.') +args = parser.parse_args() + +# BEGIN (STRIPPED AND MODIFIED) COPY FROM niraitools.py +class NiraiPackager: + HEADER = 'NRI\n' + + def __init__(self, outfile): + self.modules = {} + self.outfile = outfile + + def __read_file(self, filename, mangler=None): + with open(filename, 'rb') as f: + data = f.read() + + base = filename.rsplit('.', 1)[0].replace('\\', '/').replace('/', '.') + pkg = base.endswith('.__init__') + moduleName = base.rsplit('.', 1)[0] if pkg else base + + name = moduleName + if mangler is not None: + name = mangler(name) + + if not name: + return '', ('', 0) + + try: + data = self.compile_module(name, data) + + except: + print 'WARNING: Failed to compile', filename + return '', ('', 0) + + size = len(data) * (-1 if pkg else 1) + return name, (data, size) + + def compile_module(self, name, data): + return marshal.dumps(compile(data, name, 'exec')) + + def add_module(self, moduleName, data, size=None, compile=False): + if compile: + data = self.compile_module(moduleName, data) + + if size is None: + size = len(data) + + self.modules[moduleName] = (data, size) + + def add_file(self, filename, mangler=None): + print 'Adding file', filename + moduleName, (data, size) = self.__read_file(filename, mangler) + if moduleName: + moduleName = os.path.basename(filename).rsplit('.', 1)[0] + self.add_module(moduleName, data, size) + + def add_directory(self, dir, mangler=None): + print 'Adding directory', dir + + def _recurse_dir(dir): + for f in os.listdir(dir): + f = os.path.join(dir, f) + + if os.path.isdir(f): + _recurse_dir(f) + + elif f.endswith('py'): + moduleName, (data, size) = self.__read_file(f, mangler) + if moduleName: + self.add_module(moduleName, data, size) + + _recurse_dir(dir) + + def get_mangle_base(self, *path): + return len(os.path.join(*path).rsplit('.', 1)[0].replace('\\', '/').replace('/', '.')) + 1 + + def write_out(self): + f = open(self.outfile, 'wb') + f.write(self.HEADER) + f.write(self.process_modules()) + f.close() + + def generate_key(self, size=256): + return os.urandom(size) + + def dump_key(self, key): + for k in key: + print ord(k), + + print + + def process_modules(self): + # Pure virtual + raise NotImplementedError('process_datagram') + + def get_file_contents(self, filename, keysize=0): + with open(filename, 'rb') as f: + data = f.read() + + if keysize: + key = self.generate_key(keysize) + rc4.rc4_setkey(key) + data = key + rc4.rc4(data) + + return data +# END COPY FROM niraitools.py + +class StridePackager(NiraiPackager): + HEADER = 'STRIDETT' + BASEDIR = '..' + os.sep + + def __init__(self, outfile): + NiraiPackager.__init__(self, outfile) + self.__manglebase = self.get_mangle_base(self.BASEDIR) + + def add_source_dir(self, dir): + self.add_directory(self.BASEDIR + dir, mangler=self.__mangler) + + def add_data_file(self, file): + mb = self.get_mangle_base('data/') + self.add_file('data/%s.py' % file, mangler=lambda x: x[mb:]) + + def __mangler(self, name): + if name.endswith('AI') or name.endswith('UD') or name in ('ToontownAIRepository', 'ToontownUberRepository', + 'ToontownInternalRepository'): + if not 'NonRepeatableRandomSource' in name: + return '' + + return name[self.__manglebase:].strip('.') + + def generate_niraidata(self): + print 'Generating niraidata' + + config = self.get_file_contents('../dependencies/config/release/en.prc') + config += '\n\n' + self.get_file_contents('../dependencies/config/general.prc') + key = self.generate_key(128) + rc4.rc4_setkey(key) + config = key + rc4.rc4(config) + + niraidata = 'CONFIG = %r' % config + niraidata += '\nDC = %r' % self.get_file_contents('../dependencies/astron/dclass/stride.dc', 128) + self.add_module('niraidata', niraidata, compile=True) + + def process_modules(self): + with open('base.dg', 'rb') as f: + basesize, = struct.unpack(' +#include +#include + +string rc4(const char* data, const char* key, int ds, int ks); + +extern "C" __declspec(dllexport) void initlibpandadna(); +void init_libpandadna(); + +const char* header = "STRIDETT"; +const int header_size = 8; + +const int keysize = 100; +const int fixedsize = 28; + +int niraicall_onPreStart(int argc, char* argv[]) +{ + return 0; +} + +int niraicall_onLoadGameData() +{ + fstream gd; + + // Open the file + gd.open("stride.dist", ios_base::in | ios_base::binary); + if (!gd.is_open()) + { + std::cerr << "unable to open game file" << std::endl; + return 1; + } + + // Check the header + char* read_header = new char[header_size]; + gd.read(read_header, header_size); + + if (memcmp(header, read_header, header_size)) + { + std::cerr << "invalid header" << std::endl; + return 1; + } + + delete[] read_header; + + // Extract the key + char* key = new char[keysize + fixedsize]; + char* fixed = new char[keysize]; + + for (int i = 0; i < fixedsize; ++i) + fixed[i] = (i ^ (5 * i + 7)) % ((i + 6) * 10); + + gd.read(key, keysize); + memcpy(&key[keysize], fixed, fixedsize); + + std::stringstream ss; + ss << gd.rdbuf(); + gd.close(); + + // Decrypt + std::string rawdata = ss.str(); + std::string decrypted_data = rc4(rawdata.c_str(), key, rawdata.size(), + keysize + fixedsize); + delete[] key; + delete[] fixed; + + // Decompress and read + std::string decompressed = decompress_string(decrypted_data); + + Datagram dg(decompressed); + DatagramIterator dgi(dg); + + unsigned int num_modules = dgi.get_uint32(); + _frozen* fzns = new _frozen[num_modules + 1]; + std::string module, data; + int size; + + for (unsigned int i = 0; i < num_modules; ++i) + { + module = dgi.get_string(); + size = dgi.get_int32(); + data = dgi.extract_bytes(abs(size)); + + char* name = new char[module.size() + 1]; + memcpy(name, module.c_str(), module.size()); + memset(&name[module.size()], 0, 1); + + unsigned char* code = new unsigned char[data.size()]; + memcpy(code, data.c_str(), data.size()); + + _frozen fz; + fz.name = name; + fz.code = code; + fz.size = size; + + memcpy(&fzns[i], &fz, sizeof(_frozen)); + } + + nassertd(dgi.get_remaining_size() == 0) + { + std::cerr << "corrupted data" << std::endl; + return 1; + } + + memset(&fzns[num_modules], 0, sizeof(_frozen)); + PyImport_FrozenModules = fzns; + + // libpandadna + init_libpandadna(); + initlibpandadna(); + + return 0; +}