Fully working code + class loader.
How to use:
1) This is my special CharacterCreationPluginImpl that does not do anything by itself, merely loading other classes into game.
Entire mechanism based of reflections, it does not need links to other classes and will load anyway, ever if classes not present at moment of compilation.
It still WIP, still use java.io and still not cleaned up.
Unlikely to work with janino, soo you must jar your mod in order to use this feature.
Spoiler
package data.scripts.plugins;
import com.fs.starfarer.api.campaign.CargoAPI.CrewXPLevel;
import com.fs.starfarer.api.characters.CharacterCreationPlugin;
import com.fs.starfarer.api.characters.MutableCharacterStatsAPI;
import data.scripts.world.RawCodeGen;
import data.usc.uscData;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import org.apache.log4j.Logger;
public class CharacterCreationPluginImpl implements CharacterCreationPlugin {
@Deprecated
Logger fun = Logger.getLogger(this.getClass());
Logger log = fun;
// externals block
@SuppressWarnings("rawtypes")
public static List _getResponses = null;
public static List _AvailableImps = new ArrayList();
public static int _stage = 0;
public static //
HashMap<String,ResponseImpl> _ResponsePool = new HashMap<String,ResponseImpl>();
public static String[] _Prompts = new String[8];
public static Response _Response = null;
public static CharacterCreationData _Data = null;
public static String _HullID = "";
public static boolean _FIRSTRUN = true;
public String getPrompt() {
if (_FIRSTRUN){
_FIRSTRUN = false;
EBUS_discover();
EBUS_execute("getPrompt");
}
if (_stage < _Prompts.length) {
return _Prompts[_stage];
}
return null;
}
public static class ResponseImpl implements Response {
private String text;
public ResponseImpl(String text) {
this.text = text;
}
public String getText() {
return text;
}
}
/*
public void eventbussurrogate1() throws Exception{
Class test = Class.forName("data.scripts.plugins.CharacterCreationPluginImpl_1");
Method inv = test.getMethod("main", null);
Method tt = test.getMethod("getResponses", null);
inv.invoke(null, null);
tt.invoke(null, null);
}
public void eventbussurrogate() throws Exception{
Class<?> test = Class.forName("data.scripts.plugins.CharacterCreationPluginImpl_0");
Method inv = test.getDeclaredMethod("main", null);
Method tt = test.getDeclaredMethod("getResponses", null);
fun.info("sur 1");
inv.invoke(null, null);
tt.invoke(null, null);
fun.info("sur 2");
}*/
public void EBUS_discover(){
String Base = "data.scripts.plugins.CharacterCreationPluginImpl_";
for(int i=0; i<31; i++){
try
{
Class<?> test = Class.forName("data.scripts.plugins.CharacterCreationPluginImpl_" + i);
test.getDeclaredMethod("init", null).invoke(null, null);
_AvailableImps.add(test);
log.info(test.getName() + " initialized.");
} catch (Exception e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
sw.toString();
//fun.info(sw.toString()+ "FFFF");
}
}
log.info(_AvailableImps.size() + " size of loaded array");
}
public void EBUS_execute(String S)
{
Iterator<Object> it = _AvailableImps.iterator();
while(it.hasNext())
{
try {
((Class) it.next()).getDeclaredMethod(S, null).invoke(null, null);
} catch (Exception e){}
}
}
public List getResponses() {
_getResponses = new ArrayList();
EBUS_execute("getResponses");
/*
fun.info("TEST 1");
try {
fun.info("TEST 2");
eventbussurrogate();
fun.info("TEST 3");
} catch (Exception e) {
fun.info("TEST 4");
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
sw.toString();
fun.info(sw.toString()+ "FFFF");
fun.info("TEST 5");
}
try {
eventbussurrogate1();
} catch (Exception e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
sw.toString();
fun.info(sw.toString()+ "FFFF");
}
fun.info("SIZE OF ARRAY OUTSIDE " + _getResponses.size());
*/
return _getResponses;
}
public void submit(Response response, CharacterCreationData data) {
_Response = response;
_Data = data;
_stage++;
EBUS_execute("submit");
}
public void startingShipPicked(String variantId, CharacterCreationData data) {
_Data = data;
_HullID = variantId;
EBUS_execute("startingShipPicked");
}
}
2) this is sample loader, 99% vanilla (4 lines missing about basic hull).
Spoiler
package data.scripts.plugins;
import com.fs.starfarer.api.campaign.CargoAPI.CrewXPLevel;
import com.fs.starfarer.api.characters.CharacterCreationPlugin;
import com.fs.starfarer.api.characters.CharacterCreationPlugin.CharacterCreationData;
import com.fs.starfarer.api.characters.CharacterCreationPlugin.Response;
import com.fs.starfarer.api.characters.MutableCharacterStatsAPI;
import com.fs.starfarer.api.fleet.FleetMemberAPI;
import data.scripts.plugins.CharacterCreationPluginImpl.ResponseImpl;
import data.usc.uscData;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.apache.log4j.Logger;
public class CharacterCreationPluginImpl_0 {
static Logger fun = Logger.getLogger("INVOKE");
public static void Responce_put(String Tag,String Info){
CharacterCreationPluginImpl._ResponsePool.put(Tag, new ResponseImpl(Info));
}
public static void Responce_rem(String Tag){
CharacterCreationPluginImpl._ResponsePool.remove(Tag);
}
@SuppressWarnings("unchecked")
public static void addResponse(String Tag)
{
CharacterCreationPluginImpl._getResponses.
add(CharacterCreationPluginImpl._ResponsePool.get(Tag));
}
public static Response Responce_get(String Tag){
return CharacterCreationPluginImpl._ResponsePool.get(Tag);
}
@SuppressWarnings("unused")
public static void init()
{
fun.info("INITIALIZATION");
Responce_put("SUPPLY_OFFICER" , "Served as a junior supply officer in an independent system's navy");
Responce_put("GUNNER" , "Hired out as a gunner on a mercenary ship");
Responce_put("ENGINEER" , "Found employment as an assistant engineer on an exploration vessel");
Responce_put("COPILOT" , "Spent time as a co-pilot on a patrol ship in an independent system");
Responce_put("SOMETHING_ELSE_1" , "Did something else");
Responce_put("ADJUTANT" , "Served as an adjutant in the Hegemony Navy");
Responce_put("QUARTERMASTER" , "Performed the duties of a quartermaster on an independent warship");
Responce_put("HELM" , "Helmed a patrol ship operating in a backwater system");
Responce_put("COMBAT_ENGINEER" , "Took over the duties of chief combat engineer during a lengthy campaign");
Responce_put("SOMETHING_ELSE_2" , "Did something else");
}
static int Capacity = 0;
static String[] tmps;
public static void setPrompt(String Tag, int Position)
{
if (Position > tmps.length)
{
String[] old = tmps.clone();
tmps = new String[Position];
for (int i = 0; i < old.length; i++)
{
tmps[i] = old[i];
}
}
tmps[Position] = Tag;
}
public static void getPrompt() {
tmps = CharacterCreationPluginImpl._Prompts;
setPrompt("Early in your career, you...",0);
setPrompt("More recently, you...",1);
CharacterCreationPluginImpl._Prompts = tmps;
}
public static void getResponses(){
fun.info("getResponses Called");
switch (CharacterCreationPluginImpl._stage)
{
case 0:
{
fun.info("case 0 Called");
addResponse("SUPPLY_OFFICER");
addResponse("GUNNER");
addResponse("ENGINEER");
addResponse("COPILOT");
addResponse("SOMETHING_ELSE_1");
break;
}
case 1:
{
fun.info("case 1 Called");
addResponse("ADJUTANT");
addResponse("QUARTERMASTER");
addResponse("HELM");
addResponse("COMBAT_ENGINEER");
addResponse("SOMETHING_ELSE_2");
break;}
default: {return;}}
}
public static void submit() {
int _stage = CharacterCreationPluginImpl._stage;
Response _Response = CharacterCreationPluginImpl._Response;
CharacterCreationData _Data = CharacterCreationPluginImpl._Data;
if (_stage == 0) { // just in case
_Data.addStartingShipChoice("shuttle_Attack");
}
MutableCharacterStatsAPI stats = _Data.getPerson().getStats();
if (_Response == Responce_get("SUPPLY_OFFICER")) {
stats.increaseAptitude("leadership");
stats.increaseSkill("fleet_logistics");
stats.increaseSkill("command_experience");
_Data.getStartingCargo().getCredits().add(3000f);
} else if (_Response == Responce_get("GUNNER")) {
stats.increaseAptitude("combat");
stats.increaseSkill("ordnance_expert");
stats.increaseSkill("target_analysis");
_Data.getStartingCargo().getCredits().add(3000f);
} else if (_Response == Responce_get("ENGINEER")) {
stats.increaseAptitude("technology");
stats.increaseSkill("field_repairs");
stats.increaseSkill("mechanical_engineering");
_Data.getStartingCargo().getCredits().add(3000f);
} else if (_Response == Responce_get("COPILOT")) {
stats.increaseAptitude("combat");
stats.increaseSkill("helmsmanship");
stats.increaseSkill("evasive_action");
_Data.getStartingCargo().getCredits().add(3000f);
} else if (_Response == Responce_get("SOMETHING_ELSE_1")) {
stats.addAptitudePoints(1);
stats.addSkillPoints(2);
_Data.getStartingCargo().getCredits().add(1000f);
}
else if (_Response == Responce_get("ADJUTANT")) {
stats.increaseAptitude("leadership");
stats.increaseSkill("fleet_logistics");
stats.increaseSkill("advanced_tactics");
_Data.addStartingShipChoice("lasher_Standard");
_Data.getStartingCargo().getCredits().add(3000f);
} else if (_Response == Responce_get("QUARTERMASTER")) {
stats.increaseAptitude("technology");
stats.increaseSkill("navigation");
stats.addSkillPoints(1);
_Data.addStartingShipChoice("wolf_CS");
_Data.getStartingCargo().getCredits().add(3000f);
} else if (_Response == Responce_get("HELM")) {
stats.increaseAptitude("combat");
stats.increaseSkill("helmsmanship");
stats.increaseSkill("evasive_action");
_Data.addStartingShipChoice("vigilance_Standard");
_Data.getStartingCargo().getCredits().add(3000f);
} else if (_Response == Responce_get("COMBAT_ENGINEER")) {
stats.increaseAptitude("combat");
stats.increaseSkill("damage_control");
stats.increaseSkill("flux_modulation");
_Data.addStartingShipChoice("lasher_Standard");
_Data.getStartingCargo().getCredits().add(3000f);
} else if (_Response == Responce_get("SOMETHING_ELSE_2")) {
stats.addAptitudePoints(1);
stats.addSkillPoints(2);
_Data.addStartingShipChoice("hound_Assault");
_Data.getStartingCargo().getCredits().add(1000f);
}
}
public static void startingShipPicked() {
CharacterCreationData data = CharacterCreationPluginImpl._Data;
String variantId = CharacterCreationPluginImpl._HullID;
MutableCharacterStatsAPI stats = data.getPerson().getStats();
stats.addAptitudePoints(1);
stats.addSkillPoints(2);
if (variantId.equals("vigilance_Standard")) {
data.getStartingCargo().addFuel(20);
data.getStartingCargo().addSupplies(30);
data.getStartingCargo().addCrew(CrewXPLevel.REGULAR, 20);
data.getStartingCargo().addMarines(5);
} else
if (variantId.equals("lasher_Standard")) {
data.getStartingCargo().addFuel(20);
data.getStartingCargo().addSupplies(20);
data.getStartingCargo().addCrew(CrewXPLevel.REGULAR, 40);
data.getStartingCargo().addMarines(10);
} else
if (variantId.equals("wolf_CS")) {
data.getStartingCargo().addFuel(20);
data.getStartingCargo().addSupplies(20);
data.getStartingCargo().addCrew(CrewXPLevel.REGULAR, 22);
data.getStartingCargo().addMarines(7);
} else
if (variantId.equals("shuttle_Attack")) {
data.getStartingCargo().addFuel(10);
data.getStartingCargo().addSupplies(10);
data.getStartingCargo().addCrew(CrewXPLevel.REGULAR, 10);
data.getStartingCargo().addMarines(3);
} else
if (variantId.equals("hound_Assault")) {
data.getStartingCargo().addFuel(30);
data.getStartingCargo().addSupplies(40);
data.getStartingCargo().addCrew(CrewXPLevel.REGULAR, 25);
data.getStartingCargo().addMarines(15);
} else {
data.getStartingCargo().addFuel(20);
data.getStartingCargo().addSupplies(20);
data.getStartingCargo().addCrew(CrewXPLevel.REGULAR, 20);
data.getStartingCargo().addMarines(10);
}
}
}
Loader will attempt to load first 32 classes with name CharacterCreationPluginImpl_X where X is integer from 0 to 31.
This is sample of class that edit second caption of character setup to "lol" and nothing else.
Spoiler
package data.scripts.plugins;
import com.fs.starfarer.api.campaign.CargoAPI.CrewXPLevel;
import com.fs.starfarer.api.characters.CharacterCreationPlugin;
import com.fs.starfarer.api.characters.CharacterCreationPlugin.CharacterCreationData;
import com.fs.starfarer.api.characters.CharacterCreationPlugin.Response;
import com.fs.starfarer.api.characters.MutableCharacterStatsAPI;
import com.fs.starfarer.api.fleet.FleetMemberAPI;
import data.scripts.plugins.CharacterCreationPluginImpl.ResponseImpl;
import data.usc.uscData;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.apache.log4j.Logger;
public class CharacterCreationPluginImpl_26 {
static Logger fun = Logger.getLogger("INVOKE");
public static void Responce_put(String Tag,String Info){
CharacterCreationPluginImpl._ResponsePool.put(Tag, new ResponseImpl(Info));
}
public static void Responce_rem(String Tag){
CharacterCreationPluginImpl._ResponsePool.remove(Tag);
}
@SuppressWarnings("unchecked")
public static void addResponse(String Tag)
{
CharacterCreationPluginImpl._getResponses.
add(CharacterCreationPluginImpl._ResponsePool.get(Tag));
}
public static Response Responce_get(String Tag){
return CharacterCreationPluginImpl._ResponsePool.get(Tag);
}
@SuppressWarnings("unused")
public static void init()
{
}
static int Capacity = 0;
static String[] tmps;
public static void setPrompt(String Tag, int Position)
{
if (Position > tmps.length)
{
String[] old = tmps.clone();
tmps = new String[Position];
for (int i = 0; i < old.length; i++)
{
tmps[i] = old[i];
}
}
tmps[Position] = Tag;
}
public static void getPrompt() {
tmps = CharacterCreationPluginImpl._Prompts;
setPrompt("Lol",1);
CharacterCreationPluginImpl._Prompts = tmps;
}
public static void getResponses(){
}
public static void submit() {
}
public static void startingShipPicked() {
}
}
Similar modifications can be done to any class, as long as mods follow rules they will be compatable and wont crash eachother randomly.