Mathias Frhlich:
The new multiplayer patch with an extension to transmit some properties with the base package. The properties are transmitted in a way that will not immediately brake the packet format if we need new ones. Even if the maxmimum number needs to be limited somehow, that format might work well until we have an improoved packet format which is even more compact and that does not require to retransmit redundant information with each packet. That part is relatively fresh and based on that what Oliver provides on his multiplayer server web page. The properties are transferred to the client and I have modified the seahawks rudder animation property to use a relative property path to verify that it works appart from the fact that you can see it changing in the property browser. The movement is still a bit jerky, but that can be fixed/tuned later without again braking the packet format.
This commit is contained in:
parent
31621f50af
commit
da6568ad50
23 changed files with 1000 additions and 1279 deletions
12
configure.ac
12
configure.ac
|
@ -90,18 +90,6 @@ if test "x$with_logging" = "xno" ; then
|
|||
AC_DEFINE([FG_NDEBUG], 1, [Define for no logging output])
|
||||
fi
|
||||
|
||||
# Specify if we want to build with Multiplayer support
|
||||
# default to with_network=yes
|
||||
AC_ARG_WITH(multiplayer, [ --with-multiplayer Include multiplayer support [default=yes]])
|
||||
|
||||
if test "x$with_multiplayer" = "xno"; then
|
||||
echo "Building without any kind of multiplayer support"
|
||||
else
|
||||
echo "Building with multiplayer support"
|
||||
AC_DEFINE([FG_MPLAYER_AS], 1, [Define to build with multiplayer support])
|
||||
fi
|
||||
AM_CONDITIONAL(ENABLE_MPLAYER_AS, test "x$with_multiplayer" != "xno")
|
||||
|
||||
AC_ARG_ENABLE(sp_fdms, [ --enable-sp-fdms Include special purpose Flight Models], [enable_sp_fdms="$enableval"] )
|
||||
AC_DEFINE([ENABLE_SP_FMDS], test "x$enable_sp_fdms" = "xyes", [Define to include special purpose FDMs])
|
||||
AM_CONDITIONAL(ENABLE_SP_FDM, test "x$enable_sp_fdms" != "xno")
|
||||
|
|
|
@ -64,7 +64,6 @@ FGAIBase::FGAIBase(object_type ot)
|
|||
invisible = true;
|
||||
no_roll = true;
|
||||
life = 900;
|
||||
index = 0;
|
||||
delete_me = false;
|
||||
}
|
||||
|
||||
|
@ -74,10 +73,13 @@ FGAIBase::~FGAIBase() {
|
|||
globals->get_scenery()->unregister_placement_transform(aip.getTransform());
|
||||
globals->get_scenery()->get_scene_graph()->removeKid(aip.getSceneGraph());
|
||||
}
|
||||
SGPropertyNode *root = globals->get_props()->getNode("ai/models", true);
|
||||
root->removeChild(getTypeString(), index);
|
||||
if (props) {
|
||||
SGPropertyNode* parent = props->getParent();
|
||||
if (parent)
|
||||
parent->removeChild(props->getName(), props->getIndex());
|
||||
}
|
||||
delete fp;
|
||||
fp = NULL;
|
||||
fp = 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -121,7 +123,8 @@ bool FGAIBase::init() {
|
|||
|
||||
SGPropertyNode *root = globals->get_props()->getNode("ai/models", true);
|
||||
|
||||
index = manager->getNum(_otype) - 1;
|
||||
unsigned index = root->getChildren(getTypeString()).size();
|
||||
|
||||
props = root->getNode(getTypeString(), index, true);
|
||||
|
||||
if (!model_path.empty()) {
|
||||
|
|
|
@ -131,8 +131,6 @@ protected:
|
|||
void CalculateMach();
|
||||
double UpdateRadar(FGAIManager* manager);
|
||||
|
||||
int index;
|
||||
|
||||
static int _newAIModelID();
|
||||
|
||||
private:
|
||||
|
|
|
@ -34,10 +34,8 @@
|
|||
#include "AIMultiplayer.hxx"
|
||||
|
||||
FGAIManager::FGAIManager() {
|
||||
for (int i=0; i < FGAIBase::MAX_OBJECTS; i++)
|
||||
numObjects[i] = 0;
|
||||
_dt = 0.0;
|
||||
scenario_filename = "";
|
||||
mNumAiModels = 0;
|
||||
}
|
||||
|
||||
FGAIManager::~FGAIManager() {
|
||||
|
@ -88,7 +86,8 @@ void FGAIManager::reinit() {
|
|||
|
||||
void FGAIManager::bind() {
|
||||
root = globals->get_props()->getNode("ai/models", true);
|
||||
root->tie("count", SGRawValuePointer<int>(&numObjects[0]));
|
||||
root->tie("count", SGRawValueMethods<FGAIManager, int>(*this,
|
||||
&FGAIManager::getNumAiObjects));
|
||||
}
|
||||
|
||||
|
||||
|
@ -102,27 +101,19 @@ void FGAIManager::update(double dt) {
|
|||
// initialize these for finding nearest thermals
|
||||
range_nearest = 10000.0;
|
||||
strength = 0.0;
|
||||
FGTrafficManager *tmgr = (FGTrafficManager*) globals->get_subsystem("Traffic Manager");
|
||||
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
FGTrafficManager *tmgr = (FGTrafficManager*) globals->get_subsystem("Traffic Manager");
|
||||
_dt = dt;
|
||||
|
||||
ai_list_iterator ai_list_itr = ai_list.begin();
|
||||
while(ai_list_itr != ai_list.end()) {
|
||||
if ((*ai_list_itr)->getDie()) {
|
||||
tmgr->release((*ai_list_itr)->getID());
|
||||
--numObjects[(*ai_list_itr)->getType()];
|
||||
--numObjects[0];
|
||||
--mNumAiModels;
|
||||
(*ai_list_itr)->unbind();
|
||||
if ( ai_list_itr == ai_list.begin() ) {
|
||||
ai_list.erase(ai_list_itr);
|
||||
ai_list_itr = ai_list.begin();
|
||||
continue;
|
||||
} else {
|
||||
ai_list.erase(ai_list_itr--);
|
||||
}
|
||||
ai_list_itr = ai_list.erase(ai_list_itr);
|
||||
} else {
|
||||
fetchUserState();
|
||||
if ((*ai_list_itr)->isa(FGAIBase::otThermal)) {
|
||||
|
@ -131,9 +122,9 @@ void FGAIManager::update(double dt) {
|
|||
} else {
|
||||
(*ai_list_itr)->update(_dt);
|
||||
}
|
||||
}
|
||||
++ai_list_itr;
|
||||
}
|
||||
}
|
||||
wind_from_down_node->setDoubleValue( strength ); // for thermals
|
||||
}
|
||||
|
||||
|
@ -142,8 +133,7 @@ FGAIManager::attach(SGSharedPtr<FGAIBase> model)
|
|||
{
|
||||
model->setManager(this);
|
||||
ai_list.push_back(model);
|
||||
++numObjects[0];
|
||||
++numObjects[model->getType()];
|
||||
++mNumAiModels;
|
||||
model->init();
|
||||
model->bind();
|
||||
}
|
||||
|
@ -153,16 +143,19 @@ void FGAIManager::destroyObject( int ID ) {
|
|||
ai_list_iterator ai_list_itr = ai_list.begin();
|
||||
while(ai_list_itr != ai_list.end()) {
|
||||
if ((*ai_list_itr)->getID() == ID) {
|
||||
--numObjects[0];
|
||||
--numObjects[(*ai_list_itr)->getType()];
|
||||
--mNumAiModels;
|
||||
(*ai_list_itr)->unbind();
|
||||
ai_list.erase(ai_list_itr);
|
||||
break;
|
||||
}
|
||||
ai_list_itr = ai_list.erase(ai_list_itr);
|
||||
} else
|
||||
++ai_list_itr;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
FGAIManager::getNumAiObjects(void) const
|
||||
{
|
||||
return mNumAiModels;
|
||||
}
|
||||
|
||||
void FGAIManager::fetchUserState( void ) {
|
||||
user_latitude = user_latitude_node->getDoubleValue();
|
||||
|
@ -174,8 +167,6 @@ void FGAIManager::fetchUserState( void ) {
|
|||
user_speed = user_speed_node->getDoubleValue() * 0.592484;
|
||||
wind_from_east = wind_from_east_node->getDoubleValue();
|
||||
wind_from_north = wind_from_north_node->getDoubleValue();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -95,9 +95,7 @@ public:
|
|||
inline double get_wind_from_east() const {return wind_from_east; }
|
||||
inline double get_wind_from_north() const {return wind_from_north; }
|
||||
|
||||
inline int getNum( FGAIBase::object_type ot ) const {
|
||||
return (0 < ot && ot < FGAIBase::MAX_OBJECTS) ? numObjects[ot] : numObjects[0];
|
||||
}
|
||||
int getNumAiObjects(void) const;
|
||||
|
||||
void processScenario( const string &filename );
|
||||
|
||||
|
@ -112,7 +110,8 @@ public:
|
|||
private:
|
||||
|
||||
bool enabled;
|
||||
int numObjects[FGAIBase::MAX_OBJECTS];
|
||||
int mNumAiModels;
|
||||
|
||||
SGPropertyNode* root;
|
||||
SGPropertyNode* wind_from_down_node;
|
||||
SGPropertyNode* user_latitude_node;
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
// 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
|
||||
|
@ -26,51 +25,18 @@
|
|||
# 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;
|
||||
|
||||
// #define SG_DEBUG SG_ALERT
|
||||
|
||||
FGAIMultiplayer::FGAIMultiplayer() : FGAIBase(otMultiplayer) {
|
||||
_time_node = fgGetNode("/sim/time/elapsed-sec", true);
|
||||
no_roll = false;
|
||||
|
||||
//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;
|
||||
mTimeOffsetSet = false;
|
||||
mAllowExtrapolation = true;
|
||||
mLagAdjustSystemSpeed = 10;
|
||||
}
|
||||
|
||||
|
||||
|
@ -83,192 +49,273 @@ bool FGAIMultiplayer::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));
|
||||
#define AIMPROProp(type, name) \
|
||||
SGRawValueMethods<FGAIMultiplayer, type>(*this, &FGAIMultiplayer::get##name)
|
||||
|
||||
#define AIMPRWProp(type, name) \
|
||||
SGRawValueMethods<FGAIMultiplayer, type>(*this, \
|
||||
&FGAIMultiplayer::get##name, &FGAIMultiplayer::set##name)
|
||||
|
||||
props->setDoubleValue("sim/current-view/view-number", 1);
|
||||
props->tie("callsign", AIMPROProp(const char *, CallSign));
|
||||
|
||||
}
|
||||
|
||||
void FGAIMultiplayer::setCompany(string comp) {
|
||||
company = comp;
|
||||
if (props)
|
||||
props->setStringValue("callsign", company.c_str());
|
||||
props->tie("controls/allow-extrapolation",
|
||||
AIMPRWProp(bool, AllowExtrapolation));
|
||||
props->tie("controls/lag-adjust-system-speed",
|
||||
AIMPRWProp(double, LagAdjustSystemSpeed));
|
||||
|
||||
#undef AIMPROProp
|
||||
#undef AIMPRWProp
|
||||
}
|
||||
|
||||
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");
|
||||
props->untie("callsign");
|
||||
props->untie("controls/allow-extrapolation");
|
||||
props->untie("controls/lag-adjust-system-speed");
|
||||
}
|
||||
|
||||
|
||||
void FGAIMultiplayer::update(double dt) {
|
||||
void FGAIMultiplayer::update(double dt)
|
||||
{
|
||||
if (dt <= 0)
|
||||
return;
|
||||
|
||||
FGAIBase::update(dt);
|
||||
Run(dt);
|
||||
Transform();
|
||||
}
|
||||
|
||||
// Check if we already got data
|
||||
if (mMotionInfo.empty())
|
||||
return;
|
||||
|
||||
void FGAIMultiplayer::Run(double dt) {
|
||||
// The current simulation time we need to update for,
|
||||
// note that the simulation time is updated before calling all the
|
||||
// update methods. Thus it contains the time intervals *end* time
|
||||
double curtime = globals->get_sim_time_sec();
|
||||
|
||||
// strangely, this is called with a dt of 0 quite often
|
||||
// Get the last available time
|
||||
MotionInfo::reverse_iterator it = mMotionInfo.rbegin();
|
||||
double curentPkgTime = it->second.time;
|
||||
|
||||
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));
|
||||
// Dynamically optimize the time offset between the feeder and the client
|
||||
// Well, 'dynamically' means that the dynamic of that update must be very
|
||||
// slow. You would otherwise notice huge jumps in the multiplayer models.
|
||||
// The reason is that we want to avoid huge extrapolation times since
|
||||
// extrapolation is highly error prone. For that we need something
|
||||
// approaching the average latency of the packets. This first order lag
|
||||
// component will provide this. We just take the error of the currently
|
||||
// requested time to the most recent available packet. This is the
|
||||
// target we want to reach in average.
|
||||
double lag = it->second.lag;
|
||||
if (!mTimeOffsetSet) {
|
||||
mTimeOffsetSet = true;
|
||||
mTimeOffset = curentPkgTime - curtime - lag;
|
||||
} 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));
|
||||
double offset = curentPkgTime - curtime - lag;
|
||||
if (!mAllowExtrapolation && offset + lag < mTimeOffset) {
|
||||
mTimeOffset = offset;
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "Resetting time offset adjust system to "
|
||||
"avoid extrapolation: time offset = " << mTimeOffset);
|
||||
} 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));
|
||||
// the error of the offset, respectively the negative error to avoid
|
||||
// a minus later ...
|
||||
double err = offset - mTimeOffset;
|
||||
// limit errors leading to shorter lag values somehow, that is late
|
||||
// arriving packets will pessimize the overall lag much more than
|
||||
// early packets will shorten the overall lag
|
||||
double sysSpeed;
|
||||
if (err < 0) {
|
||||
// Ok, we have some very late packets and nothing newer increase the
|
||||
// lag by the given speedadjust
|
||||
sysSpeed = mLagAdjustSystemSpeed*err;
|
||||
} else {
|
||||
// skip the filter
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG,"alt high pass filter");
|
||||
damp_alt = raw_alt;
|
||||
// We have a too pessimistic display delay shorten that a small bit
|
||||
sysSpeed = SGMiscd::min(0.1*err*err, 0.5);
|
||||
}
|
||||
|
||||
// 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;
|
||||
// simple euler integration for that first order system including some
|
||||
// overshooting guard to prevent to aggressive system speeds
|
||||
// (stiff systems) to explode the systems state
|
||||
double systemIncrement = dt*sysSpeed;
|
||||
if (fabs(err) < fabs(systemIncrement))
|
||||
systemIncrement = err;
|
||||
mTimeOffset += systemIncrement;
|
||||
|
||||
// set new position
|
||||
pos.setlat( damp_lat );
|
||||
pos.setlon( damp_lon );
|
||||
pos.setelev( damp_alt * SG_FEET_TO_METER );
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "Offset adjust system: time offset = "
|
||||
<< mTimeOffset << ", expected longitudinal position error due to "
|
||||
" current adjustment of the offset: "
|
||||
<< fabs(norm(it->second.linearVel)*systemIncrement));
|
||||
}
|
||||
}
|
||||
|
||||
//save the values
|
||||
time_stamp = time;
|
||||
|
||||
// Compute the time in the feeders time scale which fits the current time
|
||||
// we need to
|
||||
double tInterp = curtime + mTimeOffset;
|
||||
|
||||
SGVec3d ecPos;
|
||||
SGQuatf ecOrient;
|
||||
if (tInterp <= curentPkgTime) {
|
||||
// Ok, we need a time prevous to the last available packet,
|
||||
// that is good ...
|
||||
|
||||
// Find the first packet before the target time
|
||||
MotionInfo::iterator nextIt = mMotionInfo.upper_bound(tInterp);
|
||||
if (nextIt == mMotionInfo.begin()) {
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "Taking oldest packet!");
|
||||
// We have no packet before the target time, just use the first one
|
||||
MotionInfo::iterator firstIt = mMotionInfo.begin();
|
||||
ecPos = firstIt->second.position;
|
||||
ecOrient = firstIt->second.orientation;
|
||||
|
||||
std::vector<FGFloatPropertyData>::const_iterator firstPropIt;
|
||||
std::vector<FGFloatPropertyData>::const_iterator firstPropItEnd;
|
||||
firstPropIt = firstIt->second.properties.begin();
|
||||
firstPropItEnd = firstIt->second.properties.end();
|
||||
while (firstPropIt != firstPropItEnd) {
|
||||
float val = firstPropIt->value;
|
||||
PropertyMap::iterator pIt = mPropertyMap.find(firstPropIt->id);
|
||||
if (pIt != mPropertyMap.end())
|
||||
pIt->second->setFloatValue(val);
|
||||
++firstPropIt;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Ok, we have really found something where our target time is in between
|
||||
// do interpolation here
|
||||
MotionInfo::iterator prevIt = nextIt;
|
||||
--prevIt;
|
||||
|
||||
// Interpolation coefficient is between 0 and 1
|
||||
double intervalStart = prevIt->second.time;
|
||||
double intervalEnd = nextIt->second.time;
|
||||
double intervalLen = intervalEnd - intervalStart;
|
||||
double tau = (tInterp - intervalStart)/intervalLen;
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "Multiplayer vehicle interpolation: ["
|
||||
<< intervalStart << ", " << intervalEnd << "], intervalLen = "
|
||||
<< intervalLen << ", interpolation parameter = " << tau);
|
||||
|
||||
// Here we do just linear interpolation on the position
|
||||
ecPos = ((1-tau)*prevIt->second.position + tau*nextIt->second.position);
|
||||
ecOrient = interpolate((float)tau, prevIt->second.orientation,
|
||||
nextIt->second.orientation);
|
||||
|
||||
if (prevIt->second.properties.size()
|
||||
== nextIt->second.properties.size()) {
|
||||
std::vector<FGFloatPropertyData>::const_iterator prevPropIt;
|
||||
std::vector<FGFloatPropertyData>::const_iterator prevPropItEnd;
|
||||
std::vector<FGFloatPropertyData>::const_iterator nextPropIt;
|
||||
std::vector<FGFloatPropertyData>::const_iterator nextPropItEnd;
|
||||
prevPropIt = prevIt->second.properties.begin();
|
||||
prevPropItEnd = prevIt->second.properties.end();
|
||||
nextPropIt = nextIt->second.properties.begin();
|
||||
nextPropItEnd = nextIt->second.properties.end();
|
||||
while (prevPropIt != prevPropItEnd) {
|
||||
float val = (1-tau)*prevPropIt->value + tau*nextPropIt->value;
|
||||
PropertyMap::iterator pIt = mPropertyMap.find(prevPropIt->id);
|
||||
if (pIt != mPropertyMap.end())
|
||||
pIt->second->setFloatValue(val);
|
||||
++prevPropIt;
|
||||
++nextPropIt;
|
||||
}
|
||||
}
|
||||
|
||||
// Now throw away too old data
|
||||
if (prevIt != mMotionInfo.begin()) {
|
||||
--prevIt;
|
||||
mMotionInfo.erase(mMotionInfo.begin(), prevIt);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Ok, we need to predict the future, so, take the best data we can have
|
||||
// and do some eom computation to guess that for now.
|
||||
FGExternalMotionData motionInfo = it->second;
|
||||
|
||||
// The time to predict, limit to 5 seconds
|
||||
double t = tInterp - motionInfo.time;
|
||||
t = SGMisc<double>::min(t, 5);
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "Multiplayer vehicle extrapolation: "
|
||||
"extrapolation time = " << t);
|
||||
|
||||
// Do a few explicit euler steps with the constant acceleration's
|
||||
// This must be sufficient ...
|
||||
ecPos = motionInfo.position;
|
||||
ecOrient = motionInfo.orientation;
|
||||
SGVec3f linearVel = motionInfo.linearVel;
|
||||
SGVec3f angularVel = motionInfo.angularVel;
|
||||
while (0 < t) {
|
||||
double h = 1e-1;
|
||||
if (t < h)
|
||||
h = t;
|
||||
|
||||
SGVec3d ecVel = toVec3d(ecOrient.backTransform(linearVel));
|
||||
ecPos += h*ecVel;
|
||||
ecOrient += h*ecOrient.derivative(angularVel);
|
||||
|
||||
linearVel += h*(cross(linearVel, angularVel) + motionInfo.linearAccel);
|
||||
angularVel += h*motionInfo.angularAccel;
|
||||
|
||||
t -= h;
|
||||
}
|
||||
|
||||
std::vector<FGFloatPropertyData>::const_iterator firstPropIt;
|
||||
std::vector<FGFloatPropertyData>::const_iterator firstPropItEnd;
|
||||
firstPropIt = it->second.properties.begin();
|
||||
firstPropItEnd = it->second.properties.end();
|
||||
while (firstPropIt != firstPropItEnd) {
|
||||
float val = firstPropIt->value;
|
||||
PropertyMap::iterator pIt = mPropertyMap.find(firstPropIt->id);
|
||||
if (pIt != mPropertyMap.end())
|
||||
pIt->second->setFloatValue(val);
|
||||
++firstPropIt;
|
||||
}
|
||||
}
|
||||
|
||||
// extract the position
|
||||
SGGeod geod = ecPos;
|
||||
pos.setlat(geod.getLatitudeDeg());
|
||||
pos.setlon(geod.getLongitudeDeg());
|
||||
pos.setelev(geod.getElevationM());
|
||||
|
||||
// The quaternion rotating from the earth centered frame to the
|
||||
// horizontal local frame
|
||||
SGQuatf qEc2Hl = SGQuatf::fromLonLat((float)geod.getLongitudeRad(),
|
||||
(float)geod.getLatitudeRad());
|
||||
// The orientation wrt the horizontal local frame
|
||||
SGQuatf hlOr = conj(qEc2Hl)*ecOrient;
|
||||
float hDeg, pDeg, rDeg;
|
||||
hlOr.getEulerDeg(hDeg, pDeg, rDeg);
|
||||
hdg = hDeg;
|
||||
roll = rDeg;
|
||||
pitch = pDeg;
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "Multiplayer position and orientation: "
|
||||
<< geod << ", " << hlOr);
|
||||
|
||||
//###########################//
|
||||
// do calculations for radar //
|
||||
//###########################//
|
||||
//double range_ft2 = UpdateRadar(manager);
|
||||
UpdateRadar(manager);
|
||||
|
||||
Transform();
|
||||
}
|
||||
|
||||
void FGAIMultiplayer::setTimeStamp()
|
||||
void
|
||||
FGAIMultiplayer::addMotionInfo(const FGExternalMotionData& motionInfo,
|
||||
long stamp)
|
||||
{
|
||||
// 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;
|
||||
mLastTimestamp = stamp;
|
||||
// Drop packets arriving out of order
|
||||
if (!mMotionInfo.empty() && motionInfo.time < mMotionInfo.rbegin()->first)
|
||||
return;
|
||||
mMotionInfo[motionInfo.time] = motionInfo;
|
||||
}
|
||||
|
||||
void
|
||||
FGAIMultiplayer::setDoubleProperty(const std::string& prop, double val)
|
||||
{
|
||||
SGPropertyNode* pNode = props->getChild(prop.c_str(), true);
|
||||
pNode->setDoubleValue(val);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
// 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
|
||||
//
|
||||
|
@ -22,82 +21,72 @@
|
|||
#ifndef _FG_AIMultiplayer_HXX
|
||||
#define _FG_AIMultiplayer_HXX
|
||||
|
||||
#include "AIManager.hxx"
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include <MultiPlayer/mpmessages.hxx>
|
||||
#include "AIBase.hxx"
|
||||
|
||||
//#include <Traffic/SchedFlight.hxx>
|
||||
//#include <Traffic/Schedule.hxx>
|
||||
|
||||
#include <string>
|
||||
SG_USING_STD(string);
|
||||
|
||||
|
||||
class FGAIMultiplayer : public FGAIBase {
|
||||
|
||||
public:
|
||||
FGAIMultiplayer();
|
||||
~FGAIMultiplayer();
|
||||
virtual ~FGAIMultiplayer();
|
||||
|
||||
bool init();
|
||||
virtual bool init();
|
||||
virtual void bind();
|
||||
virtual void unbind();
|
||||
void update(double dt);
|
||||
virtual void update(double dt);
|
||||
|
||||
void addMotionInfo(const FGExternalMotionData& motionInfo, long stamp);
|
||||
void setDoubleProperty(const std::string& prop, double val);
|
||||
|
||||
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();
|
||||
void setCallSign(const string& callSign)
|
||||
{ mCallSign = callSign; }
|
||||
const char* getCallSign(void) const
|
||||
{ return mCallSign.c_str(); }
|
||||
|
||||
inline SGPropertyNode *FGAIMultiplayer::getProps() { return props; }
|
||||
long getLastTimestamp(void) const
|
||||
{ return mLastTimestamp; }
|
||||
|
||||
void setAcType(string ac) { acType = ac; };
|
||||
void setCompany(string comp);
|
||||
void setAllowExtrapolation(bool allowExtrapolation)
|
||||
{ mAllowExtrapolation = allowExtrapolation; }
|
||||
bool getAllowExtrapolation(void) const
|
||||
{ return mAllowExtrapolation; }
|
||||
void setLagAdjustSystemSpeed(double lagAdjustSystemSpeed)
|
||||
{
|
||||
if (lagAdjustSystemSpeed < 0)
|
||||
lagAdjustSystemSpeed = 0;
|
||||
mLagAdjustSystemSpeed = lagAdjustSystemSpeed;
|
||||
}
|
||||
double getLagAdjustSystemSpeed(void) const
|
||||
{ return mLagAdjustSystemSpeed; }
|
||||
|
||||
void addPropertyId(unsigned id, const char* name)
|
||||
{ mPropertyMap[id] = props->getNode(name, true); }
|
||||
|
||||
virtual const char* getTypeString(void) const { return "multiplayer"; }
|
||||
|
||||
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;
|
||||
private:
|
||||
|
||||
SGPropertyNode_ptr _time_node;
|
||||
// Automatic sorting of motion data according to its timestamp
|
||||
typedef std::map<double,FGExternalMotionData> MotionInfo;
|
||||
MotionInfo mMotionInfo;
|
||||
|
||||
void Run(double dt);
|
||||
inline double sign(double x) { return (x < 0.0) ? -1.0 : 1.0; }
|
||||
// Map between the property id's from the multiplayers network packets
|
||||
// and the property nodes
|
||||
typedef std::map<unsigned, SGSharedPtr<SGPropertyNode> > PropertyMap;
|
||||
PropertyMap mPropertyMap;
|
||||
|
||||
string acType;
|
||||
string company;
|
||||
std::string mCallSign;
|
||||
|
||||
double mTimeOffset;
|
||||
bool mTimeOffsetSet;
|
||||
|
||||
/// Properties which are for now exposed for testing
|
||||
bool mAllowExtrapolation;
|
||||
double mLagAdjustSystemSpeed;
|
||||
|
||||
long mLastTimestamp;
|
||||
};
|
||||
|
||||
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
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
EXTRA_DIST = 3dfx.sh runfgfs.in runfgfs.bat.in \
|
||||
fg_os_sdl.cxx fg_os.cxx fg_os.hxx
|
||||
|
||||
if ENABLE_MPLAYER_AS
|
||||
MPLAYER_LIBS = $(top_builddir)/src/MultiPlayer/libMultiPlayer.a
|
||||
else
|
||||
MPLAYER_LIBS =
|
||||
endif
|
||||
|
||||
if ENABLE_SP_FDM
|
||||
SP_FDM_LIBS = $(top_builddir)/src/FDM/SP/libSPFDM.a
|
||||
|
|
|
@ -111,10 +111,7 @@
|
|||
#include <Time/sunsolver.hxx>
|
||||
#include <Time/tmp.hxx>
|
||||
#include <Traffic/TrafficMgr.hxx>
|
||||
|
||||
#ifdef FG_MPLAYER_AS
|
||||
#include <MultiPlayer/multiplaymgr.hxx>
|
||||
#endif
|
||||
|
||||
#include <Environment/environment_mgr.hxx>
|
||||
|
||||
|
@ -1805,14 +1802,12 @@ bool fgInitSubsystems() {
|
|||
globals->get_subsystem_mgr()->bind();
|
||||
globals->get_subsystem_mgr()->init();
|
||||
|
||||
#ifdef FG_MPLAYER_AS
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Initialize multiplayer subsystem
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
globals->set_multiplayer_mgr(new FGMultiplayMgr);
|
||||
globals->get_multiplayer_mgr()->init();
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Initialize the Nasal interpreter.
|
||||
|
|
|
@ -58,10 +58,7 @@
|
|||
#include <Network/ray.hxx>
|
||||
#include <Network/rul.hxx>
|
||||
#include <Network/generic.hxx>
|
||||
|
||||
#ifdef FG_MPLAYER_AS
|
||||
#include <Network/multiplay.hxx>
|
||||
#endif
|
||||
|
||||
#include "globals.hxx"
|
||||
#include "fg_io.hxx"
|
||||
|
@ -182,8 +179,6 @@ FGIO::parse_port_config( const string& config )
|
|||
else if (tokens[1] == "file") n--;
|
||||
FGGeneric *generic = new FGGeneric( tokens[n] );
|
||||
io = generic;
|
||||
|
||||
#ifdef FG_MPLAYER_AS
|
||||
} else if ( protocol == "multiplay" ) {\
|
||||
//Determine dir, rate, host & port
|
||||
string dir = tokens[1];
|
||||
|
@ -191,8 +186,6 @@ FGIO::parse_port_config( const string& config )
|
|||
string host = tokens[3];
|
||||
string port = tokens[4];
|
||||
return new FGMultiplay(dir, atoi(rate.c_str()), host, atoi(port.c_str()));
|
||||
#endif
|
||||
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -96,12 +96,12 @@ FGGlobals::FGGlobals() :
|
|||
FGGlobals::~FGGlobals()
|
||||
{
|
||||
delete soundmgr;
|
||||
delete io;
|
||||
delete subsystem_mgr;
|
||||
delete event_mgr;
|
||||
delete initial_state;
|
||||
delete props;
|
||||
delete commands;
|
||||
delete io;
|
||||
delete renderer;
|
||||
delete initial_waypoints;
|
||||
}
|
||||
|
|
|
@ -79,9 +79,7 @@ class FGLight;
|
|||
class FGModelMgr;
|
||||
class FGRouteMgr;
|
||||
class FGScenery;
|
||||
#ifdef FG_MPLAYER_AS
|
||||
class FGMultiplayMgr;
|
||||
#endif
|
||||
class FGPanel;
|
||||
class FGTileMgr;
|
||||
class FGViewMgr;
|
||||
|
@ -210,11 +208,8 @@ private:
|
|||
FGTACANList *channellist;
|
||||
FGFixList *fixlist;
|
||||
|
||||
|
||||
#ifdef FG_MPLAYER_AS
|
||||
//Mulitplayer managers
|
||||
FGMultiplayMgr *multiplayer_mgr;
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
|
@ -326,7 +321,6 @@ public:
|
|||
model_mgr = mgr;
|
||||
}
|
||||
|
||||
#ifdef FG_MPLAYER_AS
|
||||
inline FGMultiplayMgr *get_multiplayer_mgr () { return multiplayer_mgr; }
|
||||
|
||||
inline void set_multiplayer_mgr (FGMultiplayMgr * mgr)
|
||||
|
@ -334,8 +328,6 @@ public:
|
|||
multiplayer_mgr = mgr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
inline string_list *get_channel_options_list () {
|
||||
return channel_options_list;
|
||||
}
|
||||
|
|
|
@ -74,12 +74,7 @@
|
|||
#include <Time/fg_timer.hxx>
|
||||
#include <Environment/environment_mgr.hxx>
|
||||
#include <GUI/new_gui.hxx>
|
||||
|
||||
#ifdef FG_MPLAYER_AS
|
||||
#include <MultiPlayer/multiplaymgr.hxx>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#include "fg_commands.hxx"
|
||||
#include "fg_io.hxx"
|
||||
|
@ -454,19 +449,20 @@ static void fgMainLoop( void ) {
|
|||
++frames;
|
||||
#endif
|
||||
|
||||
// Update any multiplayer's network queues, the AIMultiplayer
|
||||
// implementation is an AI model and depends on that
|
||||
globals->get_multiplayer_mgr()->Update();
|
||||
|
||||
// Run ATC subsystem
|
||||
if (fgGetBool("/sim/atc/enabled"))
|
||||
globals->get_ATC_mgr()->update(delta_time_sec);
|
||||
|
||||
// Run the AI subsystem
|
||||
// FIXME: run that also if we have multiplying enabled since the
|
||||
// multiplayer information is interpreted by an AI model
|
||||
if (fgGetBool("/sim/ai-traffic/enabled"))
|
||||
globals->get_AI_mgr()->update(delta_time_sec);
|
||||
|
||||
#ifdef FG_MPLAYER_AS
|
||||
// Update any multiplayer models
|
||||
globals->get_multiplayer_mgr()->Update();
|
||||
#endif
|
||||
|
||||
// Run flight model
|
||||
|
||||
// Calculate model iterations needed for next frame
|
||||
|
|
|
@ -230,14 +230,11 @@ fgSetDefaults ()
|
|||
fgSetBool("/sim/freeze/clock", false);
|
||||
fgSetBool("/sim/freeze/fuel", false);
|
||||
|
||||
#ifdef FG_MPLAYER_AS
|
||||
fgSetString("/sim/multiplay/callsign", "callsign");
|
||||
fgSetString("/sim/multiplay/rxhost", "0");
|
||||
fgSetString("/sim/multiplay/txhost", "0");
|
||||
fgSetInt("/sim/multiplay/rxport", 0);
|
||||
fgSetInt("/sim/multiplay/txport", 0);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -1343,10 +1340,8 @@ struct OptionDesc {
|
|||
{"joyclient", true, OPTION_CHANNEL, "", false, "", 0 },
|
||||
{"jsclient", true, OPTION_CHANNEL, "", false, "", 0 },
|
||||
{"proxy", true, OPTION_FUNC, "", false, "", fgSetupProxy },
|
||||
#ifdef FG_MPLAYER_AS
|
||||
{"callsign", true, OPTION_STRING, "sim/multiplay/callsign", false, "", 0 },
|
||||
{"multiplay", true, OPTION_CHANNEL, "", false, "", 0 },
|
||||
#endif
|
||||
{"trace-read", true, OPTION_FUNC, "", false, "", fgOptTraceRead },
|
||||
{"trace-write", true, OPTION_FUNC, "", false, "", fgOptTraceWrite },
|
||||
{"log-level", true, OPTION_FUNC, "", false, "", fgOptLogLevel },
|
||||
|
|
|
@ -83,7 +83,6 @@ FGAircraftModel::~FGAircraftModel ()
|
|||
globals->get_scenery()->unregister_placement_transform(_aircraft->getTransform());
|
||||
|
||||
delete _aircraft;
|
||||
delete _scene;
|
||||
// SSG will delete it
|
||||
globals->get_scenery()->get_aircraft_branch()->removeKid(_selector);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
noinst_LIBRARIES = libMultiPlayer.a
|
||||
|
||||
libMultiPlayer_a_SOURCES = multiplaymgr.cxx multiplaymgr.hxx mpplayer.cxx mpplayer.hxx mpmessages.hxx tiny_xdr.cxx tiny_xdr.hxx
|
||||
libMultiPlayer_a_SOURCES = multiplaymgr.cxx multiplaymgr.hxx mpmessages.hxx tiny_xdr.cxx tiny_xdr.hxx
|
||||
|
||||
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
|
||||
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
// Written by Duncan McCreanor, started February 2003.
|
||||
// duncan.mccreanor@airservicesaustralia.com
|
||||
//
|
||||
// With minor additions be Vivian Meazza, January 2006
|
||||
//
|
||||
// Copyright (C) 2003 Airservices Australia
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
|
@ -37,8 +35,11 @@
|
|||
*
|
||||
******************************************************************/
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <plib/sg.h>
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
#include "tiny_xdr.hxx"
|
||||
|
||||
// magic value for messages
|
||||
|
@ -49,9 +50,11 @@ const uint32_t PROTO_VER = 0x00010001; // 1.1
|
|||
// Message identifiers
|
||||
#define CHAT_MSG_ID 1
|
||||
#define UNUSABLE_POS_DATA_ID 2
|
||||
#define OLD_POS_DATA_ID 3
|
||||
#define POS_DATA_ID 4
|
||||
#define PROP_MSG_ID 5
|
||||
#define OLD_OLD_POS_DATA_ID 3
|
||||
#define OLD_POS_DATA_ID 4
|
||||
#define OLD_PROP_MSG_ID 5
|
||||
#define RESET_DATA_ID 6
|
||||
#define POS_DATA_ID 7
|
||||
|
||||
// XDR demands 4 byte alignment, but some compilers use8 byte alignment
|
||||
// so it's safe to let the overall size of a network message be a
|
||||
|
@ -61,13 +64,8 @@ const uint32_t PROTO_VER = 0x00010001; // 1.1
|
|||
#define MAX_MODEL_NAME_LEN 96
|
||||
#define MAX_PROPERTY_LEN 52
|
||||
|
||||
/** Aircraft position message */
|
||||
typedef xdr_data2_t xdrPosition[3];
|
||||
typedef xdr_data_t xdrOrientation[4];
|
||||
|
||||
// Header for use with all messages sent
|
||||
class T_MsgHdr {
|
||||
public:
|
||||
struct T_MsgHdr {
|
||||
xdr_data_t Magic; // Magic Value
|
||||
xdr_data_t Version; // Protocoll version
|
||||
xdr_data_t MsgId; // Message identifier
|
||||
|
@ -78,50 +76,80 @@ public:
|
|||
};
|
||||
|
||||
// Chat message
|
||||
class T_ChatMsg {
|
||||
public:
|
||||
struct T_ChatMsg {
|
||||
char Text[MAX_CHAT_MSG_LEN]; // Text of chat message
|
||||
};
|
||||
|
||||
// Position message
|
||||
class T_PositionMsg {
|
||||
public:
|
||||
struct T_PositionMsg {
|
||||
char Model[MAX_MODEL_NAME_LEN]; // Name of the aircraft model
|
||||
xdr_data_t time; // Time when this packet was generated
|
||||
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
|
||||
|
||||
// Time when this packet was generated
|
||||
xdr_data2_t time;
|
||||
xdr_data2_t lag;
|
||||
|
||||
// position wrt the earth centered frame
|
||||
xdr_data2_t position[3];
|
||||
// orientation wrt the earth centered frame, stored in the angle axis
|
||||
// representation where the angle is coded into the axis length
|
||||
xdr_data_t orientation[3];
|
||||
|
||||
// linear velocity wrt the earth centered frame measured in
|
||||
// the earth centered frame
|
||||
xdr_data_t linearVel[3];
|
||||
// angular velocity wrt the earth centered frame measured in
|
||||
// the earth centered frame
|
||||
xdr_data_t angularVel[3];
|
||||
|
||||
// linear acceleration wrt the earth centered frame measured in
|
||||
// the earth centered frame
|
||||
xdr_data_t linearAccel[3];
|
||||
// angular acceleration wrt the earth centered frame measured in
|
||||
// the earth centered frame
|
||||
xdr_data_t angularAccel[3];
|
||||
};
|
||||
|
||||
// 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
|
||||
struct T_PropertyMsg {
|
||||
xdr_data_t id;
|
||||
xdr_data_t value;
|
||||
};
|
||||
|
||||
struct FGFloatPropertyData {
|
||||
unsigned id;
|
||||
float value;
|
||||
};
|
||||
|
||||
// Position message
|
||||
struct FGExternalMotionData {
|
||||
// simulation time when this packet was generated
|
||||
double time;
|
||||
// the artificial lag the client should stay behind the average
|
||||
// simulation time to arrival time diference
|
||||
// FIXME: should be some 'per model' instead of 'per packet' property
|
||||
double lag;
|
||||
|
||||
// position wrt the earth centered frame
|
||||
SGVec3d position;
|
||||
// orientation wrt the earth centered frame
|
||||
SGQuatf orientation;
|
||||
|
||||
// linear velocity wrt the earth centered frame measured in
|
||||
// the earth centered frame
|
||||
SGVec3f linearVel;
|
||||
// angular velocity wrt the earth centered frame measured in
|
||||
// the earth centered frame
|
||||
SGVec3f angularVel;
|
||||
|
||||
// linear acceleration wrt the earth centered frame measured in
|
||||
// the earth centered frame
|
||||
SGVec3f linearAccel;
|
||||
// angular acceleration wrt the earth centered frame measured in
|
||||
// the earth centered frame
|
||||
SGVec3f angularAccel;
|
||||
|
||||
// The set of properties recieved for this timeslot
|
||||
std::vector<FGFloatPropertyData> properties;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -5,10 +5,9 @@
|
|||
// Written by Duncan McCreanor, started February 2003.
|
||||
// duncan.mccreanor@airservicesaustralia.com
|
||||
//
|
||||
// With minor additions by Vivian Meazza, January 2006
|
||||
//
|
||||
// Copyright (C) 2003 Airservices Australia
|
||||
// Copyright (C) 2005 Oliver Schroeder
|
||||
// Copyright (C) 2006 Mathias Froehlich
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
|
@ -32,33 +31,89 @@
|
|||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef FG_MPLAYER_AS
|
||||
|
||||
#include <sys/types.h>
|
||||
#if !(defined(_MSC_VER) || defined(__MINGW32__))
|
||||
# include <sys/socket.h>
|
||||
# include <netinet/in.h>
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <plib/netSocket.h>
|
||||
|
||||
#include <simgear/timing/timestamp.hxx>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include <AIModel/AIManager.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
|
||||
#include "multiplaymgr.hxx"
|
||||
#include "mpmessages.hxx"
|
||||
#include "mpplayer.hxx"
|
||||
|
||||
#define MAX_PACKET_SIZE 1024
|
||||
#define MAX_PACKET_SIZE 1200
|
||||
|
||||
// These constants are provided so that the ident
|
||||
// command can list file versions
|
||||
const char sMULTIPLAYMGR_BID[] =
|
||||
"$Id$";
|
||||
const char sMULTIPLAYMGR_BID[] = "$Id$";
|
||||
const char sMULTIPLAYMGR_HID[] = MULTIPLAYTXMGR_HID;
|
||||
|
||||
// A static map of protocol property id values to property paths,
|
||||
// This should be extendable dynamically for every specific aircraft ...
|
||||
// For now only that static list
|
||||
FGMultiplayMgr::IdPropertyList
|
||||
FGMultiplayMgr::sIdPropertyList[] = {
|
||||
{100, "surface-positions/left-aileron-pos-norm"},
|
||||
{101, "surface-positions/right-aileron-pos-norm"},
|
||||
{102, "surface-positions/elevator-pos-norm"},
|
||||
{103, "surface-positions/rudder-pos-norm"},
|
||||
{104, "surface-positions/flap-pos-norm"},
|
||||
{105, "surface-positions/speedbrake-pos-norm"},
|
||||
{106, "gear/tailhook/position-norm"},
|
||||
|
||||
{200, "gear/gear[0]/compression-norm"},
|
||||
{201, "gear/gear[0]/position-norm"},
|
||||
{210, "gear/gear[1]/compression-norm"},
|
||||
{211, "gear/gear[1]/position-norm"},
|
||||
{220, "gear/gear[2]/compression-norm"},
|
||||
{221, "gear/gear[2]/position-norm"},
|
||||
{230, "gear/gear[3]/compression-norm"},
|
||||
{231, "gear/gear[3]/position-norm"},
|
||||
{240, "gear/gear[4]/compression-norm"},
|
||||
{241, "gear/gear[4]/position-norm"},
|
||||
|
||||
{300, "engines/engine[0]/n1"},
|
||||
{301, "engines/engine[0]/n2"},
|
||||
{302, "engines/engine[0]/rpm"},
|
||||
{310, "engines/engine[1]/n1"},
|
||||
{311, "engines/engine[1]/n2"},
|
||||
{312, "engines/engine[1]/rpm"},
|
||||
{320, "engines/engine[2]/n1"},
|
||||
{321, "engines/engine[2]/n2"},
|
||||
{322, "engines/engine[2]/rpm"},
|
||||
{330, "engines/engine[3]/n1"},
|
||||
{331, "engines/engine[3]/n2"},
|
||||
{332, "engines/engine[3]/rpm"},
|
||||
{340, "engines/engine[4]/n1"},
|
||||
{341, "engines/engine[4]/n2"},
|
||||
{342, "engines/engine[4]/rpm"},
|
||||
{350, "engines/engine[5]/n1"},
|
||||
{351, "engines/engine[5]/n2"},
|
||||
{352, "engines/engine[5]/rpm"},
|
||||
{360, "engines/engine[6]/n1"},
|
||||
{361, "engines/engine[6]/n2"},
|
||||
{362, "engines/engine[6]/rpm"},
|
||||
{370, "engines/engine[7]/n1"},
|
||||
{371, "engines/engine[7]/n2"},
|
||||
{372, "engines/engine[7]/rpm"},
|
||||
{380, "engines/engine[8]/n1"},
|
||||
{381, "engines/engine[8]/n2"},
|
||||
{382, "engines/engine[8]/rpm"},
|
||||
{390, "engines/engine[9]/n1"},
|
||||
{391, "engines/engine[9]/n2"},
|
||||
{392, "engines/engine[9]/rpm"},
|
||||
|
||||
{1001, "controls/flight/slats"},
|
||||
{1002, "controls/flight/speedbrake"},
|
||||
{1003, "controls/flight/spoilers"},
|
||||
{1004, "controls/gear/gear-down"},
|
||||
{1005, "controls/lighting/nav-lights"},
|
||||
|
||||
/// termination
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// MultiplayMgr constructor
|
||||
|
@ -66,14 +121,8 @@ const char sMULTIPLAYMGR_HID[] = MULTIPLAYTXMGR_HID;
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
FGMultiplayMgr::FGMultiplayMgr()
|
||||
{
|
||||
m_Initialised = false;
|
||||
m_LocalPlayer = NULL;
|
||||
m_RxAddress = "0";
|
||||
m_RxPort = 0;
|
||||
m_Initialised = false;
|
||||
m_HaveServer = false;
|
||||
|
||||
send_all_props= false;
|
||||
mInitialised = false;
|
||||
mHaveServer = false;
|
||||
} // FGMultiplayMgr::FGMultiplayMgr()
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -88,22 +137,6 @@ 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
|
||||
|
@ -112,76 +145,53 @@ void FGMultiplayMgr::setSendAllProps(bool s) {
|
|||
bool
|
||||
FGMultiplayMgr::init (void)
|
||||
{
|
||||
string TxAddress; // Destination address
|
||||
int TxPort;
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// Initialise object if not already done
|
||||
//////////////////////////////////////////////////
|
||||
if (m_Initialised)
|
||||
{
|
||||
SG_LOG( SG_NETWORK, SG_WARN,
|
||||
"FGMultiplayMgr::init - already initialised" );
|
||||
return (false);
|
||||
if (mInitialised) {
|
||||
SG_LOG(SG_NETWORK, SG_WARN, "FGMultiplayMgr::init - already initialised");
|
||||
return false;
|
||||
}
|
||||
//////////////////////////////////////////////////
|
||||
// Set members from property values
|
||||
//////////////////////////////////////////////////
|
||||
TxAddress = fgGetString ("/sim/multiplay/txhost");
|
||||
TxPort = fgGetInt ("/sim/multiplay/txport");
|
||||
m_Callsign = fgGetString ("/sim/multiplay/callsign");
|
||||
m_RxAddress = fgGetString ("/sim/multiplay/rxhost");
|
||||
m_RxPort = fgGetInt ("/sim/multiplay/rxport");
|
||||
if (m_RxPort <= 0)
|
||||
{
|
||||
m_RxPort = 5000;
|
||||
}
|
||||
if (m_Callsign == "")
|
||||
{
|
||||
short rxPort = fgGetInt("/sim/multiplay/rxport");
|
||||
if (rxPort <= 0)
|
||||
rxPort = 5000;
|
||||
mCallsign = fgGetString("/sim/multiplay/callsign");
|
||||
if (mCallsign.empty())
|
||||
// FIXME: use getpwuid
|
||||
m_Callsign = "JohnDoe";
|
||||
mCallsign = "JohnDoe";
|
||||
string rxAddress = fgGetString("/sim/multiplay/rxhost");
|
||||
if (rxAddress.empty())
|
||||
rxAddress = "127.0.0.1";
|
||||
short txPort = fgGetInt("/sim/multiplay/txport");
|
||||
string txAddress = fgGetString("/sim/multiplay/txhost");
|
||||
if (txPort > 0 && !txAddress.empty()) {
|
||||
mHaveServer = true;
|
||||
mServer.set(txAddress.c_str(), txPort);
|
||||
}
|
||||
if (m_RxAddress == "")
|
||||
{
|
||||
m_RxAddress = "127.0.0.1";
|
||||
}
|
||||
if ((TxPort > 0) && (TxAddress != ""))
|
||||
{
|
||||
m_HaveServer = true;
|
||||
m_Server.set (TxAddress.c_str(), TxPort);
|
||||
}
|
||||
SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-txaddress= "<<TxAddress);
|
||||
SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-txport= "<<TxPort );
|
||||
SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-rxaddress="<<m_RxAddress );
|
||||
SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-rxport= "<<m_RxPort);
|
||||
SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-callsign= "<<m_Callsign);
|
||||
m_DataSocket = new netSocket();
|
||||
if (!m_DataSocket->open(false))
|
||||
{
|
||||
SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-txaddress= "<<txAddress);
|
||||
SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-txport= "<<txPort );
|
||||
SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-rxaddress="<<rxAddress );
|
||||
SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-rxport= "<<rxPort);
|
||||
SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-callsign= "<<mCallsign);
|
||||
mSocket = new netSocket();
|
||||
if (!mSocket->open(false)) {
|
||||
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||
"FGMultiplayMgr::init - Failed to create data socket" );
|
||||
return (false);
|
||||
return false;
|
||||
}
|
||||
m_DataSocket->setBlocking(false);
|
||||
m_DataSocket->setBroadcast(true);
|
||||
if (m_DataSocket->bind(m_RxAddress.c_str(), m_RxPort) != 0)
|
||||
{
|
||||
mSocket->setBlocking(false);
|
||||
mSocket->setBroadcast(true);
|
||||
if (mSocket->bind(rxAddress.c_str(), rxPort) != 0) {
|
||||
perror("bind");
|
||||
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||
"FGMultiplayMgr::Open - Failed to bind receive socket" );
|
||||
return (false);
|
||||
return false;
|
||||
}
|
||||
m_LocalPlayer = new MPPlayer();
|
||||
if (!m_LocalPlayer->Open(m_RxAddress, m_RxPort, m_Callsign,
|
||||
fgGetString("/sim/model/path"), true))
|
||||
{
|
||||
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||
"FGMultiplayMgr::init - Failed to create local player" );
|
||||
return (false);
|
||||
}
|
||||
m_Initialised = true;
|
||||
send_all_props= true;
|
||||
return (true);
|
||||
mInitialised = true;
|
||||
return true;
|
||||
} // FGMultiplayMgr::init()
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -194,37 +204,14 @@ FGMultiplayMgr::init (void)
|
|||
void
|
||||
FGMultiplayMgr::Close (void)
|
||||
{
|
||||
//////////////////////////////////////////////////
|
||||
// Delete local player
|
||||
//////////////////////////////////////////////////
|
||||
if (m_LocalPlayer)
|
||||
{
|
||||
delete m_LocalPlayer;
|
||||
m_LocalPlayer = NULL;
|
||||
mMultiPlayerMap.clear();
|
||||
|
||||
if (mSocket) {
|
||||
mSocket->close();
|
||||
delete mSocket;
|
||||
mSocket = 0;
|
||||
}
|
||||
//////////////////////////////////////////////////
|
||||
// Delete any existing players
|
||||
//////////////////////////////////////////////////
|
||||
t_MPClientListIterator CurrentPlayer;
|
||||
t_MPClientListIterator P;
|
||||
CurrentPlayer = m_MPClientList.begin ();
|
||||
while (CurrentPlayer != m_MPClientList.end ())
|
||||
{
|
||||
P = CurrentPlayer;
|
||||
delete (*P);
|
||||
*P = 0;
|
||||
CurrentPlayer = m_MPClientList.erase (P);
|
||||
}
|
||||
//////////////////////////////////////////////////
|
||||
// Delete socket
|
||||
//////////////////////////////////////////////////
|
||||
if (m_DataSocket)
|
||||
{
|
||||
m_DataSocket->close();
|
||||
delete m_DataSocket;
|
||||
m_DataSocket = NULL;
|
||||
}
|
||||
m_Initialised = false;
|
||||
mInitialised = false;
|
||||
} // FGMultiplayMgr::Close(void)
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -234,83 +221,63 @@ FGMultiplayMgr::Close (void)
|
|||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
FGMultiplayMgr::SendMyPosition
|
||||
(
|
||||
const double lat, const double lon, const double alt,
|
||||
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
|
||||
)
|
||||
FGMultiplayMgr::SendMyPosition(const FGExternalMotionData& motionInfo)
|
||||
{
|
||||
T_MsgHdr MsgHdr;
|
||||
T_PositionMsg PosMsg;
|
||||
char Msg[sizeof(T_MsgHdr) + sizeof(T_PositionMsg)];
|
||||
|
||||
if ((! m_Initialised) || (! m_HaveServer))
|
||||
{
|
||||
if (! m_Initialised)
|
||||
if ((! mInitialised) || (! mHaveServer)) {
|
||||
if (! mInitialised)
|
||||
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||
"FGMultiplayMgr::SendMyPosition - not initialised" );
|
||||
if (! m_HaveServer)
|
||||
if (! mHaveServer)
|
||||
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||
"FGMultiplayMgr::SendMyPosition - no server" );
|
||||
return;
|
||||
}
|
||||
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);
|
||||
memcpy(Msg, &MsgHdr, sizeof(T_MsgHdr));
|
||||
|
||||
T_PositionMsg PosMsg;
|
||||
strncpy(PosMsg.Model, fgGetString("/sim/model/path"), MAX_MODEL_NAME_LEN);
|
||||
PosMsg.Model[MAX_MODEL_NAME_LEN - 1] = '\0';
|
||||
|
||||
PosMsg.time = XDR_encode_double (motionInfo.time);
|
||||
PosMsg.lag = XDR_encode_double (motionInfo.lag);
|
||||
for (unsigned i = 0 ; i < 3; ++i)
|
||||
PosMsg.position[i] = XDR_encode_double (motionInfo.position(i));
|
||||
SGVec3f angleAxis;
|
||||
motionInfo.orientation.getAngleAxis(angleAxis);
|
||||
for (unsigned i = 0 ; i < 3; ++i)
|
||||
PosMsg.orientation[i] = XDR_encode_float (angleAxis(i));
|
||||
for (unsigned i = 0 ; i < 3; ++i)
|
||||
PosMsg.linearVel[i] = XDR_encode_float (motionInfo.linearVel(i));
|
||||
for (unsigned i = 0 ; i < 3; ++i)
|
||||
PosMsg.angularVel[i] = XDR_encode_float (motionInfo.angularVel(i));
|
||||
for (unsigned i = 0 ; i < 3; ++i)
|
||||
PosMsg.linearAccel[i] = XDR_encode_float (motionInfo.linearAccel(i));
|
||||
for (unsigned i = 0 ; i < 3; ++i)
|
||||
PosMsg.angularAccel[i] = XDR_encode_float (motionInfo.angularAccel(i));
|
||||
|
||||
char Msg[MAX_PACKET_SIZE];
|
||||
memcpy(Msg + sizeof(T_MsgHdr), &PosMsg, sizeof(T_PositionMsg));
|
||||
m_DataSocket->sendto (Msg,
|
||||
sizeof(T_MsgHdr) + sizeof(T_PositionMsg), 0, &m_Server);
|
||||
SG_LOG( SG_NETWORK, SG_DEBUG,
|
||||
"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);
|
||||
char* ptr = Msg + sizeof(T_MsgHdr) + sizeof(T_PositionMsg);
|
||||
std::vector<FGFloatPropertyData>::const_iterator it;
|
||||
it = motionInfo.properties.begin();
|
||||
while (it != motionInfo.properties.end()
|
||||
&& ptr < (Msg + MAX_PACKET_SIZE - sizeof(T_PropertyMsg))) {
|
||||
T_PropertyMsg pMsg;
|
||||
pMsg.id = XDR_encode_uint32(it->id);
|
||||
pMsg.value = XDR_encode_float(it->value);
|
||||
memcpy(ptr, &pMsg, sizeof(T_PropertyMsg));
|
||||
ptr += sizeof(T_PropertyMsg);
|
||||
++it;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
FillMsgHdr(&MsgHdr, POS_DATA_ID, ptr - Msg);
|
||||
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 ()
|
||||
|
||||
mSocket->sendto(Msg, ptr - Msg, 0, &mServer);
|
||||
SG_LOG(SG_NETWORK, SG_DEBUG, "FGMultiplayMgr::SendMyPosition");
|
||||
} // FGMultiplayMgr::SendMyPosition()
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
@ -321,35 +288,28 @@ void FGMultiplayMgr::SendPropMessage (const string &property, SGPropertyNode::Ty
|
|||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
FGMultiplayMgr::SendTextMessage
|
||||
(
|
||||
const string &MsgText
|
||||
) const
|
||||
{
|
||||
T_MsgHdr MsgHdr;
|
||||
T_ChatMsg ChatMsg;
|
||||
unsigned int iNextBlockPosition = 0;
|
||||
char Msg[sizeof(T_MsgHdr) + sizeof(T_ChatMsg)];
|
||||
|
||||
if ((! m_Initialised) || (! m_HaveServer))
|
||||
FGMultiplayMgr::SendTextMessage(const string &MsgText)
|
||||
{
|
||||
if (!mInitialised || !mHaveServer)
|
||||
return;
|
||||
}
|
||||
m_LocalPlayer->FillMsgHdr(&MsgHdr, CHAT_MSG_ID);
|
||||
|
||||
T_MsgHdr MsgHdr;
|
||||
FillMsgHdr(&MsgHdr, CHAT_MSG_ID);
|
||||
//////////////////////////////////////////////////
|
||||
// Divide the text string into blocks that fit
|
||||
// in the message and send the blocks.
|
||||
//////////////////////////////////////////////////
|
||||
while (iNextBlockPosition < MsgText.length())
|
||||
{
|
||||
unsigned iNextBlockPosition = 0;
|
||||
T_ChatMsg ChatMsg;
|
||||
char Msg[sizeof(T_MsgHdr) + sizeof(T_ChatMsg)];
|
||||
while (iNextBlockPosition < MsgText.length()) {
|
||||
strncpy (ChatMsg.Text,
|
||||
MsgText.substr(iNextBlockPosition, MAX_CHAT_MSG_LEN - 1).c_str(),
|
||||
MAX_CHAT_MSG_LEN);
|
||||
ChatMsg.Text[MAX_CHAT_MSG_LEN - 1] = '\0';
|
||||
memcpy (Msg, &MsgHdr, sizeof(T_MsgHdr));
|
||||
memcpy (Msg + sizeof(T_MsgHdr), &ChatMsg, sizeof(T_ChatMsg));
|
||||
m_DataSocket->sendto (Msg,
|
||||
sizeof(T_MsgHdr) + sizeof(T_ChatMsg), 0, &m_Server);
|
||||
mSocket->sendto (Msg, sizeof(T_MsgHdr) + sizeof(T_ChatMsg), 0, &mServer);
|
||||
iNextBlockPosition += MAX_CHAT_MSG_LEN - 1;
|
||||
}
|
||||
} // FGMultiplayMgr::SendTextMessage ()
|
||||
|
@ -363,99 +323,97 @@ FGMultiplayMgr::SendTextMessage
|
|||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
FGMultiplayMgr::ProcessData (void)
|
||||
FGMultiplayMgr::Update(void)
|
||||
{
|
||||
char Msg[MAX_PACKET_SIZE]; // Buffer for received message
|
||||
int Bytes; // Bytes received
|
||||
T_MsgHdr* MsgHdr; // Pointer to header in received data
|
||||
netAddress SenderAddress;
|
||||
|
||||
if (! m_Initialised)
|
||||
{
|
||||
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||
"FGMultiplayMgr::ProcessData - not initialised" );
|
||||
if (!mInitialised)
|
||||
return;
|
||||
}
|
||||
|
||||
/// Just for expiry
|
||||
SGTimeStamp timestamper;
|
||||
timestamper.stamp();
|
||||
long stamp = timestamper.get_seconds();
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// Read the receive socket and process any data
|
||||
//////////////////////////////////////////////////
|
||||
int bytes;
|
||||
do {
|
||||
char Msg[MAX_PACKET_SIZE];
|
||||
//////////////////////////////////////////////////
|
||||
// Although the recv call asks for
|
||||
// MAX_PACKET_SIZE of data, the number of bytes
|
||||
// returned will only be that of the next
|
||||
// packet waiting to be processed.
|
||||
//////////////////////////////////////////////////
|
||||
Bytes = m_DataSocket->recvfrom (Msg, MAX_PACKET_SIZE, 0,
|
||||
&SenderAddress);
|
||||
netAddress SenderAddress;
|
||||
bytes = mSocket->recvfrom(Msg, sizeof(Msg), 0, &SenderAddress);
|
||||
//////////////////////////////////////////////////
|
||||
// no Data received
|
||||
//////////////////////////////////////////////////
|
||||
if (Bytes <= 0)
|
||||
{
|
||||
if (bytes <= 0) {
|
||||
if (errno != EAGAIN)
|
||||
{
|
||||
perror("FGMultiplayMgr::MP_ProcessData");
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (Bytes <= (int)sizeof(MsgHdr))
|
||||
{
|
||||
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||
"FGMultiplayMgr::MP_ProcessData - "
|
||||
if (bytes <= sizeof(T_MsgHdr)) {
|
||||
SG_LOG( SG_NETWORK, SG_ALERT, "FGMultiplayMgr::MP_ProcessData - "
|
||||
<< "received message with insufficient data" );
|
||||
return;
|
||||
break;
|
||||
}
|
||||
//////////////////////////////////////////////////
|
||||
// Read header
|
||||
//////////////////////////////////////////////////
|
||||
MsgHdr = (T_MsgHdr *)Msg;
|
||||
T_MsgHdr* MsgHdr = (T_MsgHdr *)Msg;
|
||||
MsgHdr->Magic = XDR_decode_uint32 (MsgHdr->Magic);
|
||||
MsgHdr->Version = XDR_decode_uint32 (MsgHdr->Version);
|
||||
MsgHdr->MsgId = XDR_decode_uint32 (MsgHdr->MsgId);
|
||||
MsgHdr->MsgLen = XDR_decode_uint32 (MsgHdr->MsgLen);
|
||||
MsgHdr->ReplyPort = XDR_decode_uint32 (MsgHdr->ReplyPort);
|
||||
if (MsgHdr->Magic != MSG_MAGIC)
|
||||
{
|
||||
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||
"FGMultiplayMgr::MP_ProcessData - "
|
||||
if (MsgHdr->Magic != MSG_MAGIC) {
|
||||
SG_LOG( SG_NETWORK, SG_ALERT, "FGMultiplayMgr::MP_ProcessData - "
|
||||
<< "message has invalid magic number!" );
|
||||
}
|
||||
if (MsgHdr->Version != PROTO_VER)
|
||||
{
|
||||
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||
"FGMultiplayMgr::MP_ProcessData - "
|
||||
if (MsgHdr->Version != PROTO_VER) {
|
||||
SG_LOG( SG_NETWORK, SG_ALERT, "FGMultiplayMgr::MP_ProcessData - "
|
||||
<< "message has invalid protocoll number!" );
|
||||
}
|
||||
//////////////////////////////////////////////////
|
||||
// Process the player data unless we generated it
|
||||
//////////////////////////////////////////////////
|
||||
if (m_Callsign == MsgHdr->Callsign)
|
||||
{
|
||||
return;
|
||||
if (MsgHdr->MsgLen != bytes) {
|
||||
SG_LOG( SG_NETWORK, SG_ALERT, "FGMultiplayMgr::MP_ProcessData - "
|
||||
<< "message has invalid length!" );
|
||||
}
|
||||
//////////////////////////////////////////////////
|
||||
// Process messages
|
||||
//////////////////////////////////////////////////
|
||||
switch(MsgHdr->MsgId)
|
||||
{
|
||||
switch (MsgHdr->MsgId) {
|
||||
case CHAT_MSG_ID:
|
||||
ProcessChatMsg ((char*) & Msg, SenderAddress);
|
||||
ProcessChatMsg(Msg, SenderAddress);
|
||||
break;
|
||||
case POS_DATA_ID:
|
||||
ProcessPosMsg ((char*) & Msg, SenderAddress);
|
||||
ProcessPosMsg(Msg, SenderAddress, bytes, stamp);
|
||||
break;
|
||||
case PROP_MSG_ID:
|
||||
ProcessPropMsg ((char *) & Msg, SenderAddress);
|
||||
case UNUSABLE_POS_DATA_ID:
|
||||
case OLD_OLD_POS_DATA_ID:
|
||||
case OLD_PROP_MSG_ID:
|
||||
case OLD_POS_DATA_ID:
|
||||
break;
|
||||
default:
|
||||
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||
"FGMultiplayMgr::MP_ProcessData - "
|
||||
<< "Unknown message Id received: "
|
||||
<< MsgHdr->MsgId );
|
||||
SG_LOG( SG_NETWORK, SG_ALERT, "FGMultiplayMgr::MP_ProcessData - "
|
||||
<< "Unknown message Id received: " << MsgHdr->MsgId );
|
||||
break;
|
||||
} // switch
|
||||
} while (Bytes > 0);
|
||||
}
|
||||
} while (bytes > 0);
|
||||
|
||||
// check for expiry
|
||||
MultiPlayerMap::iterator it = mMultiPlayerMap.begin();
|
||||
while (it != mMultiPlayerMap.end()) {
|
||||
if (it->second->getLastTimestamp() + 10 < stamp) {
|
||||
std::string name = it->first;
|
||||
it->second->setDie(true);
|
||||
mMultiPlayerMap.erase(it);
|
||||
it = mMultiPlayerMap.upper_bound(name);
|
||||
} else
|
||||
++it;
|
||||
}
|
||||
} // FGMultiplayMgr::ProcessData(void)
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -465,111 +423,48 @@ FGMultiplayMgr::ProcessData (void)
|
|||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
FGMultiplayMgr::ProcessPosMsg
|
||||
(
|
||||
const char *Msg,
|
||||
netAddress & SenderAddress
|
||||
)
|
||||
FGMultiplayMgr::ProcessPosMsg(const char *Msg, netAddress & SenderAddress,
|
||||
unsigned len, long stamp)
|
||||
{
|
||||
T_PositionMsg* PosMsg; // Pointer to position message in received data
|
||||
T_MsgHdr* MsgHdr; // Pointer to header in received data
|
||||
bool ActivePlayer;
|
||||
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;
|
||||
|
||||
ActivePlayer = false;
|
||||
MsgHdr = (T_MsgHdr *)Msg;
|
||||
if (MsgHdr->MsgLen < sizeof(T_MsgHdr) + sizeof(T_PositionMsg))
|
||||
{
|
||||
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||
"FGMultiplayMgr::MP_ProcessData - "
|
||||
T_MsgHdr* MsgHdr = (T_MsgHdr *)Msg;
|
||||
if (MsgHdr->MsgLen < sizeof(T_MsgHdr) + sizeof(T_PositionMsg)) {
|
||||
SG_LOG( SG_NETWORK, SG_ALERT, "FGMultiplayMgr::MP_ProcessData - "
|
||||
<< "Position message received with insufficient data" );
|
||||
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));
|
||||
time = XDR_decode_uint32 (PosMsg->time);
|
||||
timeusec = XDR_decode_uint32 (PosMsg->timeusec);
|
||||
lat = XDR_decode_double (PosMsg->lat);
|
||||
lon = XDR_decode_double (PosMsg->lon);
|
||||
alt = XDR_decode_double (PosMsg->alt);
|
||||
hdg = XDR_decode_double (PosMsg->hdg);
|
||||
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);
|
||||
T_PositionMsg* PosMsg = (T_PositionMsg *)(Msg + sizeof(T_MsgHdr));
|
||||
FGExternalMotionData motionInfo;
|
||||
motionInfo.time = XDR_decode_double(PosMsg->time);
|
||||
motionInfo.lag = XDR_decode_double(PosMsg->lag);
|
||||
for (unsigned i = 0; i < 3; ++i)
|
||||
motionInfo.position(i) = XDR_decode_double(PosMsg->position[i]);
|
||||
SGVec3f angleAxis;
|
||||
for (unsigned i = 0; i < 3; ++i)
|
||||
angleAxis(i) = XDR_decode_float(PosMsg->orientation[i]);
|
||||
motionInfo.orientation = SGQuatf::fromAngleAxis(angleAxis);
|
||||
for (unsigned i = 0; i < 3; ++i)
|
||||
motionInfo.linearVel(i) = XDR_decode_float(PosMsg->linearVel[i]);
|
||||
for (unsigned i = 0; i < 3; ++i)
|
||||
motionInfo.angularVel(i) = XDR_decode_float(PosMsg->angularVel[i]);
|
||||
for (unsigned i = 0; i < 3; ++i)
|
||||
motionInfo.linearAccel(i) = XDR_decode_float(PosMsg->linearAccel[i]);
|
||||
for (unsigned i = 0; i < 3; ++i)
|
||||
motionInfo.angularAccel(i) = XDR_decode_float(PosMsg->angularAccel[i]);
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// Check if the player is already in the game
|
||||
// by using the Callsign
|
||||
//////////////////////////////////////////////////
|
||||
for (CurrentPlayer = m_MPClientList.begin ();
|
||||
CurrentPlayer != m_MPClientList.end ();
|
||||
CurrentPlayer++)
|
||||
{
|
||||
if ((*CurrentPlayer)->CompareCallsign(MsgHdr->Callsign))
|
||||
{
|
||||
// Player found. Update the data for the player if the timestamp is OK
|
||||
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;
|
||||
T_PropertyMsg* PropMsg
|
||||
= (T_PropertyMsg*)(Msg + sizeof(T_MsgHdr) + sizeof(T_PositionMsg));
|
||||
while ((char*)PropMsg < Msg + len) {
|
||||
FGFloatPropertyData pData;
|
||||
pData.id = XDR_decode_uint32(PropMsg->id);
|
||||
pData.value = XDR_decode_float(PropMsg->value);
|
||||
motionInfo.properties.push_back(pData);
|
||||
++PropMsg;
|
||||
}
|
||||
} // for (...)
|
||||
if (ActivePlayer)
|
||||
{ // nothing more to do
|
||||
return;
|
||||
}
|
||||
//////////////////////////////////////////////////
|
||||
// Player not active, so add as new player
|
||||
//////////////////////////////////////////////////
|
||||
MPPlayer* NewPlayer;
|
||||
NewPlayer = new MPPlayer;
|
||||
NewPlayer->Open(SenderAddress.getHost(), MsgHdr->ReplyPort,
|
||||
MsgHdr->Callsign, PosMsg->Model, false);
|
||||
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);
|
||||
|
||||
// if we have a new player then we need to send all our properties
|
||||
send_all_props = true;
|
||||
|
||||
FGAIMultiplayer* mp = getMultiplayer(MsgHdr->Callsign);
|
||||
if (!mp)
|
||||
mp = addMultiplayer(MsgHdr->Callsign, PosMsg->Model);
|
||||
mp->addMotionInfo(motionInfo, stamp);
|
||||
} // FGMultiplayMgr::ProcessPosMsg()
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -580,124 +475,83 @@ FGMultiplayMgr::ProcessPosMsg
|
|||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
FGMultiplayMgr::ProcessChatMsg
|
||||
(
|
||||
const char *Msg,
|
||||
netAddress & SenderAddress
|
||||
)
|
||||
FGMultiplayMgr::ProcessChatMsg(const char *Msg, netAddress& SenderAddress)
|
||||
{
|
||||
T_ChatMsg* ChatMsg; // Pointer to chat message in received data
|
||||
T_MsgHdr* MsgHdr; // Pointer to header in received data
|
||||
|
||||
MsgHdr = (T_MsgHdr *)Msg;
|
||||
if (MsgHdr->MsgLen < sizeof(T_MsgHdr) + 1)
|
||||
{
|
||||
SG_LOG( SG_NETWORK, SG_ALERT,
|
||||
"FGMultiplayMgr::MP_ProcessData - "
|
||||
T_MsgHdr* MsgHdr = (T_MsgHdr *)Msg;
|
||||
if (MsgHdr->MsgLen < sizeof(T_MsgHdr) + 1) {
|
||||
SG_LOG( SG_NETWORK, SG_ALERT, "FGMultiplayMgr::MP_ProcessData - "
|
||||
<< "Chat message received with insufficient data" );
|
||||
return;
|
||||
}
|
||||
|
||||
char *MsgBuf = new char[MsgHdr->MsgLen - sizeof(T_MsgHdr)];
|
||||
strncpy(MsgBuf, ((T_ChatMsg *)(Msg + sizeof(T_MsgHdr)))->Text, MsgHdr->MsgLen - sizeof(T_MsgHdr));
|
||||
char MsgBuf[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));
|
||||
SG_LOG ( SG_NETWORK, SG_ALERT,
|
||||
"Chat [" << MsgHdr->Callsign << "]" << " " << MsgBuf << endl);
|
||||
delete [] MsgBuf;
|
||||
T_ChatMsg* ChatMsg = (T_ChatMsg *)(Msg + sizeof(T_MsgHdr));
|
||||
SG_LOG ( SG_NETWORK, SG_ALERT, "Chat [" << MsgHdr->Callsign << "]"
|
||||
<< " " << MsgBuf << endl);
|
||||
} // 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
|
||||
// to update its position on the scene. If a player object
|
||||
// returns status information indicating that it has not
|
||||
// had an update for some time then the player is deleted.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
FGMultiplayMgr::Update (void)
|
||||
FGMultiplayMgr::FillMsgHdr(T_MsgHdr *MsgHdr, int MsgId, unsigned _len)
|
||||
{
|
||||
MPPlayer::TPlayerDataState ePlayerDataState;
|
||||
t_MPClientListIterator CurrentPlayer;
|
||||
|
||||
CurrentPlayer = m_MPClientList.begin ();
|
||||
while (CurrentPlayer != m_MPClientList.end ())
|
||||
{
|
||||
ePlayerDataState = (*CurrentPlayer)->Draw();
|
||||
//////////////////////////////////////////////////
|
||||
// If the player has not received an update for
|
||||
// some time then assume that the player has quit.
|
||||
//////////////////////////////////////////////////
|
||||
if (ePlayerDataState == MPPlayer::PLAYER_DATA_EXPIRED)
|
||||
{
|
||||
SG_LOG( SG_NETWORK, SG_ALERT, "FGMultiplayMgr::Update - "
|
||||
<< "Deleting player from game. Callsign: "
|
||||
<< (*CurrentPlayer)->Callsign() );
|
||||
t_MPClientListIterator P;
|
||||
P = CurrentPlayer;
|
||||
delete (*P);
|
||||
*P = 0;
|
||||
CurrentPlayer = m_MPClientList.erase (P);
|
||||
uint32_t len;
|
||||
switch (MsgId) {
|
||||
case CHAT_MSG_ID:
|
||||
len = sizeof(T_MsgHdr) + sizeof(T_ChatMsg);
|
||||
break;
|
||||
case POS_DATA_ID:
|
||||
len = _len;
|
||||
break;
|
||||
default:
|
||||
len = sizeof(T_MsgHdr);
|
||||
break;
|
||||
}
|
||||
else CurrentPlayer++;
|
||||
MsgHdr->Magic = XDR_encode_uint32(MSG_MAGIC);
|
||||
MsgHdr->Version = XDR_encode_uint32(PROTO_VER);
|
||||
MsgHdr->MsgId = XDR_encode_uint32(MsgId);
|
||||
MsgHdr->MsgLen = XDR_encode_uint32(len);
|
||||
MsgHdr->ReplyAddress = 0; // Are obsolete, keep them for the server for
|
||||
MsgHdr->ReplyPort = 0; // now
|
||||
strncpy(MsgHdr->Callsign, mCallsign.c_str(), MAX_CALLSIGN_LEN);
|
||||
MsgHdr->Callsign[MAX_CALLSIGN_LEN - 1] = '\0';
|
||||
}
|
||||
} // FGMultiplayMgr::Update()
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif // FG_MPLAYER_AS
|
||||
FGAIMultiplayer*
|
||||
FGMultiplayMgr::addMultiplayer(const std::string& callsign,
|
||||
const std::string& modelName)
|
||||
{
|
||||
if (0 < mMultiPlayerMap.count(callsign))
|
||||
return mMultiPlayerMap[callsign];
|
||||
|
||||
FGAIMultiplayer* mp = new FGAIMultiplayer;
|
||||
mp->setPath(modelName.c_str());
|
||||
mp->setCallSign(callsign);
|
||||
mMultiPlayerMap[callsign] = mp;
|
||||
|
||||
FGAIManager *aiMgr = (FGAIManager*)globals->get_subsystem("ai_model");
|
||||
if (aiMgr) {
|
||||
aiMgr->attach(mp);
|
||||
|
||||
/// FIXME: that must follow the attach ATM ...
|
||||
unsigned i = 0;
|
||||
while (sIdPropertyList[i].name) {
|
||||
mp->addPropertyId(sIdPropertyList[i].id, sIdPropertyList[i].name);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
return mp;
|
||||
}
|
||||
|
||||
FGAIMultiplayer*
|
||||
FGMultiplayMgr::getMultiplayer(const std::string& callsign)
|
||||
{
|
||||
if (0 < mMultiPlayerMap.count(callsign))
|
||||
return mMultiPlayerMap[callsign];
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
|
||||
#define MULTIPLAYTXMGR_HID "$Id$"
|
||||
|
||||
#include "mpplayer.hxx"
|
||||
#include "mpmessages.hxx"
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
@ -48,52 +47,48 @@ SG_USING_STD(vector);
|
|||
#include <plib/netSocket.h>
|
||||
#include <Main/globals.hxx>
|
||||
|
||||
// Maximum number of players that can exist at any time
|
||||
// FIXME: use a list<mplayer> instead
|
||||
#define MAX_PLAYERS 10
|
||||
#include <AIModel/AIMultiplayer.hxx>
|
||||
|
||||
struct FGExternalMotionInfo;
|
||||
|
||||
class FGMultiplayMgr
|
||||
{
|
||||
public:
|
||||
struct IdPropertyList {
|
||||
unsigned id;
|
||||
const char* name;
|
||||
};
|
||||
static IdPropertyList sIdPropertyList[];
|
||||
|
||||
FGMultiplayMgr();
|
||||
~FGMultiplayMgr();
|
||||
bool init(void);
|
||||
void Close(void);
|
||||
// transmitter
|
||||
void SendMyPosition (const double lat, const double lon, const double alt,
|
||||
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 SendMyPosition(const FGExternalMotionData& motionInfo);
|
||||
void SendTextMessage(const string &sMsgText);
|
||||
void FillMsgHdr(T_MsgHdr *MsgHdr, int iMsgId, unsigned _len = 0u);
|
||||
|
||||
// receiver
|
||||
void ProcessData(void);
|
||||
void ProcessPosMsg ( const char *Msg, netAddress & SenderAddress );
|
||||
void ProcessPosMsg(const char *Msg, netAddress & SenderAddress,
|
||||
unsigned len, long stamp);
|
||||
void ProcessChatMsg(const char *Msg, netAddress & SenderAddress);
|
||||
void ProcessPropMsg ( const char *Msg, netAddress & SenderAddress );
|
||||
void Update(void);
|
||||
|
||||
/* getters/setters */
|
||||
bool getSendAllProps();
|
||||
void setSendAllProps(bool s);
|
||||
bool send_all_props;
|
||||
|
||||
private:
|
||||
typedef vector<MPPlayer*> t_MPClientList;
|
||||
typedef t_MPClientList::iterator t_MPClientListIterator;
|
||||
MPPlayer* m_LocalPlayer;
|
||||
netSocket* m_DataSocket;
|
||||
netAddress m_Server;
|
||||
bool m_HaveServer;
|
||||
bool m_Initialised;
|
||||
t_MPClientList m_MPClientList;
|
||||
string m_RxAddress;
|
||||
int m_RxPort;
|
||||
string m_Callsign;
|
||||
FGAIMultiplayer* addMultiplayer(const std::string& callsign,
|
||||
const std::string& modelName);
|
||||
FGAIMultiplayer* getMultiplayer(const std::string& callsign);
|
||||
|
||||
/// maps from the callsign string to the FGAIMultiplayer
|
||||
typedef std::map<std::string, SGSharedPtr<FGAIMultiplayer> > MultiPlayerMap;
|
||||
MultiPlayerMap mMultiPlayerMap;
|
||||
|
||||
netSocket* mSocket;
|
||||
netAddress mServer;
|
||||
bool mHaveServer;
|
||||
bool mInitialised;
|
||||
string mCallsign;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,7 +11,10 @@
|
|||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <plib/ul.h>
|
||||
#include <plib/netSocket.h>
|
||||
|
||||
#include "tiny_xdr.hxx"
|
||||
|
||||
|
@ -168,4 +171,3 @@ XDR_decode_double ( const xdr_data2_t & d_Val )
|
|||
return tmp.d;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -9,11 +9,7 @@ else
|
|||
JPEG_SERVER =
|
||||
endif
|
||||
|
||||
if ENABLE_MPLAYER_AS
|
||||
MPLAYER_AS = multiplay.cxx multiplay.hxx
|
||||
else
|
||||
MPLAYER_AS =
|
||||
endif
|
||||
|
||||
libNetwork_a_SOURCES = \
|
||||
protocol.cxx protocol.hxx \
|
||||
|
|
|
@ -35,10 +35,10 @@
|
|||
#include <string>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/scene/model/placement.hxx>
|
||||
#include <simgear/scene/model/placementtrans.hxx>
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
|
||||
#include <Scenery/scenery.hxx>
|
||||
#include <FDM/flight.hxx>
|
||||
#include <MultiPlayer/mpmessages.hxx>
|
||||
|
||||
#include "multiplay.hxx"
|
||||
|
||||
|
@ -57,9 +57,6 @@ const char sFG_MULTIPLAY_HID[] = FG_MULTIPLAY_HID;
|
|||
******************************************************************/
|
||||
FGMultiplay::FGMultiplay (const string &dir, const int rate, const string &host, const int port) {
|
||||
|
||||
last_time = 0;
|
||||
last_speedN = last_speedE = last_speedD = 0;
|
||||
calcaccN = calcaccE = calcaccD = 0;
|
||||
set_hz(rate);
|
||||
|
||||
set_direction(dir);
|
||||
|
@ -76,104 +73,6 @@ FGMultiplay::FGMultiplay (const string &dir, const int rate, const string &host,
|
|||
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -182,7 +81,6 @@ FGMultiplay::FGMultiplay (const string &dir, const int rate, const string &host,
|
|||
* Description: Destructor.
|
||||
******************************************************************/
|
||||
FGMultiplay::~FGMultiplay () {
|
||||
props.clear();
|
||||
}
|
||||
|
||||
|
||||
|
@ -200,6 +98,18 @@ bool FGMultiplay::open() {
|
|||
|
||||
set_enabled(true);
|
||||
|
||||
SGPropertyNode* root = globals->get_props();
|
||||
|
||||
/// Build up the id to property map
|
||||
unsigned i = 0;
|
||||
while (FGMultiplayMgr::sIdPropertyList[i].name) {
|
||||
const char* name = FGMultiplayMgr::sIdPropertyList[i].name;
|
||||
SGPropertyNode* pNode = root->getNode(name);
|
||||
if (pNode)
|
||||
mPropertyMap[FGMultiplayMgr::sIdPropertyList[i].id] = pNode;
|
||||
++i;
|
||||
}
|
||||
|
||||
return is_enabled();
|
||||
}
|
||||
|
||||
|
@ -211,80 +121,91 @@ bool FGMultiplay::open() {
|
|||
******************************************************************/
|
||||
bool FGMultiplay::process() {
|
||||
|
||||
if (get_direction() == SG_IO_IN) {
|
||||
if (get_direction() == SG_IO_OUT) {
|
||||
|
||||
globals->get_multiplayer_mgr()->ProcessData();
|
||||
// check if we have left initialization phase. That will not provide
|
||||
// interresting data, also the freeze in simulation time hurts the
|
||||
// multiplayer clients
|
||||
double sim_time = globals->get_sim_time_sec();
|
||||
// if (sim_time < 20)
|
||||
// return true;
|
||||
|
||||
} else if (get_direction() == SG_IO_OUT) {
|
||||
FGInterface *ifce = cur_fdm_state;
|
||||
|
||||
double accN, accE, accD;
|
||||
string fdm = fgGetString("/sim/flight-model");
|
||||
// put together a motion info struct, you will get that later
|
||||
// from FGInterface directly ...
|
||||
FGExternalMotionData motionInfo;
|
||||
|
||||
if(fdm == "jsb"){
|
||||
calcAcc(speedN_n->getDoubleValue(),
|
||||
speedE_n->getDoubleValue(),
|
||||
speedD_n->getDoubleValue());
|
||||
accN = calcaccN;
|
||||
accE = calcaccE;
|
||||
accD = calcaccD;
|
||||
// The current simulation time we need to update for,
|
||||
// note that the simulation time is updated before calling all the
|
||||
// update methods. Thus it contains the time intervals *end* time.
|
||||
// The FDM is already run, so the states belong to that time.
|
||||
motionInfo.time = sim_time;
|
||||
|
||||
// The typical lag will be the reciprocal of the output frequency
|
||||
double hz = get_hz();
|
||||
if (hz != 0) // I guess we can test a double for exact zero in this case
|
||||
motionInfo.lag = 1/get_hz();
|
||||
else
|
||||
motionInfo.lag = 0.1; //??
|
||||
|
||||
// These are for now converted from lat/lon/alt and euler angles.
|
||||
// But this should change in FGInterface ...
|
||||
double lon = ifce->get_Longitude();
|
||||
double lat = ifce->get_Latitude();
|
||||
// first the aprioriate structure for the geodetic one
|
||||
SGGeod geod = SGGeod::fromRadFt(lon, lat, ifce->get_Altitude());
|
||||
// Convert to cartesion coordinate
|
||||
motionInfo.position = geod;
|
||||
|
||||
// The quaternion rotating from the earth centered frame to the
|
||||
// horizontal local frame
|
||||
SGQuatf qEc2Hl = SGQuatf::fromLonLat((float)lon, (float)lat);
|
||||
// The orientation wrt the horizontal local frame
|
||||
float heading = ifce->get_Psi();
|
||||
float pitch = ifce->get_Theta();
|
||||
float roll = ifce->get_Phi();
|
||||
SGQuatf hlOr = SGQuatf::fromYawPitchRoll(heading, pitch, roll);
|
||||
// The orientation of the vehicle wrt the earth centered frame
|
||||
motionInfo.orientation = qEc2Hl*hlOr;
|
||||
|
||||
if (!ifce->is_suspended()) {
|
||||
// velocities
|
||||
motionInfo.linearVel = SG_FEET_TO_METER*SGVec3f(ifce->get_U_body(),
|
||||
ifce->get_V_body(),
|
||||
ifce->get_W_body());
|
||||
motionInfo.angularVel = SGVec3f(ifce->get_P_body(),
|
||||
ifce->get_Q_body(),
|
||||
ifce->get_R_body());
|
||||
|
||||
// accels, set that to zero for now.
|
||||
// Angular accelerations are missing from the interface anyway,
|
||||
// linear accelerations are screwed up at least for JSBSim.
|
||||
// motionInfo.linearAccel = SG_FEET_TO_METER*SGVec3f(ifce->get_U_dot_body(),
|
||||
// ifce->get_V_dot_body(),
|
||||
// ifce->get_W_dot_body());
|
||||
motionInfo.linearAccel = SGVec3f::zeros();
|
||||
motionInfo.angularAccel = SGVec3f::zeros();
|
||||
} 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");
|
||||
// if the interface is suspendend, prevent the client from
|
||||
// wild extrapolations
|
||||
motionInfo.linearVel = SGVec3f::zeros();
|
||||
motionInfo.angularVel = SGVec3f::zeros();
|
||||
motionInfo.linearAccel = SGVec3f::zeros();
|
||||
motionInfo.angularAccel = SGVec3f::zeros();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
// now send the properties
|
||||
PropertyMap::iterator it;
|
||||
for (it = mPropertyMap.begin(); it != mPropertyMap.end(); ++it) {
|
||||
FGFloatPropertyData pData;
|
||||
pData.id = it->first;
|
||||
pData.value = it->second->getFloatValue();
|
||||
motionInfo.properties.push_back(pData);
|
||||
}
|
||||
|
||||
// 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;
|
||||
FGMultiplayMgr* mpmgr = globals->get_multiplayer_mgr();
|
||||
mpmgr->SendMyPosition(motionInfo);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -304,46 +225,10 @@ bool FGMultiplay::close() {
|
|||
|
||||
} else if (get_direction() == SG_IO_OUT) {
|
||||
|
||||
// globals->get_multiplayer_mgr()->Close();
|
||||
globals->get_multiplayer_mgr()->Close();
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
#include STL_STRING
|
||||
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/scene/model/model.hxx>
|
||||
|
||||
#include <Main/globals.hxx>
|
||||
|
@ -58,8 +59,6 @@ SG_USING_STD(string);
|
|||
*
|
||||
******************************************************************/
|
||||
|
||||
#include <simgear/props/props.hxx>
|
||||
|
||||
class FGMultiplay : public FGProtocol {
|
||||
public:
|
||||
|
||||
|
@ -72,39 +71,20 @@ public:
|
|||
/** Enables the FGMultiplay object. */
|
||||
bool open();
|
||||
|
||||
/** Tells the multiplayer_mgr to send/receive data. */
|
||||
/** Tells the multiplayer_mgr to send/receive data.
|
||||
*/
|
||||
bool process();
|
||||
|
||||
/** Closes the multiplayer_mgr. */
|
||||
/** Closes the multiplayer_mgr.
|
||||
*/
|
||||
bool close();
|
||||
|
||||
|
||||
private:
|
||||
struct _node_cache {
|
||||
double val;
|
||||
SGPropertyNode_ptr node;
|
||||
_node_cache(double v, SGPropertyNode_ptr n) {
|
||||
val = v; node = n;
|
||||
};
|
||||
// Map between the property id's from the multiplayers network packets
|
||||
// and the property nodes
|
||||
typedef std::map<unsigned, SGSharedPtr<SGPropertyNode> > PropertyMap;
|
||||
PropertyMap mPropertyMap;
|
||||
};
|
||||
|
||||
/** 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
|
||||
|
|
Loading…
Reference in a new issue