OXP Performance tips

Discussion and information relevant to creating special missions, new ships, skins etc.

Moderators: winston, another_commander

UK_Eliter
---- E L I T E ----
---- E L I T E ----
Posts: 1248
Joined: Sat Sep 12, 2009 11:58 pm
Location: Essex (mainly industrial and occasionally anarchic)

Re: OXP Performance tips

Post by UK_Eliter »

This is great stuff. I think some of it will do wonders for my code.

I had trouble getting the profiler to work in the past, but I think I can see, without it, which bits of my code are the most time critical.

Happily, I'd started rewriting - mainly just stylistically - already.

If I could get someone to give my newly rewritten Interstellar Tweaks OXP a test run, that would be great. I should be able to have it - the rewritten and ready-for-second-party test - version ready in a few days. There should not be that much to do because, though the OXP allows a great many scenarios, I haven't rewritten that much (and I'll test it myself somewhat).
UK_Eliter
---- E L I T E ----
---- E L I T E ----
Posts: 1248
Joined: Sat Sep 12, 2009 11:58 pm
Location: Essex (mainly industrial and occasionally anarchic)

Re: OXP Performance tips

Post by UK_Eliter »

Day, this is throwing me:

Code: Select all

var z = myArray.length;
while (z--) {
    var myElement = myArray[z];
    // my code
}
What exactly does that do? Suppose that the length of myArray is 3, i.e. myArray has three members, the indices of which are:

Code: Select all

myArray[0]
myArray[1]
MyArray[2]
Does your loop proceed backwards through the members of myArray, starting at myArray[2] and proceeding to myArray[0]? The loop through an error in my code, which makes me think its trying to access myArray[-1] or myArray[3], but probably there's a mistake elsewhere in my code.

EDIT: Here are the relevant bits of my code, i.e. the bits that threw the error.

Code: Select all

this.maxBattleships = 2;

this.$isBattleship = function(e) {
	return e.isShip && e.isThargoid && e.name === "Thargoid Thargorn Battleship"
}
// Note: the battleship lacks a distinct role, so we have to use its name.

if ( this.bugThreat_Installed && Math.random() <= this.chanceLimitBattleshipsInOtherwiseUnmodified ) {
	s = system.filteredEntities(this, this.$isBattleship);
	i = s.length - this.maxBattleships;
	while ( i-- ) {
		s[i].remove(true);
	}
}
The error is:

Code: Select all

JavaScript exception (IST_masterScript 5.38): TypeError: s[i] is undefined
User avatar
phkb
Impressively Grand Sub-Admiral
Impressively Grand Sub-Admiral
Posts: 4829
Joined: Tue Jan 21, 2014 10:37 pm
Location: Writing more OXPs, because the world needs more OXPs.

Re: OXP Performance tips

Post by phkb »

I think the problem is with this line:

Code: Select all

i = s.length - this.maxBattleships;
You're setting "i" up to be an index of the "s" array, but then you're adjusting the starting point. If "s" ends up having 0 elements (ie because there are no battleships returned through the filteredEntities call), then i is going to start with at index -2. And, therefore, "undefined".
User avatar
Day
---- E L I T E ----
---- E L I T E ----
Posts: 545
Joined: Tue Mar 03, 2015 11:35 am
Location: Paris

Re: OXP Performance tips

Post by Day »

UK_Eliter wrote: Wed Jun 21, 2017 2:43 am
Day, this is throwing me:

Code: Select all

var z = myArray.length;
while (z--) {
    var myElement = myArray[z];
    // my code
}
What exactly does that do? Suppose that the length of myArray is 3, i.e. myArray has three members, the indices of which are:

Code: Select all

myArray[0]
myArray[1]
MyArray[2]
Does your loop proceed backwards through the members of myArray, starting at myArray[2] and proceeding to myArray[0]?
Exactly.
phkb wrote:
I think the problem is with this line:

Code: Select all

