Outerra forum

Please login or register.

Login with username, password and session length
Advanced search  

News:

Outerra Tech Demo download. Help with graphics driver issues

Pages: 1 2 [3] 4

Author Topic: can we create, place or throw custom made objects that have physics in outerra ?  (Read 5689 times)

fly77

  • Outerra Master Modder
  • Hero Member
  • *****
  • Posts: 1182

You won't have pdbs from the exe or c4e, but you should have a pdb for your own dll plugin.

I have the global_variables_plugin.pdb file in the same visual studio folder where the global_variables_plugin.dll has been created

still get the same degug call stack message  in c4e.dll and no other message. This time I could launch 3 missiles before crashing though.
after stopping debug...VS output continue sto show the c4e error message "Eccezione generata in corrispondenza di 0x0FF9B731 (c4e.dll) in outerra.exe: 0xC0000005: violazione di accesso durante la lettura del percorso 0x00000024."

maybe I'd better  consider seriously the missile as an aircraft (which seems also more natural) and define its flight behaviour using JSBSIM instead of vehicles extra_force command...allthough that requires me an "extra effort" to get more familiar with JSBSIM
« Last Edit: February 24, 2020, 03:05:18 pm by fly77 »
Logged

cameni

  • Brano Kemen
  • Outerra Administrator
  • Hero Member
  • *****
  • Posts: 6700
  • No sense of urgency.
    • outerra.com

This is the call stack I see (with VS 2019)



My bet is the global var plugin does something wrong in the creator method.
The difference between aircraft and vehicles is that every aircraft has a separate javascript context, and also a separate JSBSim instance. Because of that aicraft are memory (and cpu) hungry.

Vehicles of the same class share a lot of stuff, and also share a javascript context. It's the reason why there's init_chassis that's run once on the first vehicle instance, to initialize stuff that's common for all instances of given vehicle class. I'm not sure what your plugin does, but from its name it sounds like you'd bind it in init_chassis and set the return value into a global variable, for all instances to use?
Logged

cameni

  • Brano Kemen
  • Outerra Administrator
  • Hero Member
  • *****
  • Posts: 6700
  • No sense of urgency.
    • outerra.com

Also this may help you:
https://stackoverflow.com/questions/654696/how-to-debug-external-class-library-projects-in-visual-studio

In any case, when you attach the debugger, you should be able to put a breakpoint into your dll code and the debugger will stop there, and you can step through it - hopefully it will show the full stack in that case.
Logged

fly77

  • Outerra Master Modder
  • Hero Member
  • *****
  • Posts: 1182

Thank you. Will help me to learn something but to get things going in the meantime I will go the JSBSIM route.

Funny how with JSBSIM I can shoot many missiles that just keep flying around randomly by their own like sailplanes  ^-^   Need to give them some THRUST !

« Last Edit: February 24, 2020, 03:41:11 pm by fly77 »
Logged

andfly

  • Sr. Member
  • ****
  • Posts: 289

Another even more esoteric thought ...

When I built the models that used the "world.create_instance" I initially had some crash problems.
The instances were created in a "for-next" loop and (I assumed ) that the overlap of the instructions did not leave enough time for the method to be executed in full before the next call ... or (easier) than the creation of the new instance was carried out with coordinates too close to the previously created instance.
I had solved it by implementing a timer that forced the method to be executed no earlier than 0.5 seconds from the previous call.
This avoided overlapping the models.

You could try avoiding to execute the method in rapid succession or, better still, by varying the position under the wing where the missiles must appear:

 this.geom.get_world_pos_offset ({x: -15, y: 0, z: 4})

 (changing the value in x, different for each missile).
Logged
I do not know the English language. I use Google Translate. I hope it's all understandable.

fly77

  • Outerra Master Modder
  • Hero Member
  • *****
  • Posts: 1182

hmm...well I fire the missiles by pressing a button and I wait between consecutive launches. So I have no overlap between consecutive missiles. So that is not the  cause of the crashes in my case.
Then I tried also launching the missile from farther away as you say - for example this.geom.get_world_pos_offset({x:-24, y:0, z:-5})- just to be sure that the launched missile does not "overlap" with the plane.
This also does not change anything in the crashes. It is something related with the fact that the missile tries to get the plugin interface. Seems outerra doesn't like that too many vehicles created from a script  try to get the plugin interface. If I spawn the missiles from F3 as I said I also have no problem.
Same happens if instead of my global variables pluging I get the interface of the example-vehicle plugin..just as a test. So also it is not the special fault/mistake in my plugin as also the example vehicle plugin creates the same problem. Its also not a graphic overload problem as it does not happen when missiles don't try to get the plugin interface o rthey are spawned from F3
« Last Edit: February 24, 2020, 04:54:46 pm by fly77 »
Logged

