Vivian Meazza:
This patch is a combined effort by Gregor Richards, Oliver Schroeder, and Vivian Meazza (and code cleanups and improvements by Erik Hofman). It corrects the bug in which a Multiplayer model responds to local inputs, and the view number bug which caused certain aircraft to appear as cockpit only models. It passes remote properties over the net, and all major control surfaces and gear are now animated correctly, providing that the local ~model.xml file contains no leading "/" in the <property></property> data entries. MP objects are now extrapolated using 1st and 2nd derivatives to make their movement appear more smooth. The sim is now halted while a new client joins the net. Known problems with MP are non-display of the remote client under certain circumstances of starting/resetting, and a freeze on starting. These bugs are long standing, and are not addressed by this patch. Special thanks must go to AJ Macleod for his patient testing of this patch over many evenings. We have also moved part of multiplayer into AIModels as part of the ongoing development of MP.
This commit is contained in:
parent
ab7a594dab
commit
5bd2ef1edb
16 changed files with 1251 additions and 111 deletions
1
Thanks
1
Thanks
|
@ -622,6 +622,7 @@ Roy Vegard Ovesen <rvovesen@tiscali.no>
|
||||||
|
|
||||||
|
|
||||||
Stuart Buchanan <stuart_d_buchanan@yahoo.co.uk>
|
Stuart Buchanan <stuart_d_buchanan@yahoo.co.uk>
|
||||||
|
Substantial additions to the Getting Started Manual
|
||||||
Enhancements to the Cessna-310 3d model.
|
Enhancements to the Cessna-310 3d model.
|
||||||
Added a generic yoke model, a generic throttle quadrant model and a
|
Added a generic yoke model, a generic throttle quadrant model and a
|
||||||
generic pedal set model.
|
generic pedal set model.
|
||||||
|
|
|
@ -56,7 +56,7 @@ FGAIBase::FGAIBase()
|
||||||
_refID( _newAIModelID() )
|
_refID( _newAIModelID() )
|
||||||
{
|
{
|
||||||
_type_str = "model";
|
_type_str = "model";
|
||||||
tgt_heading = tgt_altitude = tgt_speed = 0.0;
|
tgt_heading = hdg = tgt_altitude = tgt_speed = 0.0;
|
||||||
tgt_roll = roll = tgt_pitch = tgt_yaw = tgt_vs = vs = pitch = 0.0;
|
tgt_roll = roll = tgt_pitch = tgt_yaw = tgt_vs = vs = pitch = 0.0;
|
||||||
bearing = elevation = range = rdot = 0.0;
|
bearing = elevation = range = rdot = 0.0;
|
||||||
x_shift = y_shift = rotation = 0.0;
|
x_shift = y_shift = rotation = 0.0;
|
||||||
|
|
|
@ -113,7 +113,7 @@ public:
|
||||||
inline const Point3D& GetPos() const { return(pos); }
|
inline const Point3D& GetPos() const { return(pos); }
|
||||||
|
|
||||||
enum object_type { otNull = 0, otAircraft, otShip, otCarrier, otBallistic,
|
enum object_type { otNull = 0, otAircraft, otShip, otCarrier, otBallistic,
|
||||||
otRocket, otStorm, otThermal, otStatic,
|
otRocket, otStorm, otThermal, otStatic, otMultiplayer,
|
||||||
MAX_OBJECTS }; // Needs to be last!!!
|
MAX_OBJECTS }; // Needs to be last!!!
|
||||||
|
|
||||||
virtual bool init();
|
virtual bool init();
|
||||||
|
@ -127,6 +127,7 @@ public:
|
||||||
void setLatitude( double latitude );
|
void setLatitude( double latitude );
|
||||||
void setLongitude( double longitude );
|
void setLongitude( double longitude );
|
||||||
void setBank( double bank );
|
void setBank( double bank );
|
||||||
|
void setPitch( double newpitch );
|
||||||
void setRadius ( double radius );
|
void setRadius ( double radius );
|
||||||
void setXoffset( double x_offset );
|
void setXoffset( double x_offset );
|
||||||
void setYoffset( double y_offset );
|
void setYoffset( double y_offset );
|
||||||
|
@ -273,6 +274,10 @@ inline void FGAIBase::setBank( double bank ) {
|
||||||
no_roll = false;
|
no_roll = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void FGAIBase::setPitch( double newpitch ) {
|
||||||
|
pitch = tgt_pitch = newpitch;
|
||||||
|
}
|
||||||
|
|
||||||
inline void FGAIBase::setLongitude( double longitude ) {
|
inline void FGAIBase::setLongitude( double longitude ) {
|
||||||
pos.setlon( longitude );
|
pos.setlon( longitude );
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include "AIThermal.hxx"
|
#include "AIThermal.hxx"
|
||||||
#include "AICarrier.hxx"
|
#include "AICarrier.hxx"
|
||||||
#include "AIStatic.hxx"
|
#include "AIStatic.hxx"
|
||||||
|
#include "AIMultiplayer.hxx"
|
||||||
|
|
||||||
SG_USING_STD(list);
|
SG_USING_STD(list);
|
||||||
|
|
||||||
|
@ -192,6 +193,23 @@ FGAIManager::createAircraft( FGAIModelEntity *entity, FGAISchedule *ref) {
|
||||||
return ai_plane;
|
return ai_plane;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
FGAIManager::createMultiplayer( FGAIModelEntity *entity ) {
|
||||||
|
|
||||||
|
FGAIMultiplayer* ai_plane = new FGAIMultiplayer(this);
|
||||||
|
ai_list.push_back(ai_plane);
|
||||||
|
++numObjects[0];
|
||||||
|
++numObjects[FGAIBase::otMultiplayer];
|
||||||
|
ai_plane->setAcType(entity->acType);
|
||||||
|
ai_plane->setCompany(entity->company);
|
||||||
|
ai_plane->setPath(entity->path.c_str());
|
||||||
|
|
||||||
|
ai_plane->init();
|
||||||
|
ai_plane->bind();
|
||||||
|
return ai_plane;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void*
|
void*
|
||||||
FGAIManager::createShip( FGAIModelEntity *entity ) {
|
FGAIManager::createShip( FGAIModelEntity *entity ) {
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,7 @@ public:
|
||||||
|
|
||||||
void* createBallistic( FGAIModelEntity *entity );
|
void* createBallistic( FGAIModelEntity *entity );
|
||||||
void* createAircraft( FGAIModelEntity *entity, FGAISchedule *ref=0 );
|
void* createAircraft( FGAIModelEntity *entity, FGAISchedule *ref=0 );
|
||||||
|
void* createMultiplayer( FGAIModelEntity *entity );
|
||||||
void* createThermal( FGAIModelEntity *entity );
|
void* createThermal( FGAIModelEntity *entity );
|
||||||
void* createStorm( FGAIModelEntity *entity );
|
void* createStorm( FGAIModelEntity *entity );
|
||||||
void* createShip( FGAIModelEntity *entity );
|
void* createShip( FGAIModelEntity *entity );
|
||||||
|
|
278
src/AIModel/AIMultiplayer.cxx
Executable file
278
src/AIModel/AIMultiplayer.cxx
Executable file
|
@ -0,0 +1,278 @@
|
||||||
|
// FGAIMultiplayer - FGAIBase-derived class creates an AI multiplayer aircraft
|
||||||
|
//
|
||||||
|
// Based on FGAIAircraft
|
||||||
|
// Written by David Culp, started October 2003.
|
||||||
|
// Also by Gregor Richards, started December 2005.
|
||||||
|
// With additions by Vivian Meazza, January 2006
|
||||||
|
//
|
||||||
|
// Copyright (C) 2003 David P. Culp - davidculp2@comcast.net
|
||||||
|
// Copyright (C) 2005 Gregor Richards
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <simgear/math/point3d.hxx>
|
||||||
|
#include <Main/fg_props.hxx>
|
||||||
|
#include <Main/globals.hxx>
|
||||||
|
#include <Main/viewer.hxx>
|
||||||
|
#include <Scenery/scenery.hxx>
|
||||||
|
#include <Scenery/tilemgr.hxx>
|
||||||
|
#include <simgear/route/waypoint.hxx>
|
||||||
|
#include <string>
|
||||||
|
#include <math.h>
|
||||||
|
#include <time.h>
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# include <float.h>
|
||||||
|
# define finite _finite
|
||||||
|
#elif defined(__sun) || defined(sgi)
|
||||||
|
# include <ieeefp.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SG_USING_STD(string);
|
||||||
|
|
||||||
|
#include "AIMultiplayer.hxx"
|
||||||
|
static string tempReg;
|
||||||
|
|
||||||
|
|
||||||
|
FGAIMultiplayer::FGAIMultiplayer(FGAIManager* mgr) {
|
||||||
|
manager = mgr;
|
||||||
|
_type_str = "multiplayer";
|
||||||
|
_otype = otMultiplayer;
|
||||||
|
|
||||||
|
_time_node = fgGetNode("/sim/time/elapsed-sec", true);
|
||||||
|
|
||||||
|
//initialise values
|
||||||
|
speedN = speedE = rateH = rateR = rateP = 0.0;
|
||||||
|
raw_hdg = hdg;
|
||||||
|
raw_roll = roll;
|
||||||
|
raw_pitch = pitch;
|
||||||
|
raw_speed_east_deg_sec = speedE / ft_per_deg_lon;
|
||||||
|
raw_speed_north_deg_sec = speedN / ft_per_deg_lat;
|
||||||
|
raw_lon = damp_lon = pos.lon();
|
||||||
|
raw_lat = damp_lat = pos.lat();
|
||||||
|
raw_alt = damp_alt = pos.elev() / SG_FEET_TO_METER;
|
||||||
|
|
||||||
|
//Exponentially weighted moving average time constants
|
||||||
|
speed_north_deg_sec_constant = speed_east_deg_sec_constant = 0.1;
|
||||||
|
alt_constant = 0.1;
|
||||||
|
lat_constant = 0.05;
|
||||||
|
lon_constant = 0.05;
|
||||||
|
hdg_constant = 0.1;
|
||||||
|
roll_constant = 0.1;
|
||||||
|
pitch_constant = 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FGAIMultiplayer::~FGAIMultiplayer() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool FGAIMultiplayer::init() {
|
||||||
|
return FGAIBase::init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAIMultiplayer::bind() {
|
||||||
|
FGAIBase::bind();
|
||||||
|
props->setStringValue("callsign", company.c_str());
|
||||||
|
|
||||||
|
props->tie("controls/constants/roll",
|
||||||
|
SGRawValuePointer<double>(&roll_constant));
|
||||||
|
props->tie("controls/constants/pitch",
|
||||||
|
SGRawValuePointer<double>(&pitch_constant));
|
||||||
|
props->tie("controls/constants/hdg",
|
||||||
|
SGRawValuePointer<double>(&hdg_constant));
|
||||||
|
props->tie("controls/constants/altitude",
|
||||||
|
SGRawValuePointer<double>(&alt_constant));
|
||||||
|
/*props->tie("controls/constants/speedE",
|
||||||
|
SGRawValuePointer<double>(&speed_east_deg_sec_constant));
|
||||||
|
props->tie("controls/constants/speedN",
|
||||||
|
SGRawValuePointer<double>(&speed_north_deg_sec_constant));*/
|
||||||
|
props->tie("controls/constants/lat",
|
||||||
|
SGRawValuePointer<double>(&lat_constant));
|
||||||
|
props->tie("controls/constants/lon",
|
||||||
|
SGRawValuePointer<double>(&lon_constant));
|
||||||
|
props->tie("surface-positions/rudder-pos-norm",
|
||||||
|
SGRawValuePointer<double>(&rudder));
|
||||||
|
props->tie("surface-positions/elevator-pos-norm",
|
||||||
|
SGRawValuePointer<double>(&elevator));
|
||||||
|
props->tie("velocities/speedE-fps",
|
||||||
|
SGRawValuePointer<double>(&speedE));
|
||||||
|
|
||||||
|
|
||||||
|
props->setDoubleValue("sim/current-view/view-number", 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAIMultiplayer::setCompany(string comp) {
|
||||||
|
company = comp;
|
||||||
|
if (props)
|
||||||
|
props->setStringValue("callsign", company.c_str());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAIMultiplayer::unbind() {
|
||||||
|
FGAIBase::unbind();
|
||||||
|
|
||||||
|
props->untie("controls/constants/roll");
|
||||||
|
props->untie("controls/constants/pitch");
|
||||||
|
props->untie("controls/constants/hdg");
|
||||||
|
props->untie("controls/constants/altitude");
|
||||||
|
/*props->untie("controls/constants/speedE");
|
||||||
|
props->untie("controls/constants/speedN");*/
|
||||||
|
props->untie("controls/constants/lat");
|
||||||
|
props->untie("controls/constants/lon");
|
||||||
|
props->untie("surface-positions/rudder-pos-norm");
|
||||||
|
props->untie("surface-positions/elevator-pos-norm");
|
||||||
|
props->untie("velocities/speedE-fps");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FGAIMultiplayer::update(double dt) {
|
||||||
|
|
||||||
|
FGAIBase::update(dt);
|
||||||
|
Run(dt);
|
||||||
|
Transform();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FGAIMultiplayer::Run(double dt) {
|
||||||
|
|
||||||
|
// strangely, this is called with a dt of 0 quite often
|
||||||
|
|
||||||
|
SG_LOG( SG_GENERAL, SG_DEBUG, "AIMultiplayer::main loop dt " << dt ) ;
|
||||||
|
|
||||||
|
//if (dt == 0) return;
|
||||||
|
|
||||||
|
//FGAIMultiplayer::dt = dt;
|
||||||
|
|
||||||
|
//double rhr, rha; // "real" heading radius/angle
|
||||||
|
|
||||||
|
// get the current sim elapsed time
|
||||||
|
double time =_time_node->getDoubleValue(); //secs
|
||||||
|
|
||||||
|
dt = 0;
|
||||||
|
|
||||||
|
//calulate the time difference, dt. Then use this value to extrapolate position and orientation
|
||||||
|
dt = time - time_stamp;
|
||||||
|
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG, "time: "
|
||||||
|
<< time << " timestamp: " << time_stamp << " dt: " << dt << " freq Hz: " << 1/dt);
|
||||||
|
|
||||||
|
// change heading/roll/pitch
|
||||||
|
raw_hdg = hdg + rateH * dt;
|
||||||
|
raw_roll = roll + rateR * dt;
|
||||||
|
raw_pitch = pitch + rateP * dt;
|
||||||
|
|
||||||
|
//apply lowpass filters
|
||||||
|
hdg = (raw_hdg * hdg_constant) + (hdg * (1 - hdg_constant));
|
||||||
|
roll = (raw_roll * roll_constant) + (roll * (1 - roll_constant));
|
||||||
|
pitch = (raw_pitch * pitch_constant) + (pitch * (1 - pitch_constant));
|
||||||
|
|
||||||
|
/*cout << "raw roll " << raw_roll <<" damp hdg " << roll << endl;
|
||||||
|
cout << "raw hdg" << raw_hdg <<" damp hdg " << hdg << endl;
|
||||||
|
cout << "raw pitch " << raw_pitch <<" damp pitch " << pitch << endl;*/
|
||||||
|
|
||||||
|
// sanitize HRP
|
||||||
|
while (hdg < 0) hdg += 360;
|
||||||
|
while (hdg >= 360) hdg -= 360;
|
||||||
|
while (roll <= -180) roll += 360;
|
||||||
|
while (roll > 180) roll -= 360;
|
||||||
|
while (pitch <= -180) pitch += 360;
|
||||||
|
while (pitch > 180) pitch -= 360;
|
||||||
|
|
||||||
|
// calculate the new accelerations by change in the rate of heading
|
||||||
|
/*rhr = sqrt(pow(accN,2) + pow(accE,2));
|
||||||
|
rha = atan2(accN, accE);
|
||||||
|
rha += rateH * dt;
|
||||||
|
accN = sin(rha);
|
||||||
|
accE = cos(rha);*/
|
||||||
|
|
||||||
|
// calculate new speed by acceleration
|
||||||
|
speedN += accN * dt;
|
||||||
|
speedE += accE * dt;
|
||||||
|
speedD += accD * dt;
|
||||||
|
|
||||||
|
// convert speed to degrees per second
|
||||||
|
// 1.686
|
||||||
|
speed_north_deg_sec = speedN / ft_per_deg_lat;
|
||||||
|
speed_east_deg_sec = speedE / ft_per_deg_lon;
|
||||||
|
|
||||||
|
// calculate new position by speed
|
||||||
|
raw_lat = pos.lat() + speed_north_deg_sec * dt;
|
||||||
|
raw_lon = pos.lon() + speed_east_deg_sec * dt ;
|
||||||
|
raw_alt = (pos.elev() / SG_FEET_TO_METER) + (speedD * dt);
|
||||||
|
|
||||||
|
//apply lowpass filters if the difference is small
|
||||||
|
if ( fabs ( pos.lat() - raw_lat) < 0.001 ) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG,"lat lowpass filter");
|
||||||
|
damp_lat = (raw_lat * lat_constant) + (damp_lat * (1 - lat_constant));
|
||||||
|
}else {
|
||||||
|
// skip the filter
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG,"lat high pass filter");
|
||||||
|
damp_lat = raw_lat;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( fabs ( pos.lon() - raw_lon) < 0.001 ) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG,"lon lowpass filter");
|
||||||
|
damp_lon = (raw_lon * lon_constant) + (damp_lon * (1 - lon_constant));
|
||||||
|
}else {
|
||||||
|
// skip the filter
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG,"lon high pass filter");
|
||||||
|
damp_lon = raw_lon;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( fabs ( (pos.elev()/SG_FEET_TO_METER) - raw_alt) < 10 ) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG,"alt lowpass filter");
|
||||||
|
damp_alt = (raw_alt * alt_constant) + (damp_alt * (1 - alt_constant));
|
||||||
|
}else {
|
||||||
|
// skip the filter
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG,"alt high pass filter");
|
||||||
|
damp_alt = raw_alt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cout << "raw lat" << raw_lat <<" damp lat " << damp_lat << endl;
|
||||||
|
//cout << "raw lon" << raw_lon <<" damp lon " << damp_lon << endl;
|
||||||
|
//cout << "raw alt" << raw_alt <<" damp alt " << damp_alt << endl;
|
||||||
|
|
||||||
|
// set new position
|
||||||
|
pos.setlat( damp_lat );
|
||||||
|
pos.setlon( damp_lon );
|
||||||
|
pos.setelev( damp_alt * SG_FEET_TO_METER );
|
||||||
|
|
||||||
|
//save the values
|
||||||
|
time_stamp = time;
|
||||||
|
|
||||||
|
//###########################//
|
||||||
|
// do calculations for radar //
|
||||||
|
//###########################//
|
||||||
|
//double range_ft2 = UpdateRadar(manager);
|
||||||
|
}
|
||||||
|
void FGAIMultiplayer::setTimeStamp()
|
||||||
|
{
|
||||||
|
// this function sets the timestamp as the sim elapsed time
|
||||||
|
time_stamp = _time_node->getDoubleValue(); //secs
|
||||||
|
|
||||||
|
//calculate the elapsed time since the latst update for display purposes only
|
||||||
|
double elapsed_time = time_stamp - last_time_stamp;
|
||||||
|
|
||||||
|
SG_LOG( SG_GENERAL, SG_DEBUG, " net input time s" << time_stamp << " freq Hz: " << 1/elapsed_time ) ;
|
||||||
|
|
||||||
|
//save the values
|
||||||
|
last_time_stamp = time_stamp;
|
||||||
|
}
|
||||||
|
|
101
src/AIModel/AIMultiplayer.hxx
Executable file
101
src/AIModel/AIMultiplayer.hxx
Executable file
|
@ -0,0 +1,101 @@
|
||||||
|
// FGAIMultiplayer - AIBase derived class creates an AI multiplayer aircraft
|
||||||
|
//
|
||||||
|
// Written by David Culp, started October 2003.
|
||||||
|
// With additions by Vivian Meazza
|
||||||
|
//
|
||||||
|
// Copyright (C) 2003 David P. Culp - davidculp2@comcast.net
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
|
||||||
|
#ifndef _FG_AIMultiplayer_HXX
|
||||||
|
#define _FG_AIMultiplayer_HXX
|
||||||
|
|
||||||
|
#include "AIManager.hxx"
|
||||||
|
#include "AIBase.hxx"
|
||||||
|
|
||||||
|
//#include <Traffic/SchedFlight.hxx>
|
||||||
|
//#include <Traffic/Schedule.hxx>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
SG_USING_STD(string);
|
||||||
|
|
||||||
|
|
||||||
|
class FGAIMultiplayer : public FGAIBase {
|
||||||
|
|
||||||
|
public:
|
||||||
|
FGAIMultiplayer(FGAIManager* mgr);
|
||||||
|
~FGAIMultiplayer();
|
||||||
|
|
||||||
|
bool init();
|
||||||
|
virtual void bind();
|
||||||
|
virtual void unbind();
|
||||||
|
void update(double dt);
|
||||||
|
|
||||||
|
|
||||||
|
void setSpeedN(double sn);
|
||||||
|
void setSpeedE(double se);
|
||||||
|
void setSpeedD(double sd);
|
||||||
|
void setAccN(double an);
|
||||||
|
void setAccE(double ae);
|
||||||
|
void setAccD(double ad);
|
||||||
|
void setRateH(double rh);
|
||||||
|
void setRateR(double rr);
|
||||||
|
void setRateP(double rp);
|
||||||
|
void setRudder( double r ) { rudder = r;}
|
||||||
|
void setElevator( double e ) { elevator = e; }
|
||||||
|
void setLeftAileron( double la ) { left_aileron = la; }
|
||||||
|
void setRightAileron( double ra ) { right_aileron = ra; }
|
||||||
|
void setTimeStamp();
|
||||||
|
|
||||||
|
inline SGPropertyNode *FGAIMultiplayer::getProps() { return props; }
|
||||||
|
|
||||||
|
void setAcType(string ac) { acType = ac; };
|
||||||
|
void setCompany(string comp);
|
||||||
|
|
||||||
|
double dt;
|
||||||
|
double speedN, speedE, speedD;
|
||||||
|
double rateH, rateR, rateP;
|
||||||
|
double raw_hdg , raw_roll , raw_pitch ;
|
||||||
|
double raw_speed_north_deg_sec, raw_speed_east_deg_sec;
|
||||||
|
double raw_lat, damp_lat, lat_constant;
|
||||||
|
double raw_lon, damp_lon, lon_constant;
|
||||||
|
double raw_alt, damp_alt, alt_constant;
|
||||||
|
double hdg_constant, roll_constant, pitch_constant;
|
||||||
|
double speed_north_deg_sec_constant, speed_east_deg_sec_constant;
|
||||||
|
double speed_north_deg_sec, speed_east_deg_sec;
|
||||||
|
double accN, accE, accD;
|
||||||
|
double rudder, elevator, left_aileron, right_aileron;
|
||||||
|
double time_stamp, last_time_stamp;
|
||||||
|
|
||||||
|
SGPropertyNode_ptr _time_node;
|
||||||
|
|
||||||
|
void Run(double dt);
|
||||||
|
inline double sign(double x) { return (x < 0.0) ? -1.0 : 1.0; }
|
||||||
|
|
||||||
|
string acType;
|
||||||
|
string company;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void FGAIMultiplayer::setSpeedN(double sn) { speedN = sn; }
|
||||||
|
inline void FGAIMultiplayer::setSpeedE(double se) { speedE = se; }
|
||||||
|
inline void FGAIMultiplayer::setSpeedD(double sd) { speedD = sd; }
|
||||||
|
inline void FGAIMultiplayer::setAccN(double an) { accN = an; }
|
||||||
|
inline void FGAIMultiplayer::setAccE(double ae) { accE = ae; }
|
||||||
|
inline void FGAIMultiplayer::setAccD(double ad) { accD = ad; }
|
||||||
|
inline void FGAIMultiplayer::setRateH(double rh) { rateH = rh; }
|
||||||
|
inline void FGAIMultiplayer::setRateR(double rr) { rateR = rr; }
|
||||||
|
inline void FGAIMultiplayer::setRateP(double rp) { rateP = rp; }
|
||||||
|
|
||||||
|
#endif // _FG_AIMultiplayer_HXX
|
|
@ -5,6 +5,7 @@ libAIModel_a_SOURCES = \
|
||||||
AIManager.hxx AIManager.cxx \
|
AIManager.hxx AIManager.cxx \
|
||||||
AIBase.hxx AIBase.cxx \
|
AIBase.hxx AIBase.cxx \
|
||||||
AIAircraft.hxx AIAircraft.cxx \
|
AIAircraft.hxx AIAircraft.cxx \
|
||||||
|
AIMultiplayer.hxx AIMultiplayer.cxx \
|
||||||
AIShip.hxx AIShip.cxx \
|
AIShip.hxx AIShip.cxx \
|
||||||
AIBallistic.hxx AIBallistic.cxx \
|
AIBallistic.hxx AIBallistic.cxx \
|
||||||
AIStorm.hxx AIStorm.cxx \
|
AIStorm.hxx AIStorm.cxx \
|
||||||
|
|
|
@ -96,12 +96,12 @@ FGGlobals::FGGlobals() :
|
||||||
FGGlobals::~FGGlobals()
|
FGGlobals::~FGGlobals()
|
||||||
{
|
{
|
||||||
delete soundmgr;
|
delete soundmgr;
|
||||||
|
delete io;
|
||||||
delete subsystem_mgr;
|
delete subsystem_mgr;
|
||||||
delete event_mgr;
|
delete event_mgr;
|
||||||
delete initial_state;
|
delete initial_state;
|
||||||
delete props;
|
delete props;
|
||||||
delete commands;
|
delete commands;
|
||||||
delete io;
|
|
||||||
delete renderer;
|
delete renderer;
|
||||||
delete initial_waypoints;
|
delete initial_waypoints;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
// Written by Duncan McCreanor, started February 2003.
|
// Written by Duncan McCreanor, started February 2003.
|
||||||
// duncan.mccreanor@airservicesaustralia.com
|
// duncan.mccreanor@airservicesaustralia.com
|
||||||
//
|
//
|
||||||
|
// With minor additions be Vivian Meazza, January 2006
|
||||||
|
//
|
||||||
// Copyright (C) 2003 Airservices Australia
|
// Copyright (C) 2003 Airservices Australia
|
||||||
//
|
//
|
||||||
// This program is free software; you can redistribute it and/or
|
// This program is free software; you can redistribute it and/or
|
||||||
|
@ -47,14 +49,17 @@ const uint32_t PROTO_VER = 0x00010001; // 1.1
|
||||||
// Message identifiers
|
// Message identifiers
|
||||||
#define CHAT_MSG_ID 1
|
#define CHAT_MSG_ID 1
|
||||||
#define UNUSABLE_POS_DATA_ID 2
|
#define UNUSABLE_POS_DATA_ID 2
|
||||||
#define POS_DATA_ID 3
|
#define OLD_POS_DATA_ID 3
|
||||||
|
#define POS_DATA_ID 4
|
||||||
|
#define PROP_MSG_ID 5
|
||||||
|
|
||||||
// XDR demands 4 byte alignment, but some compilers use8 byte alignment
|
// XDR demands 4 byte alignment, but some compilers use8 byte alignment
|
||||||
// so it's safe to let the overall size of a netmork message be a
|
// so it's safe to let the overall size of a network message be a
|
||||||
// multiple of 8!
|
// multiple of 8!
|
||||||
#define MAX_CALLSIGN_LEN 8
|
#define MAX_CALLSIGN_LEN 8
|
||||||
#define MAX_CHAT_MSG_LEN 48
|
#define MAX_CHAT_MSG_LEN 256
|
||||||
#define MAX_MODEL_NAME_LEN 48
|
#define MAX_MODEL_NAME_LEN 96
|
||||||
|
#define MAX_PROPERTY_LEN 52
|
||||||
|
|
||||||
/** Aircraft position message */
|
/** Aircraft position message */
|
||||||
typedef xdr_data2_t xdrPosition[3];
|
typedef xdr_data2_t xdrPosition[3];
|
||||||
|
@ -66,7 +71,7 @@ public:
|
||||||
xdr_data_t Magic; // Magic Value
|
xdr_data_t Magic; // Magic Value
|
||||||
xdr_data_t Version; // Protocoll version
|
xdr_data_t Version; // Protocoll version
|
||||||
xdr_data_t MsgId; // Message identifier
|
xdr_data_t MsgId; // Message identifier
|
||||||
xdr_data_t MsgLen; // absolue length of message
|
xdr_data_t MsgLen; // absolute length of message
|
||||||
xdr_data_t ReplyAddress; // (player's receiver address
|
xdr_data_t ReplyAddress; // (player's receiver address
|
||||||
xdr_data_t ReplyPort; // player's receiver port
|
xdr_data_t ReplyPort; // player's receiver port
|
||||||
char Callsign[MAX_CALLSIGN_LEN]; // Callsign used by the player
|
char Callsign[MAX_CALLSIGN_LEN]; // Callsign used by the player
|
||||||
|
@ -82,8 +87,39 @@ public:
|
||||||
class T_PositionMsg {
|
class T_PositionMsg {
|
||||||
public:
|
public:
|
||||||
char Model[MAX_MODEL_NAME_LEN]; // Name of the aircraft model
|
char Model[MAX_MODEL_NAME_LEN]; // Name of the aircraft model
|
||||||
xdrPosition PlayerPosition; // players position
|
xdr_data_t time; // Time when this packet was generated
|
||||||
xdrOrientation PlayerOrientation; // players orientation
|
xdr_data_t timeusec; // Microsecs when this packet was generated
|
||||||
|
xdr_data2_t lat; // Position, orientation, speed
|
||||||
|
xdr_data2_t lon; // ...
|
||||||
|
xdr_data2_t alt; // ...
|
||||||
|
xdr_data2_t hdg; // ...
|
||||||
|
xdr_data2_t roll; // ...
|
||||||
|
xdr_data2_t pitch; // ...
|
||||||
|
xdr_data2_t speedN; // ...
|
||||||
|
xdr_data2_t speedE; // ...
|
||||||
|
xdr_data2_t speedD; // ...
|
||||||
|
xdr_data_t accN; // acceleration N
|
||||||
|
xdr_data_t accE; // acceleration E
|
||||||
|
xdr_data_t accD; // acceleration D
|
||||||
|
xdr_data_t left_aileron; // control positions
|
||||||
|
xdr_data_t right_aileron; // control positions
|
||||||
|
xdr_data_t elevator; // ...
|
||||||
|
xdr_data_t rudder; // ...
|
||||||
|
// xdr_data_t rpms[6]; // RPMs of all of the motors
|
||||||
|
xdr_data_t rateH; // Rate of change of heading
|
||||||
|
xdr_data_t rateR; // roll
|
||||||
|
xdr_data_t rateP; // and pitch
|
||||||
|
// xdr_data_t dummy; // pad message length
|
||||||
|
};
|
||||||
|
|
||||||
|
// Property message
|
||||||
|
class T_PropertyMsg {
|
||||||
|
public:
|
||||||
|
char property[MAX_PROPERTY_LEN]; // the property name
|
||||||
|
xdr_data_t type; // the type
|
||||||
|
xdr_data2_t val; // and value
|
||||||
|
// xdr_data2_t dummy; // pad message length
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
// Written by Duncan McCreanor, started February 2003.
|
// Written by Duncan McCreanor, started February 2003.
|
||||||
// duncan.mccreanor@airservicesaustralia.com
|
// duncan.mccreanor@airservicesaustralia.com
|
||||||
//
|
//
|
||||||
|
// With additions by Vivian Meazza, January 2006
|
||||||
|
//
|
||||||
// Copyright (C) 2003 Airservices Australia
|
// Copyright (C) 2003 Airservices Australia
|
||||||
// Copyright (C) 2005 Oliver Schroeder
|
// Copyright (C) 2005 Oliver Schroeder
|
||||||
//
|
//
|
||||||
|
@ -46,6 +48,7 @@
|
||||||
|
|
||||||
#include "mpplayer.hxx"
|
#include "mpplayer.hxx"
|
||||||
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#if !(defined(_MSC_VER) || defined(__MINGW32__))
|
#if !(defined(_MSC_VER) || defined(__MINGW32__))
|
||||||
# include <netdb.h>
|
# include <netdb.h>
|
||||||
|
@ -56,12 +59,16 @@
|
||||||
#include <plib/netSocket.h>
|
#include <plib/netSocket.h>
|
||||||
#include <plib/sg.h>
|
#include <plib/sg.h>
|
||||||
|
|
||||||
|
#include <simgear/math/sg_geodesy.hxx>
|
||||||
|
#include <simgear/props/props.hxx>
|
||||||
#include <simgear/scene/model/modellib.hxx>
|
#include <simgear/scene/model/modellib.hxx>
|
||||||
#include <simgear/scene/model/placementtrans.hxx>
|
#include <simgear/scene/model/placementtrans.hxx>
|
||||||
|
|
||||||
|
#include <AIModel/AIBase.hxx>
|
||||||
|
#include <AIModel/AIManager.hxx>
|
||||||
|
#include <AIModel/AIMultiplayer.hxx>
|
||||||
#include <Main/globals.hxx>
|
#include <Main/globals.hxx>
|
||||||
#include <Scenery/scenery.hxx>
|
//#include <Scenery/scenery.hxx>
|
||||||
|
|
||||||
|
|
||||||
// These constants are provided so that the ident command can list file versions.
|
// These constants are provided so that the ident command can list file versions.
|
||||||
const char sMPPLAYER_BID[] = "$Id$";
|
const char sMPPLAYER_BID[] = "$Id$";
|
||||||
|
@ -76,8 +83,14 @@ MPPlayer::MPPlayer()
|
||||||
{
|
{
|
||||||
m_Initialised = false;
|
m_Initialised = false;
|
||||||
m_LastUpdate = 0;
|
m_LastUpdate = 0;
|
||||||
|
m_LastUpdate = 0;
|
||||||
|
m_LastTime = 0;
|
||||||
|
m_LastUTime = 0;
|
||||||
|
m_Elapsed = 0;
|
||||||
|
m_TimeOffset = 0.0;
|
||||||
m_Callsign = "none";
|
m_Callsign = "none";
|
||||||
m_PlayerAddress.set("localhost", 0);
|
m_PlayerAddress.set("localhost", 0);
|
||||||
|
m_AIModel = NULL;
|
||||||
} // MPPlayer::MPPlayer()
|
} // MPPlayer::MPPlayer()
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -118,7 +131,7 @@ MPPlayer::Open
|
||||||
if (!LocalPlayer)
|
if (!LocalPlayer)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
LoadModel();
|
LoadAI();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
SG_LOG( SG_NETWORK, SG_ALERT,
|
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||||
"Failed to load remote model '" << ModelName << "'." );
|
"Failed to load remote model '" << ModelName << "'." );
|
||||||
|
@ -147,23 +160,86 @@ MPPlayer::Close(void)
|
||||||
// Remove the model from the game
|
// Remove the model from the game
|
||||||
if (m_Initialised && !m_LocalPlayer)
|
if (m_Initialised && !m_LocalPlayer)
|
||||||
{
|
{
|
||||||
// Disconnect the model from the transform,
|
m_Initialised = 0;
|
||||||
// then the transform from the scene.
|
|
||||||
m_ModelTrans->removeKid(m_Model);
|
// get the model manager
|
||||||
globals->get_scenery()->unregister_placement_transform(m_ModelTrans);
|
FGAIManager *aiModelMgr = (FGAIManager *) globals->get_subsystem("ai_model");
|
||||||
globals->get_scenery()->get_aircraft_branch()->removeKid( m_ModelTrans);
|
if (!aiModelMgr) {
|
||||||
// Flush the model loader so that it erases the model from its list of
|
SG_LOG( SG_NETWORK, SG_ALERT, "MPPlayer::Close - "
|
||||||
// models.
|
<< "Cannot find AI model manager!" );
|
||||||
// globals->get_model_lib()->flush1();
|
return;
|
||||||
// Assume that plib/ssg deletes the model and transform as their
|
}
|
||||||
// refcounts should be zero.
|
|
||||||
|
// remove it
|
||||||
|
aiModelMgr->destroyObject(m_AIModel->getID());
|
||||||
|
m_AIModel = NULL;
|
||||||
}
|
}
|
||||||
m_Initialised = false;
|
m_Initialised = false;
|
||||||
m_Updated = false;
|
m_Updated = false;
|
||||||
m_LastUpdate = 0;
|
m_LastUpdate = 0;
|
||||||
|
m_LastUpdate = 0;
|
||||||
|
m_LastTime = 0;
|
||||||
|
m_LastUTime = 0;
|
||||||
|
m_Elapsed = 0;
|
||||||
|
m_TimeOffset = 0.0;
|
||||||
m_Callsign = "none";
|
m_Callsign = "none";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: CheckTime
|
||||||
|
* Description: Checks if the time is valid for a position update
|
||||||
|
* and perhaps sets the time offset
|
||||||
|
******************************************************************/
|
||||||
|
bool MPPlayer::CheckTime(int time, int timeusec)
|
||||||
|
{
|
||||||
|
double curOffset;
|
||||||
|
|
||||||
|
// set the offset
|
||||||
|
struct timeval tv;
|
||||||
|
int toff, utoff;
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
|
||||||
|
// calculate the offset
|
||||||
|
toff = ((int) tv.tv_sec) - time;
|
||||||
|
utoff = ((int) tv.tv_usec) - timeusec;
|
||||||
|
while (utoff < 0) {
|
||||||
|
toff--;
|
||||||
|
utoff += 1000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set it
|
||||||
|
curOffset = ((double)toff) + (((double)utoff) / 1000000);
|
||||||
|
|
||||||
|
if (m_LastUpdate == 0) {
|
||||||
|
// set the main offset
|
||||||
|
m_TimeOffset = curOffset;
|
||||||
|
m_Elapsed = 0;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// check it
|
||||||
|
if (time < m_LastTime ||
|
||||||
|
(time == m_LastTime && timeusec <= m_LastUTime)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
// set the current offset
|
||||||
|
m_LastOffset = curOffset;
|
||||||
|
// calculate the Hz
|
||||||
|
toff = time - m_LastTime;
|
||||||
|
utoff = timeusec - m_LastUTime;
|
||||||
|
while (utoff < 0) {
|
||||||
|
toff--;
|
||||||
|
utoff += 1000000;
|
||||||
|
}
|
||||||
|
m_Elapsed = ((double)toff) + (((double)utoff)/1000000);
|
||||||
|
|
||||||
|
m_LastTime = time;
|
||||||
|
m_LastUTime = timeusec;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
* Name: SetPosition
|
* Name: SetPosition
|
||||||
* Description: Updates position data held for this player and resets
|
* Description: Updates position data held for this player and resets
|
||||||
|
@ -172,20 +248,133 @@ MPPlayer::Close(void)
|
||||||
void
|
void
|
||||||
MPPlayer::SetPosition
|
MPPlayer::SetPosition
|
||||||
(
|
(
|
||||||
const sgQuat PlayerOrientation,
|
const double lat, const double lon, const double alt,
|
||||||
const sgdVec3 PlayerPosition
|
const double heading, const double roll, const double pitch,
|
||||||
|
const double speedN, const double speedE, const double speedD,
|
||||||
|
const double left_aileron, const double right_aileron, const double elevator, const double rudder,
|
||||||
|
//const double rpms[6],
|
||||||
|
const double rateH, const double rateR, const double rateP,
|
||||||
|
const double accN, const double accE, const double accD
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
int toff, utoff;
|
||||||
|
|
||||||
// Save the position matrix and update time
|
// Save the position matrix and update time
|
||||||
if (m_Initialised)
|
if (m_Initialised)
|
||||||
{
|
{
|
||||||
sgdCopyVec3(m_ModelPosition, PlayerPosition);
|
// calculate acceleration
|
||||||
sgCopyVec4(m_ModelOrientation, PlayerOrientation);
|
/*if (m_Elapsed > 0) {
|
||||||
|
m_accN = (speedN - m_speedN) / m_Elapsed;
|
||||||
|
m_accE = (speedE - m_speedE) / m_Elapsed;
|
||||||
|
m_accD = (speedD - m_speedD) / m_Elapsed;
|
||||||
|
} else {
|
||||||
|
m_accN = 0;
|
||||||
|
m_accE = 0;
|
||||||
|
m_accD = 0;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
// store the position
|
||||||
|
m_lat = lat;
|
||||||
|
m_lon = lon;
|
||||||
|
m_alt = alt;
|
||||||
|
m_hdg = heading;
|
||||||
|
m_roll = roll;
|
||||||
|
m_pitch = pitch;
|
||||||
|
m_speedN = speedN;
|
||||||
|
m_speedE = speedE;
|
||||||
|
m_speedD = speedD;
|
||||||
|
m_accN = accN;
|
||||||
|
m_accE = accE;
|
||||||
|
m_accD = accD;
|
||||||
|
m_left_aileron = left_aileron;
|
||||||
|
m_right_aileron = right_aileron;
|
||||||
|
m_elevator = elevator;
|
||||||
|
m_rudder = rudder;
|
||||||
|
|
||||||
|
/*for (int i = 0; i < 6; i++) {
|
||||||
|
m_rpms[i] = rpms[i];
|
||||||
|
}
|
||||||
|
m_rateH = rateH;
|
||||||
|
m_rateR = rateR;
|
||||||
|
m_rateP = rateP;*/
|
||||||
|
|
||||||
|
if (!m_LocalPlayer) {
|
||||||
|
m_AIModel->setLatitude(m_lat);
|
||||||
|
m_AIModel->setLongitude(m_lon);
|
||||||
|
m_AIModel->setAltitude(m_alt);
|
||||||
|
m_AIModel->setHeading(m_hdg);
|
||||||
|
m_AIModel->setBank(m_roll);
|
||||||
|
m_AIModel->setPitch(m_pitch);
|
||||||
|
m_AIModel->setSpeedN(m_speedN);
|
||||||
|
m_AIModel->setSpeedE(m_speedE);
|
||||||
|
m_AIModel->setSpeedD(m_speedD);
|
||||||
|
m_AIModel->setAccN(m_accN);
|
||||||
|
m_AIModel->setAccE(m_accE);
|
||||||
|
m_AIModel->setAccD(m_accD);
|
||||||
|
m_AIModel->setRateH(m_rateH);
|
||||||
|
m_AIModel->setRateR(m_rateR);
|
||||||
|
m_AIModel->setRateP(m_rateP);
|
||||||
|
|
||||||
|
// set properties
|
||||||
|
SGPropertyNode *root = m_AIModel->getProps();
|
||||||
|
root->getNode("surface-positions/left-aileron-pos-norm", true)->setDoubleValue(m_left_aileron);
|
||||||
|
root->getNode("surface-positions/right-aileron-pos-norm", true)->setDoubleValue(m_right_aileron);
|
||||||
|
root->getNode("surface-positions/elevator-pos-norm", true)->setDoubleValue(m_elevator);
|
||||||
|
root->getNode("surface-positions/rudder-pos-norm", true)->setDoubleValue(m_rudder);
|
||||||
|
/*root->getNode("engines/engine/rpm", true)->setDoubleValue(m_rpms[0]);
|
||||||
|
root->getNode("engines/engine[1]/rpm", true)->setDoubleValue(m_rpms[1]);
|
||||||
|
root->getNode("engines/engine[2]/rpm", true)->setDoubleValue(m_rpms[2]);
|
||||||
|
root->getNode("engines/engine[3]/rpm", true)->setDoubleValue(m_rpms[3]);
|
||||||
|
root->getNode("engines/engine[4]/rpm", true)->setDoubleValue(m_rpms[4]);
|
||||||
|
root->getNode("engines/engine[5]/rpm", true)->setDoubleValue(m_rpms[5]);*/
|
||||||
|
|
||||||
|
// Adjust by the last offset
|
||||||
|
//cout << "OFFSET: " << (m_LastOffset - m_TimeOffset) << endl;
|
||||||
|
|
||||||
|
//m_AIModel->timewarp(m_LastOffset - m_TimeOffset);
|
||||||
|
|
||||||
|
// set the timestamp for the data update (sim elapsed time (secs))
|
||||||
|
m_AIModel->setTimeStamp();
|
||||||
|
}
|
||||||
|
|
||||||
time(&m_LastUpdate);
|
time(&m_LastUpdate);
|
||||||
|
|
||||||
m_Updated = true;
|
m_Updated = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: SetProperty
|
||||||
|
* Description: Sets a property of this player.
|
||||||
|
******************************************************************/
|
||||||
|
void MPPlayer::SetProperty(string property, SGPropertyNode::Type type, double val)
|
||||||
|
{
|
||||||
|
// get rid of any leading /
|
||||||
|
while (property[0] == '/') property = property.substr(1);
|
||||||
|
|
||||||
|
// get our root node
|
||||||
|
SGPropertyNode *node = m_AIModel->getProps()->getNode(property.c_str(), true);
|
||||||
|
|
||||||
|
// set the property
|
||||||
|
switch (type) {
|
||||||
|
case 2:
|
||||||
|
node->setBoolValue((bool) val);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
node->setIntValue((int) val);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
node->setLongValue((long) val);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
node->setFloatValue((float) val);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
default:
|
||||||
|
node->setDoubleValue(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
* Name: Draw
|
* Name: Draw
|
||||||
* Description: Updates the position for the player's model
|
* Description: Updates the position for the player's model
|
||||||
|
@ -202,12 +391,37 @@ MPPlayer::Draw (void)
|
||||||
// Peform an update if it has changed since the last update
|
// Peform an update if it has changed since the last update
|
||||||
if (m_Updated)
|
if (m_Updated)
|
||||||
{
|
{
|
||||||
// Transform and update player model
|
/*
|
||||||
sgMat4 orMat;
|
m_AIModel->setLatitude(m_lat);
|
||||||
sgMakeIdentMat4(orMat);
|
m_AIModel->setLongitude(m_lon);
|
||||||
sgQuatToMatrix(orMat, m_ModelOrientation);
|
m_AIModel->setAltitude(m_alt);
|
||||||
m_ModelTrans->setTransform(m_ModelPosition, orMat);
|
m_AIModel->setHeading(m_hdg);
|
||||||
|
m_AIModel->setBank(m_roll);
|
||||||
|
m_AIModel->setPitch(m_pitch);
|
||||||
|
m_AIModel->setSpeedN(m_speedN);
|
||||||
|
m_AIModel->setSpeedE(m_speedE);
|
||||||
|
m_AIModel->_setVS_fps(m_speedU*60.0); // it needs input in fpm
|
||||||
|
m_AIModel->setRateH(m_rateH);
|
||||||
|
m_AIModel->setRateR(m_rateR);
|
||||||
|
m_AIModel->setRateP(m_rateP);
|
||||||
|
|
||||||
|
// set properties
|
||||||
|
SGPropertyNode *root = m_AIModel->getProps();
|
||||||
|
root->getNode("controls/flight/aileron", true)->setDoubleValue(m_aileron);
|
||||||
|
root->getNode("controls/flight/elevator", true)->setDoubleValue(m_elevator);
|
||||||
|
root->getNode("controls/flight/rudder", true)->setDoubleValue(m_rudder);
|
||||||
|
root->getNode("engines/engine/rpm", true)->setDoubleValue(m_rpms[0]);
|
||||||
|
root->getNode("engines/engine[1]/rpm", true)->setDoubleValue(m_rpms[1]);
|
||||||
|
root->getNode("engines/engine[2]/rpm", true)->setDoubleValue(m_rpms[2]);
|
||||||
|
root->getNode("engines/engine[3]/rpm", true)->setDoubleValue(m_rpms[3]);
|
||||||
|
root->getNode("engines/engine[4]/rpm", true)->setDoubleValue(m_rpms[4]);
|
||||||
|
root->getNode("engines/engine[5]/rpm", true)->setDoubleValue(m_rpms[5]);
|
||||||
|
|
||||||
|
// Adjust by the last offset
|
||||||
|
m_AIModel->update(m_LastOffset - m_TimeOffset);
|
||||||
|
*/
|
||||||
eResult = PLAYER_DATA_AVAILABLE;
|
eResult = PLAYER_DATA_AVAILABLE;
|
||||||
|
|
||||||
// Clear the updated flag so that the position data
|
// Clear the updated flag so that the position data
|
||||||
// is only available if it has changed
|
// is only available if it has changed
|
||||||
m_Updated = false;
|
m_Updated = false;
|
||||||
|
@ -243,22 +457,31 @@ MPPlayer::CompareCallsign(const char *Callsign) const
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
* Name: LoadModel
|
* Name: LoadAI
|
||||||
* Description: Loads the player's aircraft model.
|
* Description: Loads the AI model into the AI core.
|
||||||
******************************************************************/
|
******************************************************************/
|
||||||
void
|
void
|
||||||
MPPlayer::LoadModel (void)
|
MPPlayer::LoadAI(void)
|
||||||
{
|
{
|
||||||
m_ModelTrans = new ssgPlacementTransform;
|
// set up the model info
|
||||||
// Load the model
|
FGAIModelEntity aiModel;
|
||||||
m_Model = globals->get_model_lib()->load_model( globals->get_fg_root(),
|
aiModel.m_type = "aircraft";
|
||||||
m_ModelName, globals->get_props(), globals->get_sim_time_sec() );
|
aiModel.path = m_ModelName;
|
||||||
m_Model->clrTraversalMaskBits( SSGTRAV_HOT );
|
aiModel.acType = "Multiplayer";
|
||||||
// Add model to transform
|
aiModel.company = m_Callsign;
|
||||||
m_ModelTrans->addKid( m_Model );
|
|
||||||
// Place on scene under aircraft branch
|
// then get the model manager
|
||||||
globals->get_scenery()->get_aircraft_branch()->addKid( m_ModelTrans );
|
FGAIManager *aiModelMgr = (FGAIManager *) globals->get_subsystem("ai_model");
|
||||||
globals->get_scenery()->register_placement_transform( m_ModelTrans);
|
if (!aiModelMgr) {
|
||||||
|
SG_LOG( SG_NETWORK, SG_ALERT, "MPPlayer::LoadAI - "
|
||||||
|
<< "Cannot find AI model manager!" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// then get the model
|
||||||
|
fgSetBool("/sim/freeze/clock", true);
|
||||||
|
m_AIModel = (FGAIMultiplayer *) aiModelMgr->createMultiplayer(&aiModel);
|
||||||
|
fgSetBool("/sim/freeze/clock", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
|
@ -272,16 +495,36 @@ MPPlayer::FillPosMsg
|
||||||
T_PositionMsg *PosMsg
|
T_PositionMsg *PosMsg
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
|
||||||
FillMsgHdr(MsgHdr, POS_DATA_ID);
|
FillMsgHdr(MsgHdr, POS_DATA_ID);
|
||||||
strncpy(PosMsg->Model, m_ModelName.c_str(), MAX_MODEL_NAME_LEN);
|
strncpy(PosMsg->Model, m_ModelName.c_str(), MAX_MODEL_NAME_LEN);
|
||||||
PosMsg->Model[MAX_MODEL_NAME_LEN - 1] = '\0';
|
PosMsg->Model[MAX_MODEL_NAME_LEN - 1] = '\0';
|
||||||
PosMsg->PlayerPosition[0] = XDR_encode_double (m_ModelPosition[0]);
|
PosMsg->time = XDR_encode_uint32 (tv.tv_sec);
|
||||||
PosMsg->PlayerPosition[1] = XDR_encode_double (m_ModelPosition[1]);
|
PosMsg->timeusec = XDR_encode_uint32 (tv.tv_usec);
|
||||||
PosMsg->PlayerPosition[2] = XDR_encode_double (m_ModelPosition[2]);
|
PosMsg->lat = XDR_encode_double (m_lat);
|
||||||
PosMsg->PlayerOrientation[0] = XDR_encode_float (m_ModelOrientation[0]);
|
PosMsg->lon = XDR_encode_double (m_lon);
|
||||||
PosMsg->PlayerOrientation[1] = XDR_encode_float (m_ModelOrientation[1]);
|
PosMsg->alt = XDR_encode_double (m_alt);
|
||||||
PosMsg->PlayerOrientation[2] = XDR_encode_float (m_ModelOrientation[2]);
|
PosMsg->hdg = XDR_encode_double (m_hdg);
|
||||||
PosMsg->PlayerOrientation[3] = XDR_encode_float (m_ModelOrientation[3]);
|
PosMsg->roll = XDR_encode_double (m_roll);
|
||||||
|
PosMsg->pitch = XDR_encode_double (m_pitch);
|
||||||
|
PosMsg->speedN = XDR_encode_double (m_speedN);
|
||||||
|
PosMsg->speedE = XDR_encode_double (m_speedE);
|
||||||
|
PosMsg->speedD = XDR_encode_double (m_speedD);
|
||||||
|
PosMsg->left_aileron = XDR_encode_float ((float) m_left_aileron);
|
||||||
|
PosMsg->right_aileron = XDR_encode_float ((float) m_right_aileron);
|
||||||
|
PosMsg->elevator = XDR_encode_float ((float) m_elevator);
|
||||||
|
PosMsg->rudder = XDR_encode_float ((float) m_rudder);
|
||||||
|
/*for (int i = 0; i < 6; i++) {
|
||||||
|
PosMsg->rpms[i] = XDR_encode_float ((float) m_rpms[i]);
|
||||||
|
}*/
|
||||||
|
PosMsg->rateH = XDR_encode_float ((float) m_rateH);
|
||||||
|
PosMsg->rateR = XDR_encode_float ((float) m_rateR);
|
||||||
|
PosMsg->rateP = XDR_encode_float ((float) m_rateP);
|
||||||
|
PosMsg->accN = XDR_encode_float ((float) m_accN);
|
||||||
|
PosMsg->accE = XDR_encode_float ((float) m_accE);
|
||||||
|
PosMsg->accD = XDR_encode_float ((float) m_accD);
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
|
@ -305,6 +548,9 @@ MPPlayer::FillMsgHdr
|
||||||
case POS_DATA_ID:
|
case POS_DATA_ID:
|
||||||
len = sizeof(T_MsgHdr) + sizeof(T_PositionMsg);
|
len = sizeof(T_MsgHdr) + sizeof(T_PositionMsg);
|
||||||
break;
|
break;
|
||||||
|
case PROP_MSG_ID:
|
||||||
|
len = sizeof(T_MsgHdr) + sizeof(T_PropertyMsg);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
len = sizeof(T_MsgHdr);
|
len = sizeof(T_MsgHdr);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -44,7 +44,9 @@
|
||||||
#include <plib/sg.h>
|
#include <plib/sg.h>
|
||||||
#include <plib/netSocket.h>
|
#include <plib/netSocket.h>
|
||||||
#include <simgear/io/sg_socket_udp.hxx>
|
#include <simgear/io/sg_socket_udp.hxx>
|
||||||
|
#include <simgear/props/props.hxx>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
#include STL_STRING
|
#include STL_STRING
|
||||||
SG_USING_STD(string);
|
SG_USING_STD(string);
|
||||||
|
@ -52,8 +54,7 @@ SG_USING_STD(string);
|
||||||
// Number of seconds before a player is consider to be lost
|
// Number of seconds before a player is consider to be lost
|
||||||
#define TIME_TO_LIVE 10
|
#define TIME_TO_LIVE 10
|
||||||
|
|
||||||
class ssgEntity;
|
class FGAIMultiplayer;
|
||||||
class ssgPlacementTransform;
|
|
||||||
|
|
||||||
class MPPlayer
|
class MPPlayer
|
||||||
{
|
{
|
||||||
|
@ -81,11 +82,21 @@ public:
|
||||||
const string &ModelName, const bool LocalPlayer);
|
const string &ModelName, const bool LocalPlayer);
|
||||||
/** Closes the player connection */
|
/** Closes the player connection */
|
||||||
void Close(void);
|
void Close(void);
|
||||||
|
/** Checks if the time is valid for a position update and perhaps sets the time offset
|
||||||
|
*/
|
||||||
|
bool CheckTime(int time, int timeusec);
|
||||||
/** Sets the positioning matrix held for this player
|
/** Sets the positioning matrix held for this player
|
||||||
* @param PlayerPosMat4 Matrix for positioning player's aircraft
|
|
||||||
*/
|
*/
|
||||||
void SetPosition(const sgQuat PlayerOrientation,
|
void SetPosition(const double lat, const double lon, const double alt,
|
||||||
const sgdVec3 PlayerPosition);
|
const double heading, const double roll, const double pitch,
|
||||||
|
const double speedN, const double speedE, const double speedD,
|
||||||
|
const double left_aileron, const double right_aileron, const double elevator, const double rudder,
|
||||||
|
//const double rpms[6],
|
||||||
|
const double rateH, const double rateR, const double rateP,
|
||||||
|
const double accN, const double accE, const double accD);
|
||||||
|
/** Sets a property for this player
|
||||||
|
*/
|
||||||
|
void SetProperty(string property, SGPropertyNode::Type type, double val);
|
||||||
/** Transform and place model for player
|
/** Transform and place model for player
|
||||||
*/
|
*/
|
||||||
TPlayerDataState Draw(void);
|
TPlayerDataState Draw(void);
|
||||||
|
@ -109,18 +120,42 @@ public:
|
||||||
*/
|
*/
|
||||||
void FillMsgHdr(T_MsgHdr *MsgHdr, const int iMsgId);
|
void FillMsgHdr(T_MsgHdr *MsgHdr, const int iMsgId);
|
||||||
private:
|
private:
|
||||||
void LoadModel(void); // Loads the model of the aircraft
|
void LoadAI(void); // Loads the plane into the AI core
|
||||||
bool m_Initialised; // True if object is initialised
|
bool m_Initialised; // True if object is initialised
|
||||||
sgdVec3 m_ModelPosition; // players global position on earth
|
|
||||||
sgQuat m_ModelOrientation; // players global orientation
|
double m_lat; // location, orientation, etc...
|
||||||
|
double m_lon; // ...
|
||||||
|
double m_alt; // ...
|
||||||
|
double m_hdg; // ...
|
||||||
|
double m_roll; // ...
|
||||||
|
double m_pitch; // ...
|
||||||
|
double m_speedN; // ...
|
||||||
|
double m_speedE; // ...
|
||||||
|
double m_speedD; // ...
|
||||||
|
double m_accN; // ...
|
||||||
|
double m_accE; // ...
|
||||||
|
double m_accD; // ...
|
||||||
|
double m_left_aileron; // ...
|
||||||
|
double m_right_aileron; // ...
|
||||||
|
double m_elevator; // ...
|
||||||
|
double m_rudder; // ...
|
||||||
|
//double m_rpms[6]; // ...
|
||||||
|
double m_rateH; // ...
|
||||||
|
double m_rateR; // ...
|
||||||
|
double m_rateP; // ...
|
||||||
|
|
||||||
time_t m_LastUpdate; // last time update data received
|
time_t m_LastUpdate; // last time update data received
|
||||||
|
int m_LastTime; // last seconds according to the packet
|
||||||
|
int m_LastUTime; // last microseconds according to the packet
|
||||||
|
double m_Elapsed; // Elapsed other-side time between responses
|
||||||
|
double m_TimeOffset; // the offset to aim for
|
||||||
|
double m_LastOffset; // the last offset we got
|
||||||
bool m_Updated; // Set when the player data is updated
|
bool m_Updated; // Set when the player data is updated
|
||||||
string m_Callsign; // players callsign
|
string m_Callsign; // players callsign
|
||||||
bool m_LocalPlayer; // true if player is the local player
|
bool m_LocalPlayer; // true if player is the local player
|
||||||
string m_ModelName; // Aircraft model name for player
|
string m_ModelName; // Aircraft model name for player
|
||||||
ssgEntity *m_Model; // The player's loaded model
|
|
||||||
netAddress m_PlayerAddress; // Address information for the player
|
netAddress m_PlayerAddress; // Address information for the player
|
||||||
ssgPlacementTransform *m_ModelTrans; // Model transform
|
FGAIMultiplayer *m_AIModel; // The AI model of this aircraft
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
// Written by Duncan McCreanor, started February 2003.
|
// Written by Duncan McCreanor, started February 2003.
|
||||||
// duncan.mccreanor@airservicesaustralia.com
|
// duncan.mccreanor@airservicesaustralia.com
|
||||||
//
|
//
|
||||||
|
// With minor additions by Vivian Meazza, January 2006
|
||||||
|
//
|
||||||
// Copyright (C) 2003 Airservices Australia
|
// Copyright (C) 2003 Airservices Australia
|
||||||
// Copyright (C) 2005 Oliver Schroeder
|
// Copyright (C) 2005 Oliver Schroeder
|
||||||
//
|
//
|
||||||
|
@ -70,6 +72,8 @@ FGMultiplayMgr::FGMultiplayMgr()
|
||||||
m_RxPort = 0;
|
m_RxPort = 0;
|
||||||
m_Initialised = false;
|
m_Initialised = false;
|
||||||
m_HaveServer = false;
|
m_HaveServer = false;
|
||||||
|
|
||||||
|
send_all_props= false;
|
||||||
} // FGMultiplayMgr::FGMultiplayMgr()
|
} // FGMultiplayMgr::FGMultiplayMgr()
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -84,6 +88,22 @@ FGMultiplayMgr::~FGMultiplayMgr()
|
||||||
} // FGMultiplayMgr::~FGMultiplayMgr()
|
} // FGMultiplayMgr::~FGMultiplayMgr()
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// Name: getSendAll
|
||||||
|
// Description: getter for send_all
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
bool FGMultiplayMgr::getSendAllProps() {
|
||||||
|
return send_all_props;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// Name: setSendAll
|
||||||
|
// Description: setter for send_all
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
void FGMultiplayMgr::setSendAllProps(bool s) {
|
||||||
|
send_all_props = s;
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Initialise object
|
// Initialise object
|
||||||
|
@ -160,6 +180,7 @@ FGMultiplayMgr::init (void)
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
m_Initialised = true;
|
m_Initialised = true;
|
||||||
|
send_all_props= true;
|
||||||
return (true);
|
return (true);
|
||||||
} // FGMultiplayMgr::init()
|
} // FGMultiplayMgr::init()
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
@ -215,8 +236,13 @@ FGMultiplayMgr::Close (void)
|
||||||
void
|
void
|
||||||
FGMultiplayMgr::SendMyPosition
|
FGMultiplayMgr::SendMyPosition
|
||||||
(
|
(
|
||||||
const sgQuat PlayerOrientation,
|
const double lat, const double lon, const double alt,
|
||||||
const sgdVec3 PlayerPosition
|
const double heading, const double roll, const double pitch,
|
||||||
|
const double speedN, const double speedE, const double speedD,
|
||||||
|
const double left_aileron, const double right_aileron, const double elevator, const double rudder,
|
||||||
|
//const double rpms[6],
|
||||||
|
const double rateH, const double rateR, const double rateP,
|
||||||
|
const double accN, const double accE, const double accD
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
T_MsgHdr MsgHdr;
|
T_MsgHdr MsgHdr;
|
||||||
|
@ -233,15 +259,59 @@ FGMultiplayMgr::SendMyPosition
|
||||||
"FGMultiplayMgr::SendMyPosition - no server" );
|
"FGMultiplayMgr::SendMyPosition - no server" );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_LocalPlayer->SetPosition(PlayerOrientation, PlayerPosition);
|
m_LocalPlayer->SetPosition(lat, lon, alt,
|
||||||
|
heading, roll, pitch,
|
||||||
|
speedN, speedE, speedD,
|
||||||
|
left_aileron, right_aileron, elevator, rudder,
|
||||||
|
//rpms,
|
||||||
|
rateH, rateR, rateP,
|
||||||
|
accN, accE, accD);
|
||||||
m_LocalPlayer->FillPosMsg(&MsgHdr, &PosMsg);
|
m_LocalPlayer->FillPosMsg(&MsgHdr, &PosMsg);
|
||||||
memcpy(Msg, &MsgHdr, sizeof(T_MsgHdr));
|
memcpy(Msg, &MsgHdr, sizeof(T_MsgHdr));
|
||||||
memcpy(Msg + sizeof(T_MsgHdr), &PosMsg, sizeof(T_PositionMsg));
|
memcpy(Msg + sizeof(T_MsgHdr), &PosMsg, sizeof(T_PositionMsg));
|
||||||
m_DataSocket->sendto (Msg,
|
m_DataSocket->sendto (Msg,
|
||||||
sizeof(T_MsgHdr) + sizeof(T_PositionMsg), 0, &m_Server);
|
sizeof(T_MsgHdr) + sizeof(T_PositionMsg), 0, &m_Server);
|
||||||
|
SG_LOG( SG_NETWORK, SG_DEBUG,
|
||||||
|
"FGMultiplayMgr::SendMyPosition" );
|
||||||
|
|
||||||
} // FGMultiplayMgr::SendMyPosition()
|
} // FGMultiplayMgr::SendMyPosition()
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Description: Sends the property data for the local player.
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
void FGMultiplayMgr::SendPropMessage (const string &property, SGPropertyNode::Type type, double value)
|
||||||
|
|
||||||
|
{SG_LOG( SG_NETWORK, SG_INFO,
|
||||||
|
"FGMultiplayMgr::Property: " << property << " Type " << type << " value " << value);
|
||||||
|
|
||||||
|
T_MsgHdr MsgHdr;
|
||||||
|
T_PropertyMsg PropMsg;
|
||||||
|
unsigned int iNextBlockPosition = 0;
|
||||||
|
char Msg[sizeof(T_MsgHdr) + sizeof(T_PropertyMsg)];
|
||||||
|
|
||||||
|
if ((! m_Initialised) || (! m_HaveServer))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_LocalPlayer->FillMsgHdr(&MsgHdr, PROP_MSG_ID);
|
||||||
|
|
||||||
|
strncpy(PropMsg.property, property.c_str(), MAX_PROPERTY_LEN);
|
||||||
|
PropMsg.property[MAX_PROPERTY_LEN-1] = '\0';
|
||||||
|
PropMsg.type = XDR_encode_uint32(type);
|
||||||
|
PropMsg.val = XDR_encode_double(value);
|
||||||
|
SG_LOG( SG_NETWORK, SG_INFO,
|
||||||
|
"FGMultiplayMgr::sending property message: "
|
||||||
|
<< PropMsg.property << " " << PropMsg.type << " " << PropMsg.val);
|
||||||
|
|
||||||
|
memcpy (Msg, &MsgHdr, sizeof(T_MsgHdr));
|
||||||
|
memcpy (Msg + sizeof(T_MsgHdr), &PropMsg, sizeof(T_PropertyMsg));
|
||||||
|
m_DataSocket->sendto (Msg,
|
||||||
|
sizeof(T_MsgHdr) + sizeof(T_PropertyMsg), 0, &m_Server);
|
||||||
|
} // FGMultiplayMgr::SendPropMessage ()
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Name: SendTextMessage
|
// Name: SendTextMessage
|
||||||
|
@ -375,6 +445,9 @@ FGMultiplayMgr::ProcessData (void)
|
||||||
case POS_DATA_ID:
|
case POS_DATA_ID:
|
||||||
ProcessPosMsg ((char*) & Msg, SenderAddress);
|
ProcessPosMsg ((char*) & Msg, SenderAddress);
|
||||||
break;
|
break;
|
||||||
|
case PROP_MSG_ID:
|
||||||
|
ProcessPropMsg ((char *) & Msg, SenderAddress);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
SG_LOG( SG_NETWORK, SG_ALERT,
|
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||||
"FGMultiplayMgr::MP_ProcessData - "
|
"FGMultiplayMgr::MP_ProcessData - "
|
||||||
|
@ -401,27 +474,56 @@ FGMultiplayMgr::ProcessPosMsg
|
||||||
T_PositionMsg* PosMsg; // Pointer to position message in received data
|
T_PositionMsg* PosMsg; // Pointer to position message in received data
|
||||||
T_MsgHdr* MsgHdr; // Pointer to header in received data
|
T_MsgHdr* MsgHdr; // Pointer to header in received data
|
||||||
bool ActivePlayer;
|
bool ActivePlayer;
|
||||||
sgQuat Orientation;
|
struct in_addr PlayerAddress;
|
||||||
sgdVec3 Position;
|
int time, timeusec;
|
||||||
|
double lat, lon, alt;
|
||||||
|
double hdg, roll, pitch;
|
||||||
|
double speedN, speedE, speedD;
|
||||||
|
double left_aileron, right_aileron, elevator, rudder;
|
||||||
|
//double rpms[6];
|
||||||
|
double rateH, rateR, rateP;
|
||||||
|
double accN, accE, accD;
|
||||||
t_MPClientListIterator CurrentPlayer;
|
t_MPClientListIterator CurrentPlayer;
|
||||||
|
|
||||||
ActivePlayer = false;
|
ActivePlayer = false;
|
||||||
MsgHdr = (T_MsgHdr *)Msg;
|
MsgHdr = (T_MsgHdr *)Msg;
|
||||||
if (MsgHdr->MsgLen != sizeof(T_MsgHdr) + sizeof(T_PositionMsg))
|
if (MsgHdr->MsgLen < sizeof(T_MsgHdr) + sizeof(T_PositionMsg))
|
||||||
{
|
{
|
||||||
SG_LOG( SG_NETWORK, SG_ALERT,
|
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||||
"FGMultiplayMgr::MP_ProcessData - "
|
"FGMultiplayMgr::MP_ProcessData - "
|
||||||
<< "Position message received with insufficient data" );
|
<< "Position message received with insufficient data" );
|
||||||
return;
|
return;
|
||||||
|
} else if (MsgHdr->MsgLen > sizeof(T_MsgHdr) + sizeof(T_PositionMsg)) {
|
||||||
|
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||||
|
"FGMultiplayMgr::MP_ProcessData - "
|
||||||
|
<< "Position message received with more data than I can handle" );
|
||||||
}
|
}
|
||||||
PosMsg = (T_PositionMsg *)(Msg + sizeof(T_MsgHdr));
|
PosMsg = (T_PositionMsg *)(Msg + sizeof(T_MsgHdr));
|
||||||
Position[0] = XDR_decode_double (PosMsg->PlayerPosition[0]);
|
time = XDR_decode_uint32 (PosMsg->time);
|
||||||
Position[1] = XDR_decode_double (PosMsg->PlayerPosition[1]);
|
timeusec = XDR_decode_uint32 (PosMsg->timeusec);
|
||||||
Position[2] = XDR_decode_double (PosMsg->PlayerPosition[2]);
|
lat = XDR_decode_double (PosMsg->lat);
|
||||||
Orientation[0] = XDR_decode_float (PosMsg->PlayerOrientation[0]);
|
lon = XDR_decode_double (PosMsg->lon);
|
||||||
Orientation[1] = XDR_decode_float (PosMsg->PlayerOrientation[1]);
|
alt = XDR_decode_double (PosMsg->alt);
|
||||||
Orientation[2] = XDR_decode_float (PosMsg->PlayerOrientation[2]);
|
hdg = XDR_decode_double (PosMsg->hdg);
|
||||||
Orientation[3] = XDR_decode_float (PosMsg->PlayerOrientation[3]);
|
roll = XDR_decode_double (PosMsg->roll);
|
||||||
|
pitch = XDR_decode_double (PosMsg->pitch);
|
||||||
|
speedN = XDR_decode_double (PosMsg->speedN);
|
||||||
|
speedE = XDR_decode_double (PosMsg->speedE);
|
||||||
|
speedD = XDR_decode_double (PosMsg->speedD);
|
||||||
|
left_aileron = XDR_decode_float (PosMsg->left_aileron);
|
||||||
|
right_aileron = XDR_decode_float (PosMsg->right_aileron);
|
||||||
|
elevator = XDR_decode_float (PosMsg->elevator);
|
||||||
|
rudder = XDR_decode_float (PosMsg->rudder);
|
||||||
|
/*for (int i = 0; i < 6; i++) {
|
||||||
|
rpms[i] = XDR_decode_float (PosMsg->rpms[i]);
|
||||||
|
}*/
|
||||||
|
rateH = XDR_decode_float (PosMsg->rateH);
|
||||||
|
rateR = XDR_decode_float (PosMsg->rateR);
|
||||||
|
rateP = XDR_decode_float (PosMsg->rateP);
|
||||||
|
accN = XDR_decode_float (PosMsg->accN);
|
||||||
|
accE = XDR_decode_float (PosMsg->accE);
|
||||||
|
accD = XDR_decode_float (PosMsg->accD);
|
||||||
|
|
||||||
//////////////////////////////////////////////////
|
//////////////////////////////////////////////////
|
||||||
// Check if the player is already in the game
|
// Check if the player is already in the game
|
||||||
// by using the Callsign
|
// by using the Callsign
|
||||||
|
@ -432,8 +534,16 @@ FGMultiplayMgr::ProcessPosMsg
|
||||||
{
|
{
|
||||||
if ((*CurrentPlayer)->CompareCallsign(MsgHdr->Callsign))
|
if ((*CurrentPlayer)->CompareCallsign(MsgHdr->Callsign))
|
||||||
{
|
{
|
||||||
// Player found. Update the data for the player.
|
// Player found. Update the data for the player if the timestamp is OK
|
||||||
(*CurrentPlayer)->SetPosition(Orientation, Position);
|
if ((*CurrentPlayer)->CheckTime(time, timeusec))
|
||||||
|
(*CurrentPlayer)->SetPosition(lat, lon, alt,
|
||||||
|
hdg, roll, pitch,
|
||||||
|
speedN, speedE, speedD,
|
||||||
|
left_aileron, right_aileron, elevator, rudder,
|
||||||
|
//rpms,
|
||||||
|
rateH, rateR, rateP,
|
||||||
|
accN, accE, accD
|
||||||
|
);
|
||||||
ActivePlayer = true;
|
ActivePlayer = true;
|
||||||
}
|
}
|
||||||
} // for (...)
|
} // for (...)
|
||||||
|
@ -448,8 +558,19 @@ FGMultiplayMgr::ProcessPosMsg
|
||||||
NewPlayer = new MPPlayer;
|
NewPlayer = new MPPlayer;
|
||||||
NewPlayer->Open(SenderAddress.getHost(), MsgHdr->ReplyPort,
|
NewPlayer->Open(SenderAddress.getHost(), MsgHdr->ReplyPort,
|
||||||
MsgHdr->Callsign, PosMsg->Model, false);
|
MsgHdr->Callsign, PosMsg->Model, false);
|
||||||
NewPlayer->SetPosition(Orientation, Position);
|
if (NewPlayer->CheckTime(time, timeusec))
|
||||||
|
NewPlayer->SetPosition(lat, lon, alt,
|
||||||
|
hdg, roll, pitch,
|
||||||
|
speedN, speedE, speedD,
|
||||||
|
left_aileron, right_aileron, elevator, rudder,
|
||||||
|
//rpms,
|
||||||
|
rateH, rateR, rateP,
|
||||||
|
accN, accE, accD);
|
||||||
m_MPClientList.push_back (NewPlayer);
|
m_MPClientList.push_back (NewPlayer);
|
||||||
|
|
||||||
|
// if we have a new player then we need to send all our properties
|
||||||
|
send_all_props = true;
|
||||||
|
|
||||||
} // FGMultiplayMgr::ProcessPosMsg()
|
} // FGMultiplayMgr::ProcessPosMsg()
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -470,19 +591,77 @@ FGMultiplayMgr::ProcessChatMsg
|
||||||
T_MsgHdr* MsgHdr; // Pointer to header in received data
|
T_MsgHdr* MsgHdr; // Pointer to header in received data
|
||||||
|
|
||||||
MsgHdr = (T_MsgHdr *)Msg;
|
MsgHdr = (T_MsgHdr *)Msg;
|
||||||
if (MsgHdr->MsgLen != sizeof(T_MsgHdr) + sizeof(T_ChatMsg))
|
if (MsgHdr->MsgLen < sizeof(T_MsgHdr) + 1)
|
||||||
{
|
{
|
||||||
SG_LOG( SG_NETWORK, SG_ALERT,
|
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||||
"FGMultiplayMgr::MP_ProcessData - "
|
"FGMultiplayMgr::MP_ProcessData - "
|
||||||
<< "Chat message received with insufficient data" );
|
<< "Chat message received with insufficient data" );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *MsgBuf = new char[MsgHdr->MsgLen - sizeof(T_MsgHdr)];
|
||||||
|
strncpy(MsgBuf, ((T_ChatMsg *)(Msg + sizeof(T_MsgHdr)))->Text, MsgHdr->MsgLen - sizeof(T_MsgHdr));
|
||||||
|
MsgBuf[MsgHdr->MsgLen - sizeof(T_MsgHdr) - 1] = '\0';
|
||||||
|
|
||||||
ChatMsg = (T_ChatMsg *)(Msg + sizeof(T_MsgHdr));
|
ChatMsg = (T_ChatMsg *)(Msg + sizeof(T_MsgHdr));
|
||||||
SG_LOG ( SG_NETWORK, SG_ALERT,
|
SG_LOG ( SG_NETWORK, SG_ALERT,
|
||||||
"Chat [" << MsgHdr->Callsign << "]" << " " << ChatMsg->Text << endl);
|
"Chat [" << MsgHdr->Callsign << "]" << " " << MsgBuf << endl);
|
||||||
|
delete [] MsgBuf;
|
||||||
} // FGMultiplayMgr::ProcessChatMsg ()
|
} // FGMultiplayMgr::ProcessChatMsg ()
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// handle a property message
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
void FGMultiplayMgr::ProcessPropMsg ( const char *Msg, netAddress & SenderAddress )
|
||||||
|
{
|
||||||
|
T_PropertyMsg* PropMsg; // Pointer to the message itself
|
||||||
|
T_MsgHdr* MsgHdr; // Pointer to the message header
|
||||||
|
t_MPClientListIterator CurrentPlayer;
|
||||||
|
|
||||||
|
MsgHdr = (T_MsgHdr *) Msg;
|
||||||
|
|
||||||
|
if (MsgHdr->MsgLen < sizeof(T_MsgHdr) + sizeof(T_PropertyMsg)) {
|
||||||
|
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||||
|
"FGMultiplayMgr::MP_ProcessData - "
|
||||||
|
<< "Properties message received with insufficient data" );
|
||||||
|
return;
|
||||||
|
} else if (MsgHdr->MsgLen > sizeof(T_MsgHdr) + sizeof(T_PropertyMsg)) {
|
||||||
|
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||||
|
"FGMultiplayMgr::MP_ProcessData - "
|
||||||
|
<< "Properties message received with more data than I know how to handle" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropMsg = (T_PropertyMsg *)(Msg + sizeof(T_MsgHdr));
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
// Check if the player is already in the game
|
||||||
|
// by using the Callsign, but don't activate
|
||||||
|
// new players (they need to send a position
|
||||||
|
// message)
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
for (CurrentPlayer = m_MPClientList.begin ();
|
||||||
|
CurrentPlayer != m_MPClientList.end ();
|
||||||
|
CurrentPlayer++)
|
||||||
|
{
|
||||||
|
if ((*CurrentPlayer)->CompareCallsign(MsgHdr->Callsign))
|
||||||
|
{
|
||||||
|
// Player found. Update the data for the player.
|
||||||
|
(*CurrentPlayer)->SetProperty(PropMsg->property,
|
||||||
|
(SGPropertyNode::Type) XDR_decode_uint32(PropMsg->type),
|
||||||
|
XDR_decode_double(PropMsg->val));
|
||||||
|
SG_LOG( SG_NETWORK, SG_INFO,
|
||||||
|
"FGMultiplayMgr::MP_ProcessData - "
|
||||||
|
<< PropMsg->property
|
||||||
|
<< (SGPropertyNode::Type) XDR_decode_uint32(PropMsg->type)
|
||||||
|
<< XDR_decode_double(PropMsg->val) );
|
||||||
|
}
|
||||||
|
} // for (...)
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// For each active player, tell the player object
|
// For each active player, tell the player object
|
||||||
|
|
|
@ -44,6 +44,7 @@ SG_USING_STD(string);
|
||||||
SG_USING_STD(vector);
|
SG_USING_STD(vector);
|
||||||
|
|
||||||
#include <simgear/compiler.h>
|
#include <simgear/compiler.h>
|
||||||
|
#include <simgear/props/props.hxx>
|
||||||
#include <plib/netSocket.h>
|
#include <plib/netSocket.h>
|
||||||
#include <Main/globals.hxx>
|
#include <Main/globals.hxx>
|
||||||
|
|
||||||
|
@ -59,14 +60,28 @@ public:
|
||||||
bool init(void);
|
bool init(void);
|
||||||
void Close(void);
|
void Close(void);
|
||||||
// transmitter
|
// transmitter
|
||||||
void SendMyPosition (const sgQuat PlayerOrientation,
|
void SendMyPosition (const double lat, const double lon, const double alt,
|
||||||
const sgdVec3 PlayerPosition);
|
const double heading, const double roll, const double pitch,
|
||||||
|
const double speedN, const double speedE, const double speedD,
|
||||||
|
const double left_aileron, const double right_aileron, const double elevator, const double rudder,
|
||||||
|
//const double rpms[6],
|
||||||
|
const double rateH, const double rateR, const double rateP,
|
||||||
|
const double accN, const double accE, const double accD
|
||||||
|
);
|
||||||
|
void SendPropMessage (const string &property, SGPropertyNode::Type type, double value);
|
||||||
void SendTextMessage (const string &sMsgText) const;
|
void SendTextMessage (const string &sMsgText) const;
|
||||||
// receiver
|
// receiver
|
||||||
void ProcessData(void);
|
void ProcessData(void);
|
||||||
void ProcessPosMsg ( const char *Msg, netAddress & SenderAddress );
|
void ProcessPosMsg ( const char *Msg, netAddress & SenderAddress );
|
||||||
void ProcessChatMsg ( const char *Msg, netAddress & SenderAddress );
|
void ProcessChatMsg ( const char *Msg, netAddress & SenderAddress );
|
||||||
|
void ProcessPropMsg ( const char *Msg, netAddress & SenderAddress );
|
||||||
void Update(void);
|
void Update(void);
|
||||||
|
|
||||||
|
/* getters/setters */
|
||||||
|
bool getSendAllProps();
|
||||||
|
void setSendAllProps(bool s);
|
||||||
|
bool send_all_props;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef vector<MPPlayer*> t_MPClientList;
|
typedef vector<MPPlayer*> t_MPClientList;
|
||||||
typedef t_MPClientList::iterator t_MPClientListIterator;
|
typedef t_MPClientList::iterator t_MPClientListIterator;
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
// Written by Diarmuid Tyson, started February 2003.
|
// Written by Diarmuid Tyson, started February 2003.
|
||||||
// diarmuid.tyson@airservicesaustralia.com
|
// diarmuid.tyson@airservicesaustralia.com
|
||||||
//
|
//
|
||||||
|
// With addtions by Vivian Meazza, January 2006
|
||||||
|
//
|
||||||
// Copyright (C) 2003 Airservices Australia
|
// Copyright (C) 2003 Airservices Australia
|
||||||
//
|
//
|
||||||
// This program is free software; you can redistribute it and/or
|
// This program is free software; you can redistribute it and/or
|
||||||
|
@ -29,6 +31,8 @@
|
||||||
#include STL_STRING
|
#include STL_STRING
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include <simgear/debug/logstream.hxx>
|
#include <simgear/debug/logstream.hxx>
|
||||||
#include <simgear/scene/model/placement.hxx>
|
#include <simgear/scene/model/placement.hxx>
|
||||||
|
@ -53,22 +57,123 @@ const char sFG_MULTIPLAY_HID[] = FG_MULTIPLAY_HID;
|
||||||
******************************************************************/
|
******************************************************************/
|
||||||
FGMultiplay::FGMultiplay (const string &dir, const int rate, const string &host, const int port) {
|
FGMultiplay::FGMultiplay (const string &dir, const int rate, const string &host, const int port) {
|
||||||
|
|
||||||
set_hz(rate);
|
last_time = 0;
|
||||||
|
last_speedN = last_speedE = last_speedD = 0;
|
||||||
|
calcaccN = calcaccE = calcaccD = 0;
|
||||||
|
set_hz(rate);
|
||||||
|
|
||||||
set_direction(dir);
|
set_direction(dir);
|
||||||
|
|
||||||
if (get_direction() == SG_IO_IN) {
|
if (get_direction() == SG_IO_IN) {
|
||||||
|
|
||||||
fgSetInt("/sim/multiplay/rxport", port);
|
fgSetInt("/sim/multiplay/rxport", port);
|
||||||
fgSetString("/sim/multiplay/rxhost", host.c_str());
|
fgSetString("/sim/multiplay/rxhost", host.c_str());
|
||||||
|
|
||||||
} else if (get_direction() == SG_IO_OUT) {
|
} else if (get_direction() == SG_IO_OUT) {
|
||||||
|
|
||||||
fgSetInt("/sim/multiplay/txport", port);
|
fgSetInt("/sim/multiplay/txport", port);
|
||||||
fgSetString("/sim/multiplay/txhost", host.c_str());
|
fgSetString("/sim/multiplay/txhost", host.c_str());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lat_n = fgGetNode("/position/latitude-deg", true);
|
||||||
|
lon_n = fgGetNode("/position/longitude-deg", true);
|
||||||
|
alt_n = fgGetNode("/position/altitude-ft", true);
|
||||||
|
heading_n = fgGetNode("/orientation/heading-deg", true);
|
||||||
|
roll_n = fgGetNode("/orientation/roll-deg", true);
|
||||||
|
pitch_n = fgGetNode("/orientation/pitch-deg", true);
|
||||||
|
speedN_n = fgGetNode("/velocities/speed-north-fps", true);
|
||||||
|
speedE_n = fgGetNode("/velocities/speed-east-fps", true);
|
||||||
|
speedD_n = fgGetNode("/velocities/speed-down-fps", true);
|
||||||
|
left_aileron_n = fgGetNode("/surface-positions/left-aileron-pos-norm", true);
|
||||||
|
right_aileron_n = fgGetNode("/surface-positions/right-aileron-pos-norm", true);
|
||||||
|
elevator_n = fgGetNode("/surface-positions/elevator-pos-norm", true);
|
||||||
|
rudder_n = fgGetNode("/surface-positions/rudder-pos-norm", true);
|
||||||
|
/*rpms_n[0] = fgGetNode("/engines/engine/rpm", true);
|
||||||
|
rpms_n[1] = fgGetNode("/engines/engine[1]/rpm", true);
|
||||||
|
rpms_n[2] = fgGetNode("/engines/engine[2]/rpm", true);
|
||||||
|
rpms_n[3] = fgGetNode("/engines/engine[3]/rpm", true);
|
||||||
|
rpms_n[4] = fgGetNode("/engines/engine[4]/rpm", true);
|
||||||
|
rpms_n[5] = fgGetNode("/engines/engine[5]/rpm", true);*/
|
||||||
|
rateH_n = fgGetNode("/orientation/yaw-rate-degps", true);
|
||||||
|
rateR_n = fgGetNode("/orientation/roll-rate-degps", true);
|
||||||
|
rateP_n = fgGetNode("/orientation/pitch-rate-degps", true);
|
||||||
|
|
||||||
|
SGPropertyNode_ptr n = fgGetNode("/controls/flight/slats",true);
|
||||||
|
_node_cache *c = new _node_cache( n->getDoubleValue(), n );
|
||||||
|
props["controls/flight/slats"] = c;
|
||||||
|
|
||||||
|
n = fgGetNode("/controls/flight/speedbrake", true);
|
||||||
|
c = new _node_cache( n->getDoubleValue(), n );
|
||||||
|
props["controls/flight/speedbrake"] = c;
|
||||||
|
|
||||||
|
n = fgGetNode("/controls/flight/spoilers", true);
|
||||||
|
c = new _node_cache( n->getDoubleValue(), n );
|
||||||
|
props["controls/flight/spoilers"] = c;
|
||||||
|
|
||||||
|
n = fgGetNode("/controls/gear/gear-down", true);
|
||||||
|
c = new _node_cache( n->getDoubleValue(), n );
|
||||||
|
props["controls/gear/gear-down"] = c;
|
||||||
|
|
||||||
|
n = fgGetNode("/controls/lighting/nav-lights", true);
|
||||||
|
c = new _node_cache( n->getDoubleValue(), n );
|
||||||
|
props["controls/lighting/nav-lights"] = c;
|
||||||
|
|
||||||
|
n = fgGetNode("/surface-positions/flap-pos-norm", true);
|
||||||
|
c = new _node_cache( n->getDoubleValue(), n );
|
||||||
|
props["surface-positions/flap-pos-norm"] = c;
|
||||||
|
|
||||||
|
n = fgGetNode("/surface-positions/speedbrake-pos-norm", true);
|
||||||
|
c = new _node_cache( n->getDoubleValue(), n );
|
||||||
|
props["surface-positions/speedbrake-pos-norm"] = c;
|
||||||
|
|
||||||
|
for (int i = 0; i < 6; i++)
|
||||||
|
{
|
||||||
|
char *s = new char[32];
|
||||||
|
|
||||||
|
snprintf(s, 32, "engines/engine[%i]/n1", i);
|
||||||
|
n = fgGetNode(s, true);
|
||||||
|
c = new _node_cache( n->getDoubleValue(), n );
|
||||||
|
props["s"] = c;
|
||||||
|
|
||||||
|
snprintf(s, 32, "engines/engine[%i]/n2", i);
|
||||||
|
n = fgGetNode(s, true);
|
||||||
|
c = new _node_cache( n->getDoubleValue(), n );
|
||||||
|
props[s] = c;
|
||||||
|
|
||||||
|
snprintf(s, 32, "engines/engine[%i]/rpm", i);
|
||||||
|
n = fgGetNode(s, true);
|
||||||
|
c = new _node_cache( n->getDoubleValue(), n );
|
||||||
|
props[s] = c;
|
||||||
|
|
||||||
|
delete [] s;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < 5; j++)
|
||||||
|
{
|
||||||
|
char *s = new char[32];
|
||||||
|
|
||||||
|
snprintf(s, 32, "gear/gear[%i]/compression-norm", j);
|
||||||
|
n = fgGetNode(s, true);
|
||||||
|
c = new _node_cache( n->getDoubleValue(), n );
|
||||||
|
props["s"] = c;
|
||||||
|
|
||||||
|
snprintf(s, 32, "gear/gear[%i]/position-norm", j);
|
||||||
|
n = fgGetNode(s, true);
|
||||||
|
c = new _node_cache( n->getDoubleValue(), n );
|
||||||
|
props[s] = c;
|
||||||
|
#if 0
|
||||||
|
snprintf(s, 32, "gear/gear[%i]/rollspeed-ms", j);
|
||||||
|
n = fgGetNode(s, true);
|
||||||
|
c = new _node_cache( n->getDoubleValue(), n );
|
||||||
|
props[s] = c;
|
||||||
|
#endif
|
||||||
|
delete [] s;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = fgGetNode("gear/tailhook/position-norm", true);
|
||||||
|
c = new _node_cache( n->getDoubleValue(), n );
|
||||||
|
props["gear/tailhook/position-norm"] = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -77,6 +182,7 @@ FGMultiplay::FGMultiplay (const string &dir, const int rate, const string &host,
|
||||||
* Description: Destructor.
|
* Description: Destructor.
|
||||||
******************************************************************/
|
******************************************************************/
|
||||||
FGMultiplay::~FGMultiplay () {
|
FGMultiplay::~FGMultiplay () {
|
||||||
|
props.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -87,9 +193,9 @@ FGMultiplay::~FGMultiplay () {
|
||||||
bool FGMultiplay::open() {
|
bool FGMultiplay::open() {
|
||||||
|
|
||||||
if ( is_enabled() ) {
|
if ( is_enabled() ) {
|
||||||
SG_LOG( SG_IO, SG_ALERT, "This shouldn't happen, but the channel "
|
SG_LOG( SG_IO, SG_ALERT, "This shouldn't happen, but the channel "
|
||||||
<< "is already in use, ignoring" );
|
<< "is already in use, ignoring" );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
set_enabled(true);
|
set_enabled(true);
|
||||||
|
@ -111,17 +217,74 @@ bool FGMultiplay::process() {
|
||||||
|
|
||||||
} else if (get_direction() == SG_IO_OUT) {
|
} else if (get_direction() == SG_IO_OUT) {
|
||||||
|
|
||||||
sgMat4 posTrans;
|
double accN, accE, accD;
|
||||||
globals->get_aircraft_model()->get3DModel()->getTransform()->getTransform(posTrans);
|
string fdm = fgGetString("/sim/flight-model");
|
||||||
Point3D center = globals->get_scenery()->get_center();
|
|
||||||
sgdVec3 PlayerPosition;
|
|
||||||
sgdSetVec3(PlayerPosition, posTrans[3][0] + center[0],
|
|
||||||
posTrans[3][1] + center[1], posTrans[3][2] + center[2]);
|
|
||||||
sgQuat PlayerOrientation;
|
|
||||||
sgMatrixToQuat(PlayerOrientation, posTrans);
|
|
||||||
|
|
||||||
globals->get_multiplayer_mgr()->SendMyPosition(PlayerOrientation, PlayerPosition);
|
if(fdm == "jsb"){
|
||||||
|
calcAcc(speedN_n->getDoubleValue(),
|
||||||
|
speedE_n->getDoubleValue(),
|
||||||
|
speedD_n->getDoubleValue());
|
||||||
|
accN = calcaccN;
|
||||||
|
accE = calcaccE;
|
||||||
|
accD = calcaccD;
|
||||||
|
}else{
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG," not doing acc calc" << fdm);
|
||||||
|
accN = fgGetDouble("/accelerations/ned/north-accel-fps_sec");
|
||||||
|
accE = fgGetDouble("/accelerations/ned/east-accel-fps_sec");
|
||||||
|
accD = fgGetDouble("/accelerations/ned/down-accel-fps_sec");
|
||||||
|
}
|
||||||
|
|
||||||
|
globals->get_multiplayer_mgr()->SendMyPosition(
|
||||||
|
lat_n->getDoubleValue(),
|
||||||
|
lon_n->getDoubleValue(),
|
||||||
|
alt_n->getDoubleValue(),
|
||||||
|
heading_n->getDoubleValue(),
|
||||||
|
roll_n->getDoubleValue(),
|
||||||
|
pitch_n->getDoubleValue(),
|
||||||
|
speedN_n->getDoubleValue(),
|
||||||
|
speedE_n->getDoubleValue(),
|
||||||
|
speedD_n->getDoubleValue(),
|
||||||
|
left_aileron_n->getDoubleValue(),
|
||||||
|
right_aileron_n->getDoubleValue(),
|
||||||
|
elevator_n->getDoubleValue(),
|
||||||
|
rudder_n->getDoubleValue(),
|
||||||
|
rateH_n->getDoubleValue(),
|
||||||
|
rateR_n->getDoubleValue(),
|
||||||
|
rateP_n->getDoubleValue(),
|
||||||
|
accN, accE, accD);
|
||||||
|
|
||||||
|
// check for changes
|
||||||
|
for (propit = props.begin(); propit != props.end(); propit++)
|
||||||
|
{
|
||||||
|
double val = propit->second->val;
|
||||||
|
double curr_val = propit->second->node->getDoubleValue();
|
||||||
|
if (curr_val < val * 0.99 || curr_val > val * 1.01 )
|
||||||
|
{
|
||||||
|
SGPropertyNode::Type type = propit->second->node->getType();
|
||||||
|
propit->second->val = val = curr_val;
|
||||||
|
globals->get_multiplayer_mgr()->SendPropMessage(propit->first, type, val);
|
||||||
|
//cout << "Prop " << propit->first <<" type " << type << " val " << val << endl;
|
||||||
|
} else {
|
||||||
|
// cout << "no change" << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// send all properties when necessary
|
||||||
|
// FGMultiplayMgr::getSendAllProps();
|
||||||
|
bool send_all = globals->get_multiplayer_mgr()->getSendAllProps();
|
||||||
|
//cout << "send_all in " << send;
|
||||||
|
if (send_all){
|
||||||
|
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||||
|
"FGMultiplay::sending ALL property messages" );
|
||||||
|
for (propit = props.begin(); propit != props.end(); propit++) {
|
||||||
|
SGPropertyNode::Type type = propit->second->node->getType();
|
||||||
|
double val = propit->second->val;
|
||||||
|
globals->get_multiplayer_mgr()->SendPropMessage(propit->first, type, val);
|
||||||
|
}
|
||||||
|
send_all = false;
|
||||||
|
globals->get_multiplayer_mgr()->setSendAllProps(send_all);
|
||||||
|
}
|
||||||
|
//cout << " send_all out " << s << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -148,3 +311,39 @@ bool FGMultiplay::close() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: CalcAcc
|
||||||
|
* Description: Calculate accelerations given speedN, speedE, speedD
|
||||||
|
******************************************************************/
|
||||||
|
void FGMultiplay::calcAcc(double speedN, double speedE, double speedD)
|
||||||
|
{
|
||||||
|
double time, dt; //secs
|
||||||
|
/*double accN, accE, accD; */ //fps2
|
||||||
|
|
||||||
|
dt = 0;
|
||||||
|
|
||||||
|
time = fgGetDouble("/sim/time/elapsed-sec");
|
||||||
|
|
||||||
|
dt = time-last_time;
|
||||||
|
|
||||||
|
SG_LOG(SG_GENERAL, SG_DEBUG," doing acc calc"
|
||||||
|
<<"time: "<< time << " last " << last_time << " dt " << dt );
|
||||||
|
|
||||||
|
//calculate the accelerations
|
||||||
|
calcaccN = (speedN - last_speedN)/dt;
|
||||||
|
calcaccE = (speedE - last_speedE)/dt;
|
||||||
|
calcaccD = (speedD - last_speedD)/dt;
|
||||||
|
|
||||||
|
//set the properties
|
||||||
|
/*fgSetDouble("/accelerations/ned/north-accel-fps_sec",accN);
|
||||||
|
fgSetDouble("/accelerations/ned/east-accel-fps_sec",accE);
|
||||||
|
fgSetDouble("/accelerations/ned/down-accel-fps_sec",accN);*/
|
||||||
|
|
||||||
|
//save the values
|
||||||
|
last_time = time;
|
||||||
|
last_speedN = speedN;
|
||||||
|
last_speedE = speedE;
|
||||||
|
last_speedD = speedD;
|
||||||
|
|
||||||
|
}// end calcAcc
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
// Written by Diarmuid Tyson, started February 2003.
|
// Written by Diarmuid Tyson, started February 2003.
|
||||||
// diarmuid.tyson@airservicesaustralia.com
|
// diarmuid.tyson@airservicesaustralia.com
|
||||||
//
|
//
|
||||||
|
// With additions by Vivian Meazza, January 2006
|
||||||
|
//
|
||||||
// Copyright (C) 2003 Airservices Australia
|
// Copyright (C) 2003 Airservices Australia
|
||||||
//
|
//
|
||||||
// This program is free software; you can redistribute it and/or
|
// This program is free software; you can redistribute it and/or
|
||||||
|
@ -56,6 +58,8 @@ SG_USING_STD(string);
|
||||||
*
|
*
|
||||||
******************************************************************/
|
******************************************************************/
|
||||||
|
|
||||||
|
#include <simgear/props/props.hxx>
|
||||||
|
|
||||||
class FGMultiplay : public FGProtocol {
|
class FGMultiplay : public FGProtocol {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -65,21 +69,42 @@ public:
|
||||||
/** Destructor. */
|
/** Destructor. */
|
||||||
~FGMultiplay ();
|
~FGMultiplay ();
|
||||||
|
|
||||||
/** Enables the FGMultiplay object
|
/** Enables the FGMultiplay object. */
|
||||||
*/
|
|
||||||
bool open();
|
bool open();
|
||||||
|
|
||||||
/** Tells the multiplayer_mgr to send/receive data.
|
/** Tells the multiplayer_mgr to send/receive data. */
|
||||||
*/
|
|
||||||
bool process();
|
bool process();
|
||||||
|
|
||||||
/** Closes the multiplayer_mgr.
|
/** Closes the multiplayer_mgr. */
|
||||||
*/
|
|
||||||
bool close();
|
bool close();
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct _node_cache {
|
||||||
|
double val;
|
||||||
|
SGPropertyNode_ptr node;
|
||||||
|
_node_cache(double v, SGPropertyNode_ptr n) {
|
||||||
|
val = v; node = n;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/** calculate accelerations
|
||||||
|
*/
|
||||||
|
void calcAcc(double speedN, double speedE, double speedD);
|
||||||
|
|
||||||
|
double last_time ; //sec
|
||||||
|
double last_speedN, last_speedE, last_speedD; //fps
|
||||||
|
double calcaccN, calcaccE, calcaccD; //fps2
|
||||||
|
|
||||||
|
SGPropertyNode *lat_n, *lon_n, *alt_n;
|
||||||
|
SGPropertyNode *heading_n, *pitch_n, *roll_n;
|
||||||
|
SGPropertyNode *speedN_n, *speedE_n, *speedD_n;
|
||||||
|
SGPropertyNode *left_aileron_n, *right_aileron_n;
|
||||||
|
SGPropertyNode *elevator_n, *rudder_n;
|
||||||
|
// SGPropertyNode *rpms[5];
|
||||||
|
SGPropertyNode *rateH_n, *rateR_n, *rateP_n;
|
||||||
|
|
||||||
|
map<string,struct _node_cache*> props;
|
||||||
|
map<string,struct _node_cache*>::iterator propit;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif // _FG_MULTIPLAY_HXX
|
#endif // _FG_MULTIPLAY_HXX
|
||||||
|
|
Loading…
Reference in a new issue