i = s.length - this.maxBattleships;
You're setting "i" up to be an index of the "s" array, but then you're adjusting the starting point. If "s" ends up having 0 elements (ie because there are no battleships returned through the filteredEntities call), then i is going to start with at index -2. And, therefore, "undefined".
Exactly. The starting point should be the length of the list you want to iterate through.
User avatar
Day
---- E L I T E ----
---- E L I T E ----
Posts: 545
Joined: Tue Mar 03, 2015 11:35 am
Location: Paris

Re: OXP Performance tips

Post by Day »

UK_Eliter wrote: Wed Jun 21, 2017 12:25 am
This is great stuff. I think some of it will do wonders for my code.
Thank you :P
UK_Eliter
---- E L I T E ----
---- E L I T E ----
Posts: 1248
Joined: Sat Sep 12, 2009 11:58 pm
Location: Essex (mainly industrial and occasionally anarchic)

Re: OXP Performance tips

Post by UK_Eliter »

phkb, Day

Thank you for your explanations.

About the 'undefined' error: I had been under the impression that if i <= 0, any text within

Code: Select all

while ( i-- ) {
}
would not run at all.
User avatar
Day
---- E L I T E ----
---- E L I T E ----
Posts: 545
Joined: Tue Mar 03, 2015 11:35 am
Location: Paris

Re: OXP Performance tips

Post by Day »

UK_Eliter wrote: Wed Jun 21, 2017 12:32 pm
phkb, Day

Thank you for your explanations.

About the 'undefined' error: I had been under the impression that if i <= 0, any text within

Code: Select all

while ( i-- ) {
}
would not run at all.
Well, 0 is considered false, and other numbers, including negative ones, are true.
So for i = 0, the code within won't run (the -- is operated after the while comparison).
For i < 0, the code within will an inifinite amount of times.
UK_Eliter
---- E L I T E ----
---- E L I T E ----
Posts: 1248
Joined: Sat Sep 12, 2009 11:58 pm
Location: Essex (mainly industrial and occasionally anarchic)

Re: OXP Performance tips

Post by UK_Eliter »

Ah, right. Sometimes I will have to add some checks for that, resulting in slightly less optimisation and - where I do add a check - a slightly more fragile script. Oh well.
UK_Eliter
---- E L I T E ----
---- E L I T E ----
Posts: 1248
Joined: Sat Sep 12, 2009 11:58 pm
Location: Essex (mainly industrial and occasionally anarchic)

Re: OXP Performance tips

Post by UK_Eliter »

I've a question about functions.

Previously, the following was typical in my code.

Code: Select all