cameni

  • Brano Kemen
  • Outerra Administrator
  • Hero Member
  • *****
  • Posts: 6700
  • No sense of urgency.
    • outerra.com

It's nothing with OT, the crash happens in your dll.
More specifically, it crashes in c4e that is given some gibberish js object from your dll. We have tests that create hundreds of objects and they work normally.
Can you show the code?
Logged

fly77

  • Outerra Master Modder
  • Hero Member
  • *****
  • Posts: 1182

Sure
here are simplugin.hpp and simplugin.cpp.
Note that I'd be glad to remove all lines of code except those related with read write to variables..but when I cancelled them I got errors in compiling. I got the code from republic of texas and it works without problems when I spawn the missile (getting the plugin) from F3

Code: [Select]
#pragma once

#include <comm/intergen/ifc.h>

//wrap in special comments to inject into the generated interface header too
// can also use /*ifc{ ... }ifc*/ to include only in the client header

//ifc{
#include <ot/vehicle_physics.h>
#include "ot/explosions.h"
#include "ot/environment.h"
#include "ot/canvas.h"

//}ifc

///Plugin's base implementation class, exposing a xt::engine interface
class simplugin
: public policy_intrusive_base
{
public:
simplugin();
~simplugin() {};

///Interface declaration: [namespace::]name, path
ifc_class(xt::global_variables, "ifc/");

///Interface creator
ifc_fnx(get) static iref<simplugin> get()
{
return new simplugin;
}

//interface function examples

ifc_fn double readDat(int index);
ifc_fn bool writeDat(int index, double data);



ifc_fn void writeEcef(int index, double x, double y, double z, int id);
ifc_fn double readEcefx(int index);
ifc_fn double readEcefy(int index);
ifc_fn double readEcefz(int index);
ifc_fn int readEcefId(int index);

ifc_fn void writeQuat(int index, double x, double y, double z, double w, int id);
ifc_fn double readQuatx(int index);
ifc_fn double readQuaty(int index);
ifc_fn double readQuatz(int index);
ifc_fn double readQuatw(int index);
ifc_fn int readQuatId(int index);



ifc_fn void init_chassis(iref<ot::vehicle_physics> obj);
ifc_fn void init_vehicle(iref<ot::vehicle_physics> obj);
ifc_fn void update_vehicle(float dt, float throttle, float brake, float steer);
ifc_fn void firething();
ifc_fn void turretthing(float v, float dt);
ifc_fn void mantletthing(float v, float dt);

private:
iref<ot::geomob> m_geomob;
iref<ot::sndgrp> m_sndgrp;
iref<ot::explosions> m_explosion;
iref<ot::environment> m_environment;
iref<ot::canvas> m_canvas;

int _counter;

iref<ot::vehicle_physics> _vehicle;
};


Code: [Select]
#pragma once

#include "simplugin.hpp"

#include "v8/v8.h"
#include <ot/vehicle_physics.h>
#include <ot/vehicle_cfg.h>
#include <ot/explosions.h>
#include <ot/environment.h>
#include <ot/canvas.h>
#include <ot/dynamic_object.h>
#include <ot/static_object.h>
#include <glm/gtc/quaternion.hpp>
#include <ot/location_cfg.h>
#include <algorithm>
#include <string>
#include <array>

ot::wheel wheel_params;
ot::vehicle_params physics_params;

const double PI = 3.141592653589793;
std::array<double, 100> globalData;
std::array<double, 100> globalLat;
std::array<double, 100> globalLon;
std::array<int, 100> globalId;

std::array<double, 100> globalEcefx;
std::array<double, 100> globalEcefy;
std::array<double, 100> globalEcefz;

std::array<double, 100> globalQuatx;
std::array<double, 100> globalQuaty;
std::array<double, 100> globalQuatz;
std::array<double, 100> globalQuatw;
std::array<int, 100> globalQuatId;

uint fnt ;
uint img ;
uint img2 ;
std::array<double,2> screensize;


double simplugin::readDat(int index)
{
return globalData[index];
}

bool simplugin::writeDat(int index, double data)
{

globalData[index] = data;
return true;

}



