OXP Development Best Practices

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

Moderators: winston, another_commander

User avatar
phkb
Commodore
Commodore
Posts: 2433
Joined: Tue Jan 21, 2014 10:37 pm
Location: [p]laying [h]ard and [k]icking [b]utt somewhere in G7...

Re: OXP Development Best Practices

Post by phkb » Fri Jun 09, 2017 1:38 am

I think this is the best place to put this...

When using timers, the normal, widely-used standard for creating the callback function is like this:

Code: Select all

this.$myFunction = function() {...}
However, internally, Oolite is unable to determine the function name from this definition, so any errors that relate to the timer, for instance

Code: Select all

10:03:18.802 [script.javaScript.unrootedTimer]: ----- WARNING: Timer <OOJSTimer 0x39246230>{nextTime: 30.002, one-shot, running, function: anonymous} 
is being garbage-collected while still running. You must keep a reference to all running timers, or they will stop unpredictably!
are impossible to trace back to the source.

However, simply by defining your callback function like this:

Code: Select all

this.$myFunction = function $myFunction() {...}
the function name can be correctly identified and debugging issues is much easier.

This also goes for instances where the function has been defined in the timer initialisation step:

Code: Select all

var myTimer = new Timer(this, function $myCallback() {...}, 5, 0);

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

Re: OXP Development Best Practices

Post by UK_Eliter » Wed Jun 21, 2017 2:59 am

I have noticed that error messages about timers do not give the timer name. However, I am unsure I understand your rememdy.

My scripts constructions of this form:

Code: Select all

this.dieTimer = new Timer(this,this.$die, 1.7);
What should I replace them with? With constructions of the following form?

Code: Select all

this.dieTimer = new Timer(this,function this.$die, 1.7);
Also, if I make the change you are recommending, do I need to change how I stop timers, remove timers, etc.?

Thanks.

User avatar
phkb
Commodore
Commodore
Posts: 2433
Joined: Tue Jan 21, 2014 10:37 pm
Location: [p]laying [h]ard and [k]icking [b]utt somewhere in G7...

Re: OXP Development Best Practices

Post by phkb » Wed Jun 21, 2017 6:11 am

UK_Eliter wrote:What should I replace them with?
If you have your timer initialised like this:
UK_Eliter wrote:

Code: Select all

this.dieTimer = new Timer(this,this.$die, 1.7);
...then the function you are calling should be declared like this:

Code: Select all

this.$die = function $die() {
	// code of the function follows...
}
Basically, all you're doing is repeating the name of the function between the "function" and the "()".

Nothing else about the timers needs to change. All this does is gives the JS engine a function name to work with when displaying information back to you in the log file.

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

Re: OXP Development Best Practices

Post by UK_Eliter » Wed Jun 21, 2017 12:47 pm

Got it. I think. I'll report back if I have problems. Thank you.

cag
Dangerous
Dangerous
Posts: 85
Joined: Fri Mar 17, 2017 1:49 am

Re: OXP Development Best Practices

Post by cag » Fri Jun 23, 2017 9:46 pm

If you plan on profiling your code, I recommend adding the repeat name on all your functions. Otherwise you get:

Code: Select all

                                                        NAME  T  COUNT    TOTAL     SELF  TOTAL%   SELF%  SELFMAX
                                     WorldScriptsGetProperty  N    779    43.52    39.73    42.9    39.1     0.25
                                        OOStringFromJSString  N   1536     7.63     7.63     7.5     7.5     0.19
                                             ShipGetProperty  N   3778    13.91     7.07    13.7     7.0     0.01
                              (telescope.js:628) <anonymous>  J    244    86.55     5.88    85.3     5.8     0.19
                                         ShipEquipmentStatus  N    755    12.67     5.25    12.5     5.2     0.03
                              (telescope.js:670) <anonymous>  J    142    48.02     5.00    47.3     4.9     0.25
                                           EntityGetProperty  N   3278     7.64     4.76     7.5     4.7     0.02
    -[NSString(OOJavaScriptExtensions) oo:jsValueInContext:]  N   1281     3.99     3.99     3.9     3.9     0.03
                              (telescope.js:767) <anonymous>  J    144     6.31     2.13     6.2     2.1     0.25
                                         JSShipGetShipEntity  N   4533     1.73     1.73     1.7     1.7     0.01
                                         OOJSEntityGetEntity  N   3284     1.62     1.62     1.6     1.6     0.01
                              (telescope.js:609) <anonymous>  J    142    12.58     1.49    12.4     1.5     0.04
                              (telescope.js:621) <anonymous>  J    143    11.32     1.47    11.2     1.4     0.04
                                      JSValueToEquipmentType  N    755     7.02     1.32     6.9     1.3     0.03
                                      
