Page 11 of 138
Posted: Wed Oct 03, 2007 10:47 pm
by JensAyton
Following my fine tradition of running off on a tangent, I’ve hacked together a basic but working command-line version of the JavaScript console, communicating over TCP, and with no Objective-C in it.
Code: Select all
- Waiting for connection.
- Client connected.
- Connection established to Oolite 1.69.2.
5 + 3
> 5 + 3
8
player
> player
[Player "Cobra Mark III" ID: 100 position: (-49515.3, 60769.4, 427622) scanClass: CLASS_PLAYER status: STATUS_DOCKED]
banana
> banana
Exception: ReferenceError: banana is not defined
Active script: "oolite-mac-js-console" 1.69.2
oolite-mac-js-console.js, line 147:
let result = eval(command)
- Connection closed (Oolite is terminating.).
It should be portable to Windows. Linux may be harder. I’ll try to slap together some documentation tomorrow, and integrate the Oolite-side part into Oolite itself rather than, as now, the Mac-only debug OXP.
Edit: I should probably add that the code is designed so that the bit for communicating with Oolite can easily be reused in, say, a GUI debug console.
Posted: Sat Oct 06, 2007 5:13 pm
by JensAyton
Console protocol is now
documented. Writing Windows and Linux consoles that don’t suck is considered a third-party opportunity. The command-line implementation in the repository now has build instructions, of sorts.
Posted: Sat Oct 06, 2007 6:42 pm
by Arexack_Heretic
Just for those that don't understand code like their native language...
what are the possibilities for this console?
Will it enable us to directly execute commands in the game?
Will it make possible for non-adept coders to build methods without using C?
Will it enable better debugging tools?
Will it do all this and more?
Posted: Sat Oct 06, 2007 7:30 pm
by JensAyton
The console allows you to issue any JavaScript command that you could usually use in a script, but allows you to do it interactively rather than having to quit, modify the script and run Oolite again. This means that you can fiddle with and examine the game state as it is in any give moment, rather than having to try to recreate the state each time. For instance, you can manipulate ships in the game world:
Code: Select all
player.target.call("becomeExplosion")
player.setPosition(player.position.add(0, 100, 0))
Spawn ships for testing:
Code: Select all
system.legacy_addSystemShips("myShipRole", 1, 1)
Examine mission state:
Code: Select all
missionVariables["trumbles"]
// Console prints "TRUMBLE_BOUGHT"
Write your own debug tools:
Code: Select all
:setM startLogging this.loggingTimer = new Timer(this, function() { Log("player position: " + player.position) } , 0, PARAM)
:setM stopLogging if (this.loggingTimer) { this.loggingTimer.stop(); delete this.loggingTimer }
:startLogging 1
// Player position is logged at one-second intervals
Make scripts do things:
Code: Select all
system.mainStation.script.doTestStuff()
Examine and modify the scripts of live objects:
Code: Select all
> systemScripts["oolite-cloaking-device"].willExitWitchSpace
// Console prints:
this.willExitWitchSpace = function()
{
if (galaxyNumber == 4)
{
if (missionVariables.cloak == null)
{
var cloakCounter = missionVariables.cloakcounter;
if (cloakCounter == null) cloakCounter = 1;
else cloakCounter++;
missionVariables.cloakcounter = cloakCounter;
if (cloakCounter > 6 && system.countShipsWithRole("asp-cloaked") == 0)
{
system.legacy_addShips("asp-cloaked", 1);
system.legacy_addShips("asp-pirate", 2);
}
}
}
}
> systemScripts["oolite-cloaking-device"].willExitWitchSpace = function() { player.credits += 5000 }
// Console prints:
function()
{
player.credits += 5000
}
Posted: Sun Oct 07, 2007 5:00 pm
by JensAyton
Oh, here’s another one:
Code: Select all
> printList(system.allShips)
// Console prints:
72 items:
[Player "Cobra Mark III" ID: 100 position: (-49515.3, 60769.4, 427622) scanClass: CLASS_PLAYER status: STATUS_START_GAME]
[Station "Coriolis Station" "Coriolis Station" ID: 105 position: (-49515.3, 60769.4, 427622) scanClass: CLASS_STATION status: STATUS_ACTIVE]
[Ship "Cobra Mark III" ID: 174 position: (0, 0, 261.843) scanClass: CLASS_NO_DRAW status: STATUS_COCKPIT_DISPLAY]
[Ship "GalCop Viper" ID: 175 position: (-48975.8, 60107.3, 427897) scanClass: CLASS_POLICE status: STATUS_LAUNCHING]
[Ship "Navigation Buoy" ID: 172 position: (-43500.3, 53387.3, 430676) scanClass: CLASS_BUOY status: STATUS_IN_FLIGHT]
...
[Ship "Asteroid" ID: 170 position: (27558.5, 7192.02, 865128) scanClass: CLASS_ROCK status: STATUS_IN_FLIGHT]
[Ship "Asteroid" ID: 171 position: (-16116.1, 20510.8, 880110) scanClass: CLASS_ROCK status: STATUS_IN_FLIGHT]
> printList(system.planets)
2 items:
[Planet ID: 103 position: (0, 0, 452760) scanClass: CLASS_NO_DRAW status: STATUS_ACTIVE type: PLANET_TYPE_GREEN radius: 41.160km]
[Planet ID: 104 position: (-782892, -340254, 754874) scanClass: CLASS_NO_DRAW status: STATUS_ACTIVE type: PLANET_TYPE_SUN radius: 84.449km]
printList() is a JavaScript function defined by the console script, which looks like this:
Code: Select all
this.printList = function(l)
{
let length = l.length
ConsoleMessage("printList", length.toString() + " items:")
for (let i = 0; i != length; i++)
{
ConsoleMessage("printList", " " + l[i].toString())
}
}
Posted: Sun Oct 07, 2007 5:05 pm
by Arexack_Heretic
How about a command that enables realtime viewing of the AI states/commands and behaviour of the current player.target?
Posted: Sun Oct 07, 2007 9:15 pm
by JensAyton
Like shift-H, you mean?
As it stands, you can get
player.target.AIState. I don’t want to expose the behaviour directly as it’s an implementation detail that may change. Adding it to the description (what you get if you type
player.target, the stuff that’s in the list in my previous post) is an option, though. Possibly additional attributes like behaviour and the AI stack could be exposed when the debug OXP is installed.
Posted: Sun Oct 07, 2007 9:24 pm
by Arexack_Heretic
I'm currently in a code-to-keyboard battle with a recalcitrant AI...the explosiveAI.
You are saying using [shift-H] would have saved me from using an entity dump (pause+zero) and reloading the stderr file again and again?
....where can these nuggets of unfathomable knowledge be found?!
I find: pauseAI: s does not work except in the UPDATE = (); line.
commsMessage is flaky.
I'm not yet sure what is going wrong, but for now I'm assuming it is my code.
Relevant code and stuff here:
https://bb.oolite.space/viewtopic.php?t=3905&start=45
Posted: Sun Oct 07, 2007 10:51 pm
by JensAyton
Arexack_Heretic wrote:I'm currently in a code-to-keyboard battle with a recalcitrant AI...the explosiveAI.
You are saying using [shift-H] would have saved me from using an entity dump (pause+zero) and reloading the stderr file again and again?
I’m referring to
key_dump_target_state, which is not enabled by default in as-yet-released versions of Oolite. You can find out about it by reading various bits of the forum. :-)
You’ll still need to reload the log file, although there are probably log-watching programs for Windows that’ll show updates as they’re written. Echoing the
key_dump_target_state dump to the debug console might be a reasonable thing to do.
Posted: Sun Oct 07, 2007 11:06 pm
by JensAyton
- Implemented Planet JavaScript class. Not very exciting; it’s an http://wiki.alioth.net/index.php/Oolite ... ass/Entity with the additional attributes isMainPlanet, isSun, hasAtmosphere and radius.
- Added System attributes sun, mainPlanet, planets and allShips.
- Added System methods shipsWithPrimaryRole(), shipsWithRole() and entitiesWithScanClass().
- Did not add method filteredEntities(), because it exposed a structural problem that I was aware of but was skirting around. The problem will also arise when a ship with a JS script is created from within a JS script. I think there’s a relatively painless fix, but I’m not certain.
system.filteredEntities() is particularly nice. It lets you get a list of entities based on arbitrary criteria. For instance, if you want to get all police ships that are within scanner range of the player and are not currently occupied, you might do this:
Code: Select all
this.findIdlePolice = function()
{
function isIdlePolice(entity)
{
return entity.isShip && entity.isPolice && !entity.target
}
return system.filteredEntities(this, isIdlePolice, player, 25600)
}
The function
isIdlePolice() (the
filter predicate) will be called for each entity within 25600 metres of the player, and those for which it returns
true will be put in a list. The second two parameters, the reference entity and range (in this case
player and 25600), are optional; if they’re not specified, the entire system is searched. The methods
shipsWithPrimaryRole(),
shipsWithRole() and
entitiesWithScanClass() also have optional reference entity and range parameters which work in the same way.
Edit: Updated isIdlePolice() example to actually check for policehood.
Posted: Mon Oct 08, 2007 6:05 am
by JensAyton
Intended additional semantics: the search-for-entities functions should return a list sorted by distance from the reference entity, if specified. They should also filter out ships with STATUS_COCKPIT_DISPLAY (those are used on the demo screen, shipyard screen etc.).
Posted: Mon Oct 08, 2007 12:03 pm
by JensAyton
Sorting and range limitation work.
Code: Select all
> this.wp = system.shipsWithRole("buoy-witchpoint")[0]
[Ship "Witchpoint Beacon" ID: 132 position: (-8700, -6700, -2500) scanClass: CLASS_BUOY status: STATUS_IN_FLIGHT]
> this.printDistance = function (l) { let length = l.length; for (let i = 0; i != length; ++i) ConsoleMessage("printList", l[i].ID.toString() + ": " + l[i].position.distanceTo(wp)) }
function (l) {
let length = l.length;
for (let i = 0; i != length; ++i) {
ConsoleMessage("printList", l[i].ID.toString() + ": " + l[i].position.distanceTo(wp));
}
}
> this.printDistance(system.shipsWithRole("asteroid"))
124: 703063.1875
130: 713221.6875
128: 706114.75
127: 704948.375
129: 711866.8125
125: 714886.8125
126: 714351.5625
> this.printDistance(system.shipsWithRole("asteroid", wp))
124: 703063.1875
127: 704948.375
128: 706114.75
129: 711866.8125
130: 713221.6875
126: 714351.5625
125: 714886.8125
> this.printDistance(system.shipsWithRole("asteroid", wp, 710000))
124: 703063.1875
127: 704948.375
128: 706114.75
Posted: Tue Oct 09, 2007 6:22 pm
by JensAyton
- Fixed bug where calling JavaScript code from Objective-C code that was itself called from JavaScript code would break the JavaScript engine. This was preventing System.filtereEntities() from working, and also breaking when a ship with a ship script was created from another script.
- Added Ship.hasRole() method, after needing it in a function and wondering for a second what sort of idiot would leave out such an obvious method. (‘ship.roles.indexOf("somerole") > -1’ works, but is somewhat lacking in elegance.)
Things holding up next release:
Well, infinitely many things, of course. But the most important ones:
- Need to go through and document the event handlers for ship scripts. Some handlers need to be moved from PlayerEntity to ShipEntity. I think there are some with dodgy names.
- Getting the client side of the debug console stuff working on Windows would be nice. Currently another_commander can connect to a console running on my machine, but doesn’t see any input coming back, limiting its usefulness. Making the command-line console, at least, run on Windows is a secondary concern – that can be released separately without a full Oolite update.
- I should probably look at at least a few bug reports at some point.
- At least one very important thing I can’t think of just at the moment.
So, maybe a 1.70 alpha release in a couple of weeks. (This one is likely to be… interesting… so we’ll probably be recommending that people don’t switch over to it immediately, but obviously it needs testing.) Oh, and it still won’t have the new “multi-nebula” sky, but the sky/nebula bug is fixed.
Posted: Fri Oct 12, 2007 12:38 pm
by JensAyton
Implemented access to world scripts:
Code: Select all
> worldScriptNames
oolite-trumbles,ahruman-billboard-populate,Pi-Forty-Two Con stores,oolite-thargoid-plans,oolite-nova,oolite-constrictor-hunt,oolite-cloaking-device
> :d worldScripts
> dumpObjectLong(eval("worldScripts"))
[object WorldScripts]:
oolite-trumbles = [Script "oolite-trumbles" version 1.69.2]
ahruman-billboard-populate = [Script "ahruman-billboard-populate" version 1.0]
Pi-Forty-Two Con stores = null
oolite-thargoid-plans = null
oolite-nova = null
oolite-constrictor-hunt = null
oolite-cloaking-device = [Script "oolite-cloaking-device" version 1.69.2]
The
null ones are legacy scripts. The JavaScript ones are
Script objects, which can be interacted with, primarily by calling methods on the script. See also:
Are sub-OXPs possible?.
Posted: Sat Oct 13, 2007 8:53 pm
by JensAyton
- Applied Eric Walch’s AI fixes.
- Had several mostly-successful remote JavaScript debugging sessions with another_commander. The Oolite side of the JavaScript console basically works, but is sensitive to bad input. On the face of it, this appears to be a GNUstep bug.