void simplugin::writeEcef(int index, double x, double y, double z, int id)
{
globalEcefx[index] = x;
globalEcefy[index] = y;
globalEcefz[index] = z;
globalId[index] = id;
}



double simplugin::readEcefx(int index)
{
return globalEcefx[index];

}


double simplugin::readEcefy(int index)
{
return globalEcefy[index];

}

double simplugin::readEcefz(int index)
{
return globalEcefz[index];

}


int simplugin::readEcefId(int index)
{
return globalId[index];

}


void simplugin::writeQuat(int index, double x, double y, double z, double w, int id)
{
globalQuatx[index] = x;
globalQuaty[index] = y;
globalQuatz[index] = z;
globalQuatw[index] = w;
globalQuatId[index] = id;
}


double simplugin::readQuatx(int index)
{
return globalQuatx[index];
}

double simplugin::readQuaty(int index)
{
return globalQuaty[index];
}

double simplugin::readQuatz(int index)
{
return globalQuatz[index];
}

double simplugin::readQuatw(int index)
{
return globalQuatw[index];
}

int simplugin::readQuatId(int index)
{
return globalQuatId[index];
}


quat Quatmult(quat q, quat p) {
quat r = quat(0, 0, 0, 0);
r.x = q.x * p.w + q.y * p.z + q.w * p.x - q.z * p.y;
r.y = q.z * p.x + q.w * p.y + q.y * p.w - q.x * p.z;
r.z = q.w * p.z + q.z * p.w + q.x * p.y - q.y * p.x;
r.w = -(q.y * p.y + q.x * p.x + q.z * p.z - q.w * p.w);
return r;
}

double rad2deg(double rad)
{
return rad * (180.f / PI);
}

double deg2rad(double deg)
{
return deg * (PI / 180.f);
}


simplugin::simplugin() {
m_sndgrp = ot::sndgrp::create();
}
float axle2coef = 1.f;

glm::quat toQuatRot(float angle, glm::vec3 axis) {
glm::quat returnQuat = glm::quat(0, 0, 0, 0);

returnQuat.x = axis.x * glm::sin(angle / 2);
returnQuat.y = axis.y * glm::sin(angle / 2);
returnQuat.z = axis.z * glm::sin(angle / 2);
returnQuat.w = glm::cos(angle / 2);
return returnQuat;
}


void simplugin::init_chassis(iref<ot::vehicle_physics> obj)
{
iref<ot::geomob> geomob = obj->get_geomob(0);
wheel_params.radius1 = 0.7f;
wheel_params.width = 0.45f;
wheel_params.differential = true;
wheel_params.suspension_max = 0.2f;
wheel_params.suspension_min = -0.35f;
wheel_params.suspension_stiffness = 5.f;
wheel_params.damping_compression = 0.2f;
wheel_params.damping_relaxation = 0.12f;
wheel_params.grip = 1.f;
wheel_params.slip_lateral_coef = 3;
obj->add_wheel_swing("halfaxle_l0", "tire_l0", wheel_params);
obj->add_wheel_swing("halfaxle_r0", "tire_r0", wheel_params);
obj->add_wheel_swing("halfaxle_l1", "tire_l1", wheel_params);
obj->add_wheel_swing("halfaxle_r1", "tire_r1", wheel_params);
obj->add_wheel_swing("halfaxle_l2", "tire_l2", wheel_params);
obj->add_wheel_swing("halfaxle_r2", "tire_r2", wheel_params);
obj->add_wheel_swing("halfaxle_l3", "tire_l3", wheel_params);
obj->add_wheel_swing("halfaxle_r3", "tire_r3", wheel_params);

float a0 = geomob->get_joint_model_pos(geomob->get_joint("tire_l0")).y;
float a1 = geomob->get_joint_model_pos(geomob->get_joint("tire_l1")).y;
float a2 = geomob->get_joint_model_pos(geomob->get_joint("tire_l2")).y;
float a3 = geomob->get_joint_model_pos(geomob->get_joint("tire_l3")).y;
float m = 0.5f * (a2 + a3);
axle2coef = (a1 - m) / (a0 - m);
}

