Very early version.
Take a look, have a play, break it as much as you can.
SSME intends to provide a semi-secure framework for run-time modification of Starsector's bytecode, thereby allowing far greater customization of the game's functionality.
Familiarity with Java bytecode, and run-time instrumentation libraries is strongly recommended.
Installation & Launching.
1) Extract both SSME (
HERE), and the Example Mod (
HERE), to your mods folder. (all sourcecode is included)
2) launch Starsector via your platform's SSME launch script located in the SSME mod folder.
Note. mac & *nix launch scripts are completely untested; if they don't work, pls let me know xxx)
(The launch scripts are just adaptations of Starsector's default scripts, with a few modifications:
- SSME added to the classpath
- libraries added to the classpath
- "java.system.class.loader" property added.- now using -javaagent instead.- Now using BOTH java.system.class.loader AND -javaagent. Compartmentalizing SSME code & Starsector code into separate class loaders prevents instrumentation malfunctions (transformers transforming their own code libraries)
- entry class changed from StarfarerLauncher to StarsectorModExpander (SSME's main class)
Quick overview:
- Mods that require SSME functionality should include an "ssme.json" in the root of their mod folder.
- "ssme.json" contains a list of jars to append to the classpath, and the name of a classTransformer contained within. (A class that implements the interface org.tjj.starsector.ssme.ClassTransformer, and will be instantiated by SSME.)
- Prior to the execution of any unsafe code, the user is prompted to give authorization to each Mod that desires it.
- SSME makes a few tweaks to the Starsector launcher, to add a UI for modifying previously granted/refused authorizations
- Class transformation occurs in 2 stages.
- Early transformation. ( ClassTransformer#doEarlyTransformations(ClassProvider) )
This occurs before any of Starsector's core code is loaded. Each Mod's ClassTransformer is given the opportunity to apply bytecode modifications to any of the game's classes it can explicitly name. - Late transformation. ( ClassTransformer#doLateTransformation(String,byte[]) )
This occurs immediately before a class is loaded. Each Mod's ClassTransformer is given a chance to modify the bytecode of the class being loaded. This is useful if you want to apply a transformation to every class in the game, or to classes for which you have no name. (either because of obfuscation, or because it's script code of other mods) - For convenience, SSME includes 3 bytecode instrumentation libraries. Javassist (which is what SSME itself uses), ASM (low level library), and Byte Buddy (not done much with this API, but it looks really good!)
- SSME offers some (and will offer more) utility methods for aiding in bytecode manipulation.
- The Example Mod is a demonstration of the simplicity of the process. It intercepts the loading of ship_data.csv & applies a modification to each JSONObject before passing it back to the game code. (inspired by this thread)
Guidance when designing your instrumentation:
- Don't attempt to write instrumentation without having a debugger attached to the VM; you'll be wasting your time
- Never rely upon obfuscated names; they will almost certainly change between releases. Identify methods via attributes other than their name (see Utils.findDeclaredMethods(CtClass, MethodPrototype)
- Make your instrumentation code fail-fast! While many instrumentation mods will work flawlessly between Starsector patches, when they do fail, for your own sanity you want them to fail as early & as verbosely as possible.
Make sure you don't instrument your own instrumentation classes! (while redirecting Random.methods() to my own implementations, I instrumented the target class too, resulting in an infinite loop! ). Improved the API so this is now impossible- Don't forget that the constructors for anonymous classes take hidden parameters (their containing class, plus any 'final' local variables that they access)
- erm..... stuff that I'll discover while I write SSMF (Starsector Multifarer)
Known Issues:
When ASM is set to COMPUTE_MAXS | COMPUTE_FRAMES on classes that it touches, it generates an invalid class file for the obfuscated class
sound/OooOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
This is either a bug in ASM (making class file format assumptions it shouldn't be), or a bug in the obfuscator Alex is using (generating a class that is technically outside the class file format specification).
Either way, it should be fixable with a patch to ASM - but I won't bother until it becomes an blocking issue that needs to be solved.
Little diagram explaining where class loading responsibility lies, and what code SSME can touch: