Page 1 of 4

UncleBob's annoying API questions

Posted: Fri Oct 28, 2011 11:07 am
by UncleBob
My endeavours in mission creation has lead to a few questions, as could be expected. I'm getting a hang of LUA, but it will probably be a few projects until I'll really know what I'm doing, but LUA related questions are not really what I'm going to ask here, there's certainly tons of places better suited for that. None the less, some of my perceived API problems might well be because of Syntax errors or similiar, so please be patient.Anyways, my scout mission is comming along, the only major thing left to do is for the script to notice that I actually completed the mission. If I could handle that by one of the provided events, that wouldn't be a problem, but it's not that simple. The mission gives you a planet you have to scout, and what I have in mind is something like go into high orbit and complete one orbit, then the computer will give a message that you completed your duty and can get your paycheck at the nearest base. Paying up isn't a problem, since I can handle that very simply by the next OnShipDocked event.But, how do I check my mission parameters? I see there's functions for checking distances, so that will doubtlessly be helpfull. But I need a loop in which this check can be performed. Is there a standard function that can be embeded into a script that gets called on in every frame? that's how orbiter enables you to keep track of stuff, is there something similiar in Pioneer?Plus, a minor problem, I have been trying to make sure that the planet one gets to scout is uninhabited. I tried this by doing the following:
Code:
local nearbysystems = Game.system:GetNearbySystems(max_delivery_dist, function (s) return #s:GetStationPaths() > 0 end)if #nearbysystems == 0 then return endnearbysystem = nearbysystems[Engine.rand:Integer(1,#nearbysystems)]local dist = nearbysystem:DistanceTo(Game.system)local nearbystations = nearbysystem:GetBodyPaths()local HasPop = 1while HasPop > 0 dolocation = nearbystations[Engine.rand:Integer(1,#nearbystations)]if location.superType() == STARPORT thenHasPop = 0endend
Without a doubt you can see that I'm shamelessly ripping off the code of the delivery mission whereever usefull, I'll do some renaming of variables later on when I know the ropes better. Anyways, the line "if location.superType() == STARPORT then..." is not much apreciated by the interpreter. Probably a Syntax error, but I looked at other loops and if's and function calls in the code, and I don't quite get what's wrong with it. It's probably too C++ish... How would I have to write that statement?

RE: UncleBob's annoying API questions

Posted: Fri Oct 28, 2011 11:25 am
by Brianetta
STARPORT needs to be in quotes.Constants.BodySuperType[5] is the string "STARPORT"; you'll find that all of the constants are made this way.

RE: UncleBob's annoying API questions

Posted: Fri Oct 28, 2011 11:34 am
by UncleBob
Thanks, it's kind of desorienting without clear datatype declaration (and to think that in the beginning I was so annoyed about C++ pedantic insistance on datatype compatibility... :lol: )I still get "unable to resolve method or atribut 'superType¨", though.Any suggestions on the other problem?

RE: UncleBob's annoying API questions

Posted: Fri Oct 28, 2011 3:02 pm
by durandal
nearbystations are paths because of nearbystations=nearbysystem:GetBodyPaths()http://eatenbyagrue.org/f/pioneer/codedoc/files/LuaSystemPath-cpp.html#SystemPathand as you can see that class does not have superType attribute.To get superType attribute you need to get call station = location.GetSystemBody()http://eatenbyagrue.org/f/pioneer/codedoc/files/LuaSBody-cpp.html#SystemBodywhich as you can see have superType attributethen you just check ifstation.superType == 'STARPORT'Anyway this whole code is pointless because location and all nearbystations are already 'STARPORT'.but if you check station.type you will know if station is 'STARPORT_ORBITAL' or 'STARPORT_SURFACE'

RE: UncleBob's annoying API questions

Posted: Fri Oct 28, 2011 3:06 pm
by durandal
And you really should ask such questions on irc because forum is so sloooow.

RE: UncleBob's annoying API questions

Posted: Fri Oct 28, 2011 3:40 pm
by UncleBob

Quote:
nearbystations are paths because of nearbystations=nearbysystem:GetBodyPaths()
Thanks a lot. As I said, it is somewhat disorienting to not have clear type declarations. Will take some getting used to...That leaves the problem of checking for my distance to the planet, since I can't use an event call (which currently is the bigger concern; if I can't get that to work, I can pretty much forgett about the scouting mission...)
Quote:
And you really should ask such questions on irc because forum is so sloooow.
To be honest, I never used IRC in my whole life... I'll look into it.

RE: UncleBob's annoying API questions

Posted: Fri Oct 28, 2011 5:29 pm
by robn
The data model is a bit confusing the first time. We need to document this better, but here's an attempt.SystemPath is a simple five-value type that acts as a pointer to a single object anywhere in the galaxy. It has no data or logic of its own, so there's basically no overhead in creating lots of these and passing them around.To actually work with an object, you use the SystemPath and its GetSystemBody() method to obtain a SystemBody. This is generally an expensive operation as it has to generate the starsystem to determine the body's attributes. There is some stuff in place to try to cache the starsystem data to reduce the overhead, but if you're going to be grabbing lots of SystemBodys from the same system you'd be better to get an explicit reference to the starsystem with GetStarSystem(). Don't worry too much about the overhead though - make something that works first, optimise later.SystemBodys are good for working with object attributes, choosing destinations, etc, but they are only an abstract representation. The "physical" representation of objects are the Body type and its subclasses. Body objects only exist for the current system, as they're part of the physics simulation and only one starsystem is ever being simulated at any time. Bodies are contained with the Space, and you use methods from that interface to obtain and manipulate handles on them. If you have a path to something in the current system, Space.GetBody(path.bodyIndex) will fetch the corresponding physics body. Another one is Game.player, which always holds the physics body that represents the current player. Many events are passed physics bodies in their arguments, for example, onShipDocked gets passed the Ship that docked and the SpaceStation that it docked with.Now, the event system. The way it works is that the game generates events for all sorts of things that happen, and pushes them onto a queue of events. You attach a function to the event queue, and that function will be called when the event occurs. The EventQueue docs give details of all the events that are available and the arguments they receive.Right now your module will receive events for every event of that type that happens, even if its happening to something that you don't care about (eg a ship controlled by another module). In the future there will be a filtering system that lets you select the objects you're interested in and only receive events for them.So, for checking for distance to a body, you might do something like this (untested):
Code:
-- body 0 is always the primary star, so this will work in any system :)local s = Space.GetBody(0)print("distance to star: "..s:DistanceTo(Game.player).." metres)
Hope that helps :)

RE: UncleBob's annoying API questions

Posted: Fri Oct 28, 2011 5:55 pm
by Ziusudra

UncleBob wrote:
But I need a loop in which this check can be performed. Is there a standard function that can be embeded into a script that gets called on in every frame? that's how orbiter enables you to keep track of stuff, is there something similiar in Pioneer?
Timer.CallEveryHowever, it might be easier to use EventQueue.onFrameChanged to know when the ship enters and exits the planet's frame.

RE: UncleBob's annoying API questions

Posted: Fri Oct 28, 2011 6:08 pm
by fluffyfreak

durandal wrote:
And you really should ask such questions on irc because forum is so sloooow.
maybe, but IRC disappears after a short while, whilst the forums are always searchable ;)

RE: UncleBob's annoying API questions

Posted: Fri Oct 28, 2011 6:40 pm
by robn

Ziusudra wrote:


UncleBob wrote:
But I need a loop in which this check can be performed. Is there a standard function that can be embeded into a script that gets called on in every frame? that's how orbiter enables you to keep track of stuff, is there something similiar in Pioneer?
Timer.CallEveryHowever, it might be easier to use EventQueue.onFrameChanged to know when the ship enters and exits the planet's frame.
I'd recommend using onFrameChanged if its enough. Timers are not for the faint of heart, and CallEvery places a lot of stress on the engine - so much so that we're considering removing it.

RE: UncleBob's annoying API questions

Posted: Sat Oct 29, 2011 7:56 am
by UncleBob
@ robn, thanks a lot for the very detailed explanation!@Ziusudra, Thanks. I saw the onFrameChanged event, but I think it's not enough. If I get this right, the event is called one time only, when my frame of reference changes to the target body, but that is usuall still a pretty far way off. I would like to be able to track the distance, and trigger "mission accomplished" after a certain time has been spent under a certain distance.Timer.CallEvery seems like a potential solution, but if its support is uncertain and it eats that much performance I'm very reluctant to use it...Have you guys ever considered some kind of "OnFrameRefresh"-event that's called once every iteration of the render-loop? Or would that burden the engine too much? (Orbiter supports it, but there you plug in dll-libraries, so I imagine script would be somewhat slower...)

RE: UncleBob's annoying API questions

Posted: Sat Oct 29, 2011 8:07 am
by robn
That's essentially what CallEvery is. It does work, and won't call your script more than once per second, but it has some real problems at higher timeaccels. If you feel inclined you should give it a try and see how it goes. If you manage to produce something compelling with it then that will justify its continued existence (or a mechanism like it).

RE: UncleBob's annoying API questions

Posted: Sat Oct 29, 2011 10:09 am
by UncleBob
Ok, I'll see how it goes. I've finally figured out my major Syntax problems, so maybe now I can make some progress... :)

RE: UncleBob's annoying API questions

Posted: Sat Oct 29, 2011 12:49 pm
by UncleBob
Hmmm, say... the onFrameChanged event gives me a body back. It toock me a while to understand that that wasn't the body of the new frame, but the body that changed frame (so basically, a ship). It was written quite clearly, but the term "body" is a bit confusing. Anyways, after figuring that out, I figured out how to get the frame of reference, but what I haven't figured out so far is how to identify the body passed to me by onFrameChange. Since the event gets passed for every ship, I have to somehow make sure that it's the player ship. Otherwise someone else might do the mission for me. How do I go about identifying the body passed on from the event? If I would get a ship back I could identify it, but I have not yet found a way to identify the body object.

RE: UncleBob's annoying API questions

Posted: Sat Oct 29, 2011 2:14 pm
by fluffyfreak
I just wanted to say that it's really cool seeing someone learning all this stuff and that people are so willing to lend their time to help :) Just about all the contracts and jobs coming up in my field are for Lua these days, it really seems to be taking over games coding so doing this stuff well stand anyone in good stead!

RE: UncleBob's annoying API questions

Posted: Sat Oct 29, 2011 2:31 pm
by Brianetta

UncleBob wrote:
I figured out how to get the frame of reference, but what I haven't figured out so far is how to identify the body passed to me by onFrameChange. Since the event gets passed for every ship, I have to somehow make sure that it's the player ship.

You want the IsPlayer() method. All Ship objects support it, and it's for exactly this situation. I've pasted the codedoc for your convenience:IsPlayerDetermines if the ship is the player ship
Code:
isplayer = ship:IsPlayer()

Returnsisplayer true if the ship is the player, false otherwiseExample
Code:
if Game.player:IsPlayer() then print("this is the player")end

RE: UncleBob's annoying API questions

Posted: Sat Oct 29, 2011 4:04 pm
by UncleBob

Quote:
You want the IsPlayer() method. All Ship objects support it, and it's for exactly this situation. I've pasted the codedoc for your convenience:
That's exactly the problem, I don't get a ship object from onFocusChanged. I get a body object, and that has no isPlayer member...

RE: UncleBob's annoying API questions

Posted: Sat Oct 29, 2011 4:55 pm
by Brianetta

UncleBob wrote:


Quote:
You want the IsPlayer() method. All Ship objects support it, and it's for exactly this situation. I've pasted the codedoc for your convenience:
That's exactly the problem, I don't get a ship object from onFocusChanged. I get a body object, and that has no isPlayer member...
All ships are bodies, so you could use Object.isa() to determine if it "is a" ship, then ask it if it's a player:
Code:
if body:isa("Ship") and body:isPlayer() then -- Whatever you do to players when frame changesend

RE: UncleBob's annoying API questions

Posted: Sun Oct 30, 2011 3:37 am
by UncleBob
so ship is kind of an inherited object of body, and i can access its members even from the parent object? Probably not, must have something to do with the loose way lua handles types. That's confusing the hell out of me... :?Anyways, thanks for the help!

RE: UncleBob's annoying API questions

Posted: Sun Oct 30, 2011 4:06 am
by robn

UncleBob wrote:
so ship is kind of an inherited object of body, and i can access its members even from the parent object? Probably not, must have something to do with the loose way lua handles types. That's confusing the hell out of me... :?
Its regular class inheritance, as you'd find in any normal OO language. A subclass is an object that builds on a more generic parent object.The object hierarchy for Pioneer's Lua engine is currently quite shallow. CargoBody, Planet, Ship, SpaceStation and Star all inherit from Body, and so all of Body's methods and attributes can be used against them. Additionally, Player inherits from Ship, so all of Ship's and Body's methods and attributes can be used on the player object.