void simplugin::init_vehicle(iref<ot::vehicle_physics> obj)
{

m_geomob = obj->get_geomob(0);
m_explosion = ot::explosions::get();
m_environment = ot::environment::get();
    m_canvas = ot::canvas::create("main");

fnt = m_canvas->load_font("ui/default.fnt");
img = m_canvas->load_image("ui/basic.imgset/airspeed");
img2 = m_canvas->load_image("ui/basic.imgset/airspeed_pointer");

screensize[0] = readDat(0); /* x */
screensize[1] = readDat(1);  /* y */




_vehicle = obj;
float3 offsetPos = float3(1, 1, 1);
double3 offset = m_geomob->get_world_pos_offset(offsetPos);
glm::quat rotation = m_geomob->get_rot();
auto firstbullet = m_explosion->launch_combo(offset, float3(75), 10, float3(1, 1, 0), float3(0.3, 0.3, 0.3), 7, 0.1, 0.1, 20, true, true, true);
m_explosion->destroy_tracer(firstbullet);
}

coid::uint exps;
quat QuatConjug(quat QuatIn) {
quat Quat = quat(0, 0, 0, 0);
Quat.x = -QuatIn.x;
Quat.y = -QuatIn.y;
Quat.z = -QuatIn.z;
Quat.w = QuatIn.w;
return Quat;
}
float turret_axis = 0, mantlet_axis = 0;
float turret_rot = 0, mantlet_rot = 0, armor_pitch = 0;

void simplugin::turretthing(float v, float dt)
{
turret_axis = -v;
}

void simplugin::mantletthing(float v, float dt)
{
mantlet_axis = v;
}

unsigned int index;
void simplugin::firething()
{
glm::vec3 mdc = glm::vec3(0, 0, 7);
double3 offset = m_geomob->get_world_pos_offset(mdc);

//mantlet_rot = std::max(0.f, std::min(0.5f, mantlet_rot));
_vehicle->log(coid::token((std::to_string(mantlet_rot) + " Hio").c_str()));
float armor_pitch = mantlet_rot;
float armor_azimuth = -turret_rot;


glm::quat cannonQuat = m_geomob->get_rot();
glm::quat unitquat = glm::quat(0, 1, 0, 0);  // default muzzle orientation
glm::quat pitchquat = toQuatRot(armor_pitch, glm::vec3(1, 0, 0));
glm::quat headquat = toQuatRot(armor_azimuth, glm::vec3(0, 0, 1));

glm::quat tempquat = Quatmult(pitchquat, Quatmult(unitquat, QuatConjug(pitchquat)));
tempquat = Quatmult(headquat, Quatmult(tempquat, QuatConjug(headquat)));
glm::quat plasmaquat = Quatmult(cannonQuat, Quatmult(tempquat, QuatConjug(cannonQuat)));

glm::quat bulletquat = Quatmult(cannonQuat, Quatmult(headquat, Quatmult(pitchquat, unitquat)));


auto bullet = ot::static_object::create("outerra/crate/crate", offset, bulletquat);

m_explosion->launch_tracer(offset, float3(827 * plasmaquat.x, 827 * plasmaquat.y, 827 * plasmaquat.z), 1, glm::vec3(1, 1, 0), 0.5, 0.2, 0, 0, 0, bullet->get_geomob(0)->get_eid(), 1);
}

float engine_force = 27000.f;
float brake_force = 28000.f;
float wheel_friction = 200.f;



void simplugin::update_vehicle(float dt, float throttle, float brake, float steer)
{

m_canvas->draw_text(fnt, screensize[0]/2, screensize[1] / 2,  "ciao", uchar4(0, 255, 0, 255));


float speed_kmh = _vehicle->speed();


float applied_engine_force = engine_force * abs(throttle);
_vehicle->wheel_force(-1, applied_engine_force);

_vehicle->steer(0, steer);
_vehicle->steer(1, steer);
_vehicle->steer(2, steer * axle2coef);
_vehicle->steer(3, steer * axle2coef);

float applied_wheel_friction = brake_force * brake + wheel_friction;
_vehicle->wheel_brake(-1, applied_wheel_friction);

for (ot::impact_info i : m_explosion->landed_tracers())
{
m_explosion->make_crater(i.wpos, 10);
}

turret_rot += turret_axis * 0.4 * dt;
mantlet_rot += mantlet_axis * 0.1 * dt;
}
« Last Edit: February 25, 2020, 04:31:33 am by fly77 »
Logged

andfly

  • Sr. Member
  • ****
  • Posts: 289

Yes, you're right, you said that the problem consisted in the continuous call of the plugin interface but I had forgotten about it fixing myself on the immediate aspects of the repeated creations ...

However...
Another possible even more esoteric trick ...

While waiting for Cameni to inspect your dll code, which has assured us that there is no interface call limit imposed by Outerra, we could try another way.
Instead of considering the characteristic of sharing the variables by instances of the same model as deleterious, we can try to exploit their advantages.

Instead of "this.plugin" we reuse the "plugin" variable which will go global for all missiles.

We put a preliminary check on the line of code that requires the interface.

function init_vehicle () {
...
if (! plugin) {
plugin = this. $ query_interface ('xt :: js :: global_variables.get');
}
...
}


The first missile, finding the variable still undefined, will make the call to the plugin interface, but all the others, created subsequently, will find the variable already defined and should not make the call but only use the "plugin" variable to read or write the values ​​you intend to share.

Since the call of a single missile does not block the program, the problem could be solved.
Logged
I do not know the English language. I use Google Translate. I hope it's all understandable.

fly77

  • Outerra Master Modder
  • Hero Member
  • *****
  • Posts: 1182

OK andfly I will try.

For cameni: note that the same happens with the default example vehicle dll downloaded from github when I add this line of code

Code: [Select]
function init_vehicle(){ 
  $plugin = this.$query_interface('xt::js::engine.create', this);
}

to the missile JS  and firing the missile from my tank through

world.create_instance("outerra/missile/missile", ecef,  bulletquat, false); 

I can fire two missiles from the tank but when firing the third one outerra crashes.
 Why two ? I was thinking that vehicles can be entered in two ways..first without animated character and second entry is with animated character...so there is "two" ways vehicles can be entered and two "vehicles" that I can fire. maybe the world.create_instance("outerra/missile/missile", ecef,  bulletquat, false) gets confused with these ways of entering vehicles. while F3 spawn doesn't
when I spawn the missile from F3 it always enters it "without animated character" ..but that's just a crazy theory as I can not imagine any reason of the "two" times working...and why there is no problem with "JSBSIM aircrafts" missiles

Code: [Select]
#pragma once

#include <comm/intergen/ifc.h>

//wrap in special comments to inject into the generated interface header too
// can also use /*ifc{ ... }ifc*/ to include only in the client header

//ifc{
#include <ot/vehicle_physics.h>
//}ifc

///Plugin's base implementation class, exposing a xt::engine interface
class simplugin
    : public policy_intrusive_base
{
public:

    simplugin(const iref<ot::vehicle_physics>& vehicle);

    ///Interface declaration: [namespace::]name, path
    ifc_class(xt::engine, "ifc/");   

    ///Interface creator
    ifc_fn static iref<simplugin> create(const iref<ot::vehicle_physics>& vehicle);


   

    //interface function examples

    ifc_fn void set_value( int x ) { _value = x; }

    ifc_fn int get_value() const { return _value; }

    ifc_fn void do_something();

private:

    int _value, _counter;

    iref<ot::vehicle_physics> _vehicle;
};



Code: [Select]
#pragma once

#include "simplugin.hpp"

#include <ot/vehicle_physics.h>


////////////////////////////////////////////////////////////////////////////////
simplugin::simplugin(const iref<ot::vehicle_physics>& vehicle)
    : _value(0), _counter(0)
{
    _vehicle = vehicle;
}

////////////////////////////////////////////////////////////////////////////////
iref<simplugin> simplugin::create(const iref<ot::vehicle_physics>& vehicle)
{
    DASSERT_RET(!vehicle.is_empty(), 0);

    return new simplugin(vehicle);
}

////////////////////////////////////////////////////////////////////////////////
void simplugin::do_something()
{
    //blink lights
    if (_vehicle)
        _vehicle->light_mask(UMAX32, (++_counter & 64) != 0);
}
« Last Edit: February 25, 2020, 05:18:35 am by fly77 »
Logged

fly77

  • Outerra Master Modder
  • Hero Member
  • *****
  • Posts: 1182

SOLVED !!

andfly your trick works !!


If I use inside the missile JS

Code: [Select]
     if (! $plugin) {
         $plugin = this.$query_interface('xt::js::engine.create', this);
      }

or

Code: [Select]
if (! $plugin) {
         $plugin = this.$query_interface('xt::js::global_variables.get');
}

I can now fire as many configurable missiles as I want !  No more crashes !

THANKS andfly !

Also learned something new: seems that "objects"  (or what is the plugin ?  an interface ? ...I am ashamed to be so ignorant but willing to learn) created inside JS appear to be global unless we put this. in front ..will experiment if this can be exploited and if it is also valid for other objects?  variables ? .


     
     
