Yeah, I discovered another optimization with the java portion.
Originally, in my java code - I was constructing Gene classes like this:
public class Gene {
public Gene(int geneID){
this.GeneID = geneID;
Initialize();
}
The initialize method would then do:
private void Initialize(){
String sName = NWScript.getLocalString(NWObject.MODULE, INHUMAN_POWER_STORAGE_NAME+GeneID);
int Feat = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_FEATID+GeneID);
boolean IsPassive = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_IS_PASSIVE+GeneID)==1;
int EffectType = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_EFFECT_TYPE+GeneID);
int TimeOfDay = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_TIMEOFDAY+GeneID);
int Number1 = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_NUMBER1+GeneID);
int Number2 = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_NUMBER2+GeneID);
int LevelOfPower = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_LEVEL_OF_POWER+GeneID);
int Natural = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_ENVIRONMENT_NATURAL+GeneID);
int Above = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_ENVIRONMENT_ABOVE_GROUND+GeneID);
int Interior = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_ENVIRONMENT_INTERIOR+GeneID);
int Surface = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_ENVIRONMENT_SURFACE_TYPE+GeneID);
boolean AlwaysActive = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_ALWAYS_ACTIVE+GeneID)==1;
int DamageAmount = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_DAMAGE_AMOUNT+GeneID);
int DamageType = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_DAMAGE_TYPE+GeneID);
int Visual = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_VISUAL+GeneID);
boolean InCombatOnly = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_COMBAT_ONLY+GeneID)==1;
setGeneName(sName);
setFeatID(Feat);
setIsPassive(IsPassive);
setTimeOfDayActive(TimeOfDay);
setEffectType(EffectType);
setEffectNumber1(Number1);
setEffectNumber2(Number2);
setLevelOfPower(LevelOfPower);
setEnvironmentNatural(Natural);
setEnvironmentAboveGround(Above);
setEnvironmentInterior(Interior);
setEnvironmentTilesetType(Surface);
setApplyDamageAmount(DamageAmount);
setDamageType(DamageType);
setVisualEffect(Visual);
setAlwaysActive(AlwaysActive);
setCombatOnly(InCombatOnly);
}
This loses the speed benefit of Java, because it has 17 calls to the NWScript / Virtual Machine.
Each one of these holds up the server process by a few ms each, since the virtual machine is single threaded and operates on the MainLoop thread.
However, by changing my code to have a static HashMap in the jvm that caches the Gene classes, it means I remove the need for it to subsequently call NWScript.
private void Initialize(){
String sName = NWScript.getLocalString(NWObject.MODULE, INHUMAN_POWER_STORAGE_NAME+GeneID);
int Feat = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_FEATID+GeneID);
boolean IsPassive = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_IS_PASSIVE+GeneID)==1;
int EffectType = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_EFFECT_TYPE+GeneID);
int TimeOfDay = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_TIMEOFDAY+GeneID);
int Number1 = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_NUMBER1+GeneID);
int Number2 = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_NUMBER2+GeneID);
int LevelOfPower = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_LEVEL_OF_POWER+GeneID);
int Natural = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_ENVIRONMENT_NATURAL+GeneID);
int Above = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_ENVIRONMENT_ABOVE_GROUND+GeneID);
int Interior = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_ENVIRONMENT_INTERIOR+GeneID);
int Surface = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_ENVIRONMENT_SURFACE_TYPE+GeneID);
boolean AlwaysActive = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_ALWAYS_ACTIVE+GeneID)==1;
int DamageAmount = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_DAMAGE_AMOUNT+GeneID);
int DamageType = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_DAMAGE_TYPE+GeneID);
int Visual = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_VISUAL+GeneID);
boolean InCombatOnly = NWScript.getLocalInt(NWObject.MODULE, INHUMAN_POWER_STORAGE_COMBAT_ONLY+GeneID)==1;
setGeneName(sName);
setFeatID(Feat);
setIsPassive(IsPassive);
setTimeOfDayActive(TimeOfDay);
setEffectType(EffectType);
setEffectNumber1(Number1);
setEffectNumber2(Number2);
setLevelOfPower(LevelOfPower);
setEnvironmentNatural(Natural);
setEnvironmentAboveGround(Above);
setEnvironmentInterior(Interior);
setEnvironmentTilesetType(Surface);
setApplyDamageAmount(DamageAmount);
setDamageType(DamageType);
setVisualEffect(Visual);
setAlwaysActive(AlwaysActive);
setCombatOnly(InCombatOnly);
IdToGene.put(GeneID, this); <-- HERE
NWScript.printString("Stored gene "+this.getGeneName()+" with gene id "+GeneID);
}
private static HashMap<Integer, Gene> IdToGene = new HashMap<Integer, Gene>();
It means that when I am getting the Genome for a creature/object.
public Genome(NWObject player) {
int AmountOfGenesOnCreature = NWScript.getLocalInt(player, "creature_gene_count_");
int i;
for (i = 1; i <= AmountOfGenesOnCreature; i++) {
int GeneID = NWScript.getLocalInt(player, "creature_genome_storage_" + i);
if (GeneID != 0) {
//Gene geneToApply = new Gene(GeneID); <-- No longer do this
Gene geneToApply = Gene.getGeneByID(GeneID); < --instead get the cached gene
this.add(geneToApply);
}
}
}
This is an improvement on performance as it removes 17 calls to NWScript, per gene per object.
Eg: In my project, creatures and players will have genomes, which contain zero or more genes that affect special abilities etc
Arguably, I could further enhance this by removing all calls to getLocal / setLocal.
Instead using getters and setters in Java, which are called from NWScript - for any system in NWScript that needs to interact with those values.