this.$timedDamageNonPlayerViaRadiation = function $timedDamageNonPlayerViaRadiation() {
	var i;
	var s;
	var damage;
	var shipsToDamage;

	if ( !system.isInterstellarSpace ) { this.$removeRadiationTimers(); return; }
	if ( !player.ship ) { this.$removeRadiationTimers(); return; }
	s = system.allShips;

	function $toDamage(e) {
		return e.isShip && !e.isPlayer
	}

	shipsToDamage = s.filteredEntities(this, $toDamage);
Now I am getting rid of functions-within-functions. But I am unsure of the syntax for entity filtering and I've been getting an error message. Is the following format right, please?

Code: Select all

this.$toDamage = function(e) {
	return e.isShip && !e.isPlayer
}

this.$timedDamageNonPlayerViaRadiation = function $timedDamageNonPlayerViaRadiation() {
	var i;
	var s;
	var damage;
	var shipsToDamage;

	if ( !system.isInterstellarSpace ) { this.$removeRadiationTimers(); return; }
	if ( !player.ship ) { this.$removeRadiationTimers(); return; }
	s = system.allShips;
	shipsToDamage = s.filteredEntities(this, this.$toDamage); // DOES THIS WORK?
I am unsure about the 'this' in 'this.$toDamage'. On the other hand, perhaps the problem is with variable declaration . .
cag
Deadly
Deadly
Posts: 202
Joined: Fri Mar 17, 2017 1:49 am

Re: OXP Performance tips

Post by cag »

your error is coming from

Code: Select all

s = system.allShips;
...
shipsToDamage = s.filteredEntities(this, $toDamage);
allShips is just an array i.e., a property of system, and has no methods.
filteredEntities is a method of system.
So, instead, just use

Code: Select all

shipsToDamage = system.filteredEntities(this, $toDamage);
"Better to be thought a fool, boy, than to open your trap and remove all doubt." - Grandma [over time, just "Shut your trap... fool"]
"The only stupid questions are the ones you fail to ask." - Dad
How do I...? Nevermind.
cag
Deadly
Deadly
Posts: 202
Joined: Fri Mar 17, 2017 1:49 am

Re: OXP Performance tips

Post by cag »

the following is faster than indexOf when dealing with arrays:

Code: Select all

this._index_in_list = function( item, list ) { // for arrays only
    var k = list.length;
    while( k-- ) {
        if( list[ k ] === item ) return k;
    }
    return -1;
}
so,

Code: Select all

if( targets.indexOf( ship ) ...
becomes

Code: Select all

if( ws._index_in_list( ship, targets ) ...
I replaced all (29) of the indexOf used on arrays in telescope.js and got 3 more frames/sec!
"Better to be thought a fool, boy, than to open your trap and remove all doubt." - Grandma [over time, just "Shut your trap... fool"]
"The only stupid questions are the ones you fail to ask." - Dad
How do I...? Nevermind.
UK_Eliter
---- E L I T E ----
---- E L I T E ----
Posts: 1248
Joined: Sat Sep 12, 2009 11:58 pm
Location: Essex (mainly industrial and occasionally anarchic)

Re: OXP Performance tips

Post by UK_Eliter »

cag: thanks a lot. About your suggestion that I use:

Code: Select all

shipsToDamage = system.filteredEntities(this, $toDamage);
Is the '(this, $toDamage)' right? I don't need '(this, this.$toDamage)'?

(As you can see, I don't really understand this stuff, though somehow I manage to have written a 1, 000 line OXP that works! Well, it worked before I started the latest bit of fiddling with it, anyway . .)
cag
Deadly
Deadly
Posts: 202
Joined: Fri Mar 17, 2017 1:49 am

Re: OXP Performance tips

Post by cag »

Yes, you do need that this!

Code: Select all

shipsToDamage = system.filteredEntities(this, this.$toDamage);
The 1st (lone) this tells filteredEntities where to operate in, in what 'scope' or enviroment to use (ie. this tells it to run using your script file's variables).
You absolutely need the 2nd one on $toDamage, or you'll get a reference error (the interpreter won't be able to find the function)
"Better to be thought a fool, boy, than to open your trap and remove all doubt." - Grandma [over time, just "Shut your trap... fool"]
"The only stupid questions are the ones you fail to ask." - Dad
How do I...? Nevermind.
UK_Eliter
---- E L I T E ----
---- E L I T E ----
Posts: 1248
Joined: Sat Sep 12, 2009 11:58 pm
Location: Essex (mainly industrial and occasionally anarchic)

Re: OXP Performance tips

Post by UK_Eliter »

OK, great. Thank you. I did not need the second 'this' when the function in question was defined within the function that I was in already. (See an earlier post of mine if you need explanation.) But, as per one of the performance tips earlier in this thread. I was trying to get rid of such nested (if that's the word I want) functions.
User avatar
Day
---- E L I T E ----
---- E L I T E ----
Posts: 545
Joined: Tue Mar 03, 2015 11:35 am
Location: Paris

Re: OXP Performance tips

Post by Day »

cag wrote: Thu Jun 22, 2017 2:28 am
the following is faster than indexOf when dealing with arrays:

Code: Select all

this._index_in_list = function( item, list ) { // for arrays only
    var k = list.length;
    while( k-- ) {
        if( list[ k ] === item ) return k;
    }
    return -1;
}
so,

Code: Select all

if( targets.indexOf( ship ) ...
becomes

Code: Select all

if( ws._index_in_list( ship, targets ) ...
I replaced all (29) of the indexOf used on arrays in telescope.js and got 3 more frames/sec!
Wow!
I would never have thought that the native method would be slower than the reimplementation :shock:
ToBeInserted => Done
Last edited by Day on Mon Jun 26, 2017 9:31 am, edited 1 time in total.
Post Reply