« Last Edit: February 25, 2020, 06:16:43 am by fly77 »
Logged

andfly

  • Sr. Member
  • ****
  • Posts: 289

Mmm ...

Verify that $plugin is truly shared and that all missiles can access the plugin.

To my knowledge only vehicle and boat models (possessing an init_chassis function that is performed a unique way and only for the first instance) can share variables.
If the variable is also shared by instances of a Jsbsim model, a new magnificent scenario opens which I am not aware of and which widens the possibilities of interaction.

The curiosity was whether the trick worked with instances of a vehicle model ...


However I thought it would be interesting to do other tests too.

Try to create (with create_instance), in the main model script (the plane), a dozen different models (missile, bomb, tank, etc.), then NOT instances of the same model, which try to recall the interface of the plugin and check if it gets to the block of the program.

Then, also, try to create successive instances of the same missile (as originally) but, in the missile code, request the interface of one of the main modules of Outerra (such as world or canvas or explosion etc ..) and check if there is they are problems.

We do not know how the code relating to numerous instances of the same model is compiled and stored. While there seems to be no limit to the amount of mathematical and graphical code there may be a particular procedure for recording the connections to the interfaces that could possibly be "unique" for each model and the subsequent attempt to redefine them in each instance could create problems ...

If, however, we notice substantial differences in the treatment of interface calls between personal plugins and Outerra modules, then ... our plugins are missing something or have imperfections that differentiate them from the well-structured Outerra code and limit their potential.

On the other hand .... if even the request for an interface to an Outerra module by successive instances of the missiles, causes the crash ... perhaps the responsibility could be attributed to the world_create_instance method which would not carry out a complete creation like that carried out by creating new instances directly from the main menu of Outerra ...
The fact that from the Outerra menu you can create a large number of instances of the same model, without any problem, suggests ...
« Last Edit: February 25, 2020, 07:19:59 am by andfly »
Logged
I do not know the English language. I use Google Translate. I hope it's all understandable.

cameni

  • Brano Kemen
  • Outerra Administrator
  • Hero Member
  • *****
  • Posts: 6700
  • No sense of urgency.
    • outerra.com

Yeah, like I wrote yesterday: vehicles share the JS context. That means you overwrote the $plugin variable each time you set to it in init_vehicle, which runs for each new vehicle but in the same JS context. The old value (a reference to interface) got orphaned and thrown to he garbage collector. Not sure why it crashed, but perhaps something to do with the global plugin interface being repeatedly created and destroyed.

Do it just once in init_chassis.

(By setting it into this.$plugin you made a copy for each vehicle instance, which works but it's a waste for global/shared stuff).

Also we need to implement a better crash catcher that shows which plugin crashed, otherwise we'd be getting "OT crashed" reports all the time :)
Logged

andfly

  • Sr. Member
  • ****
  • Posts: 289

Do it just once in init_chassis.

Here is the egg of Columbus.
The simplest and most elegant solution.  8)
Logged
I do not know the English language. I use Google Translate. I hope it's all understandable.

fly77

  • Outerra Master Modder
  • Hero Member
  • *****
  • Posts: 1182

Right !

but about "vehicles share the same JS context" : i tried to set a variable var $myvariable =100; in one vehicle (the t817 of outerra root directory) and then read it in a vehicle of another type (my tank in my packages folder) but it does get $myvariable undefined. If I remember well the context of shared variables was just for HTML (like config.HTML) ..maybe just vehicles of same type.

for andfly: yes I can create lots of different models each one using the same plugin. worked fine !

 
Code: [Select]
this.ot_world.create_instance("outerra/t817/t817", this.geom.get_world_pos_offset({x:+0, y:0, z:-20}), this.geom.get_rot(), false);

      this.ot_world.create_instance("outerra/c172/liveries/Red/Red", this.geom.get_world_pos_offset({x:+40, y:0, z:1}), this.geom.get_rot(), false);

      this.ot_world.create_instance("outerra/missile3/missile3", this.geom.get_world_pos_offset({x:-4, y:0, z:-1}), this.geom.get_rot(), false); 
 
      this.ot_world.create_instance("outerra/missile2/missile2", this.geom.get_world_pos_offset({x:-40, y:0, z:-1}), this.geom.get_rot(), false); 
 
« Last Edit: February 25, 2020, 08:29:10 am by fly77 »
Logged
Pages: 1 2 [3] 4