By adding the 2nd function name, all the above "<anonymous>" tags get replaced with the actual function names. Esp. important if you're modifying code in real-time (ie. w/o restarting oolite), as the line numbers quickly become useless.
"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: 1103
Joined: Sat Sep 12, 2009 11:58 pm
Location: Essex (mainly industrial and occasionally anarchic)

Re: OXP Development Best Practices

Post by UK_Eliter » Thu Jul 20, 2017 1:50 am

I've just discovered error-checking plugins for editors. Specifically, the jshint javascript plugin for Sublime Text (though jshint has plugins for other editors). Getting such 'linters' installed, in Linux and especially Windows, was a pain. Also, I can't seem to stop jshint complaining about "use strict";. Further, it complains about problems that might seem merely cosmetic, such as missing semi-colons at the end of functions. Still, the plugin did pick up some errors of a more substantial kind, though even in nearly all of those cases the errors would not have been such - I hope - to affect functionality.

Anyone else use such a thing? (I've stated using a Bash linter on Linux too.)

cag
Dangerous
Dangerous
Posts: 85
Joined: Fri Mar 17, 2017 1:49 am

Re: OXP Development Best Practices

Post by cag » Thu Jul 20, 2017 9:35 pm

I'm on Windows and use NotePad++ with a JSLint/JSHint plug-in. I find JSHint more useful, though I think we're stuck w/ the
Use the function form of "use strict"
message. You can DL the plug-in here:

https://sourceforge.net/projects/jslintnpp/

unzip and copy the .dll file into C:\Program Files (x86)\Notepad++\plugins\

In the JSHint options, I've got this:

Code: Select all

addFrameCallback, checkScanner, clock, console, consoleMessage, defaultFont, displayNameForCommodity, EquipmentInfo, 
expandDescription, expandMissionText, formatCredits, formatInteger, galaxyNumber, global, guiScreen, isValidFrameCallback, 
log, manifest, mission, missionVariables, oolite, player, randomInhabitantsDescription,  randomName, removeFrameCallback, 
setScreenBackground, setScreenOverlay, Sound, SoundSource, System, system, takeSnapShot, timeAccelerationFactor, Timer, 
Vector3D,worldScriptNames, worldScripts
in the "Predefined" options box (there may be more oolite specific ones, I just add them as they come up) and this:

Code: Select all

elision:true, shadow:false, esnext: true, validthis: true, curly: false, maxerr: 1000, asi: true, laxbreak: true, undef: true, unused:true
in the "Additional Options" box. Don't ask me what these do (it was a hit or miss procedure). The only message I get once all the errors are fixed is the one about "use strict". I don't think our version of JS (whatever that is) has it and this message can be ignored.

Given how long it takes to rebuild the cache and launch, this can be a real time-saver in the dev cycle. And if you're loading newly edited functions into the debug console, this is a must, as the console cannot give you line numbers for any errors.
"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: 1103
Joined: Sat Sep 12, 2009 11:58 pm
Location: Essex (mainly industrial and occasionally anarchic)

Re: OXP Development Best Practices

Post by UK_Eliter » Fri Jul 21, 2017 12:38 am

Hi cag,

The web does mention ways of avoiding the 'use strict' nag in JSHint. One of them involves doing something to every function in one's script. That's not worth it. There is at least one other way, though, at least for Sublime Text; but this other method / these other methods looked a bit involved themselves.

I don't see the other errors you mention, except perhaps one to do with SoundSource; I think the correct form of this is indeed SoundSource(), even though Oolite doesn't complain about SoundSource. Also, at one point the 'linter' did report something about some WorldScripts formulation, but that message seemed to go away.

PS: I use NotePad++ (on Windows) but only for Autohotkey coding and only because I can't find a SublimeText plugin for that. There are things I dislike about Sublime, but I do prefer it to NotePad++.

User avatar
Svengali
---- E L I T E ----
---- E L I T E ----
Posts: 2365
Joined: Sat Oct 20, 2007 2:52 pm

Re: OXP Development Best Practices

Post by Svengali » Fri Jul 21, 2017 8:37 am

You don't need to do it for every function. Just wrap your code in a function. Please also note that the jshint and the global settings will vary from script to script - sometimes you don't need them at all.

Code: Select all

/* jshint <your options> */
/* global <your global vars> */
(function(){
"use strict";
<your code>

}).call(this);

User avatar
Day
---- E L I T E ----
---- E L I T E ----
Posts: 518
Joined: Tue Mar 03, 2015 11:35 am
Location: Paris

Re: OXP Development Best Practices

Post by Day » Fri Jul 21, 2017 12:29 pm

UK_Eliter wrote:
Thu Jul 20, 2017 1:50 am
Anyone else use such a thing?
I use Intellij Idea.

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

Re: OXP Development Best Practices

Post by UK_Eliter » Fri Jul 21, 2017 4:51 pm

Svengali: thank you - I thought someone here would know! The procedure is a bit of a pain - if one has many scripts - but now that I've got it set up, it's good.

Post Reply