Add multiplayer support from Duncan McCreanor and Diarmuid Tyson
This commit is contained in:
parent
01be2ed8e4
commit
e46c59d4d0
23 changed files with 1771 additions and 38 deletions
28
configure.ac
28
configure.ac
|
@ -57,16 +57,30 @@ if test "x$with_logging" = "xno" ; then
|
||||||
AC_DEFINE([FG_NDEBUG], 1, [Define for no logging output])
|
AC_DEFINE([FG_NDEBUG], 1, [Define for no logging output])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Specify if we want to build with default Multiplayer support
|
||||||
|
# default to with_network=yes
|
||||||
|
AC_ARG_WITH(multiplayer, [ --with-multiplayer Include default multiplayer support])
|
||||||
|
if test "x$with_multiplayer" = "xno" ; then
|
||||||
|
echo "Building without default multiplayer support"
|
||||||
|
else
|
||||||
|
echo "Building with default multiplayer support"
|
||||||
|
AC_DEFINE([FG_MPLAYER_AS], 1, [Define to build with default multiplayer support])
|
||||||
|
fi
|
||||||
|
AM_CONDITIONAL(ENABLE_MPLAYER_AS, test "x$with_multiplayer" != "xno")
|
||||||
|
|
||||||
|
|
||||||
# Specify if we want to build with Oliver's networking support
|
# Specify if we want to build with Oliver's networking support
|
||||||
# default to with_network=yes
|
# default to with_network=yes
|
||||||
AC_ARG_WITH(network_olk, [ --with-network-olk Include Oliver's multi-pilot networking support])
|
NETWORK_DIRS=Network
|
||||||
|
AC_ARG_WITH(network_olk, [ --with-network-olk Include Oliver's multi-pilot networking support [default=no]])
|
||||||
if test "x$with_network_olk" = "xno" ; then
|
if test "x$with_network_olk" = "xno" ; then
|
||||||
echo "Building without Oliver's multi-pilot network support"
|
echo "Building without Oliver's multi-pilot network support"
|
||||||
else
|
else
|
||||||
echo "Building with Oliver's multi-pilot network support"
|
echo "Building with Oliver's multi-pilot network support"
|
||||||
AC_DEFINE([FG_NETWORK_OLK], 1, [Define to build with Oliver's networking])
|
AC_DEFINE([FG_NETWORK_OLK], 1, [Define to build with Oliver's networking])
|
||||||
fi
|
fi
|
||||||
AM_CONDITIONAL(ENABLE_NETWORK_OLK, test "x$with_network_olk" != "xno")
|
AM_CONDITIONAL(ENABLE_NETWORK_OLK, test "x$with_network_olk" != "xno" -a "x$with_multiplayer" = "xno")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Specify if we want to use WeatherCM instead of FGEnvironment.
|
# Specify if we want to use WeatherCM instead of FGEnvironment.
|
||||||
|
@ -82,7 +96,7 @@ fi
|
||||||
AM_CONDITIONAL(ENABLE_WEATHERCM, test "x$with_weathercm" = "xyes")
|
AM_CONDITIONAL(ENABLE_WEATHERCM, test "x$with_weathercm" = "xyes")
|
||||||
|
|
||||||
dnl Specify if we want the old menubar; default to the new one
|
dnl Specify if we want the old menubar; default to the new one
|
||||||
AC_ARG_WITH(old-menubar, [ --with-old-menubar Use the old menu bar])
|
AC_ARG_WITH(old-menubar, [ --with-old-menubar Use the old menu bar])
|
||||||
if test "x$with_old_menubar" = "xyes" ; then
|
if test "x$with_old_menubar" = "xyes" ; then
|
||||||
echo "Building with old menubar"
|
echo "Building with old menubar"
|
||||||
AC_DEFINE([FG_OLD_MENUBAR], 1,
|
AC_DEFINE([FG_OLD_MENUBAR], 1,
|
||||||
|
@ -90,7 +104,6 @@ if test "x$with_old_menubar" = "xyes" ; then
|
||||||
else
|
else
|
||||||
echo "Building with new menubar"
|
echo "Building with new menubar"
|
||||||
fi
|
fi
|
||||||
AM_CONDITIONAL(ENABLE_WEATHERCM, test "x$with_weathercm" = "xyes")
|
|
||||||
|
|
||||||
dnl Thread related checks
|
dnl Thread related checks
|
||||||
AC_ARG_WITH(threads, [ --with-threads Include tile loading threads [default=no]])
|
AC_ARG_WITH(threads, [ --with-threads Include tile loading threads [default=no]])
|
||||||
|
@ -590,6 +603,7 @@ AC_CONFIG_FILES([ \
|
||||||
src/Main/runfgfs \
|
src/Main/runfgfs \
|
||||||
src/Main/runfgfs.bat \
|
src/Main/runfgfs.bat \
|
||||||
src/Model/Makefile \
|
src/Model/Makefile \
|
||||||
|
src/MultiPlayer/Makefile \
|
||||||
src/Navaids/Makefile \
|
src/Navaids/Makefile \
|
||||||
src/Network/Makefile \
|
src/Network/Makefile \
|
||||||
src/NetworkOLK/Makefile \
|
src/NetworkOLK/Makefile \
|
||||||
|
@ -639,6 +653,12 @@ else
|
||||||
echo "Using FGEnvironment"
|
echo "Using FGEnvironment"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test "x$with_multiplayer" != "xno"; then
|
||||||
|
echo "Using default multiplayer support"
|
||||||
|
elif test "x$with_network_olk" != "xno"; then
|
||||||
|
echo "Using Oliver's multi-pilot network support"
|
||||||
|
fi
|
||||||
|
|
||||||
if test "x$with_old_menubar" != "x"; then
|
if test "x$with_old_menubar" != "x"; then
|
||||||
echo "Using old menubar"
|
echo "Using old menubar"
|
||||||
else
|
else
|
||||||
|
|
72
docs-mini/README.multiplayer
Normal file
72
docs-mini/README.multiplayer
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
The commands are of the form:
|
||||||
|
|
||||||
|
--multiplay=in | out,Hz,destination address,destination port
|
||||||
|
--callsign=a_unique_name
|
||||||
|
|
||||||
|
|
||||||
|
Below are some examples of startup commands that demonstrate the use of the
|
||||||
|
multiplayer facilities.
|
||||||
|
|
||||||
|
For two players on a local network or across the internet:
|
||||||
|
----------------------------------------------------------
|
||||||
|
Player1:
|
||||||
|
--multiplay=out,10,192.168.0.3,5500 --multiplay=in,10,192.168.0.2,5501
|
||||||
|
--callsign=player1
|
||||||
|
|
||||||
|
Player2:
|
||||||
|
--multiplay=out,10,192.168.0.2,5501 --multiplay=in,10,192.168.0.3,5500
|
||||||
|
--callsign=player2
|
||||||
|
|
||||||
|
|
||||||
|
For multiple players on a local network:
|
||||||
|
----------------------------------------
|
||||||
|
Player1:
|
||||||
|
--multiplay=out,10,255.255.255.255,5500
|
||||||
|
--multiplay=in,10,255.255.255.255,5500 --callsign=player1
|
||||||
|
|
||||||
|
Playern:
|
||||||
|
--multiplay=out,10,255.255.255.255,5500
|
||||||
|
--multiplay=in,10,255.255.255.255,5500 --callsign=playern
|
||||||
|
|
||||||
|
Note that the callsign is used to identify each player in a multiplayer game
|
||||||
|
so the callsigns must be unique. The multiplayer code ignores packets that
|
||||||
|
are sent back to itself, as would occur with broadcasting when the rx and tx
|
||||||
|
ports are the same.
|
||||||
|
|
||||||
|
|
||||||
|
Multiple players sending to a single player:
|
||||||
|
--------------------------------------------
|
||||||
|
Player1:
|
||||||
|
--multiplay=out,10,192.168.0.2,5500 --callsign=player1
|
||||||
|
|
||||||
|
Player2:
|
||||||
|
--multiplay=out,10,192.168.0.2,5500 --callsign=player2
|
||||||
|
|
||||||
|
Player3:
|
||||||
|
--multiplay=out,10,192.168.0.2,5500 --callsign=player3
|
||||||
|
|
||||||
|
Player4 (rx only):
|
||||||
|
--multiplay=in,10,192.168.0.2,5500 --callsign=player4
|
||||||
|
|
||||||
|
This demonstrates that it is possible to have multiple instances of
|
||||||
|
Flightgear that send to a single instance that displays all the traffic. This
|
||||||
|
is the sort of implementation that we are considering for use as a tower
|
||||||
|
visual simulator.
|
||||||
|
|
||||||
|
|
||||||
|
For use with a server (when one is created):
|
||||||
|
--------------------------------------------
|
||||||
|
Player1:
|
||||||
|
--multiplay=out,10,serveraddress,6000 --multiplay=in,10,myaddress,5500
|
||||||
|
--callsign=player1
|
||||||
|
|
||||||
|
Player2:
|
||||||
|
--multiplay=out,10,serveraddress,6000 --multiplay=in,10,myaddress,5501
|
||||||
|
--callsign=player2
|
||||||
|
|
||||||
|
Playern:
|
||||||
|
--multiplay=out,10,serveraddress,6000 --multiplay=in,10,myaddress,5502
|
||||||
|
--callsign=playern
|
||||||
|
|
||||||
|
The server would simply act as a packet forwarding mechanism. When it
|
||||||
|
receives a packet, it sends it to all other active players.
|
|
@ -73,6 +73,7 @@ fgfs_LDADD = \
|
||||||
$(top_builddir)/src/Input/libInput.a \
|
$(top_builddir)/src/Input/libInput.a \
|
||||||
$(top_builddir)/src/Instrumentation/libInstrumentation.a \
|
$(top_builddir)/src/Instrumentation/libInstrumentation.a \
|
||||||
$(top_builddir)/src/Model/libModel.a \
|
$(top_builddir)/src/Model/libModel.a \
|
||||||
|
$(top_builddir)/src/MultiPlayer/libMultiPlayer.a \
|
||||||
$(top_builddir)/src/Navaids/libNavaids.a \
|
$(top_builddir)/src/Navaids/libNavaids.a \
|
||||||
$(top_builddir)/src/Scenery/libScenery.a \
|
$(top_builddir)/src/Scenery/libScenery.a \
|
||||||
$(SCRIPTING_LIBS) \
|
$(SCRIPTING_LIBS) \
|
||||||
|
|
|
@ -118,6 +118,11 @@
|
||||||
#include <Time/moonpos.hxx>
|
#include <Time/moonpos.hxx>
|
||||||
#include <Time/tmp.hxx>
|
#include <Time/tmp.hxx>
|
||||||
|
|
||||||
|
#ifdef FG_MPLAYER_AS
|
||||||
|
#include <MultiPlayer/multiplaytxmgr.hxx>
|
||||||
|
#include <MultiPlayer/multiplayrxmgr.hxx>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef FG_WEATHERCM
|
#ifdef FG_WEATHERCM
|
||||||
# include <WeatherCM/FGLocalWeatherDatabase.h>
|
# include <WeatherCM/FGLocalWeatherDatabase.h>
|
||||||
#else
|
#else
|
||||||
|
@ -249,7 +254,7 @@ bool fgInitFGRoot ( int argc, char **argv ) {
|
||||||
root = fgScanForOption( "--fg-root=", config.str() );
|
root = fgScanForOption( "--fg-root=", config.str() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next check if fg-root is set as an env variable
|
// Next check if fg-root is set as an env variable
|
||||||
if ( root.empty() ) {
|
if ( root.empty() ) {
|
||||||
envp = ::getenv( "FG_ROOT" );
|
envp = ::getenv( "FG_ROOT" );
|
||||||
|
@ -951,7 +956,7 @@ static void fgSetDistOrAltFromGlideSlope() {
|
||||||
SG_LOG( SG_GENERAL, SG_ALERT, "Resetting glideslope to zero" );
|
SG_LOG( SG_GENERAL, SG_ALERT, "Resetting glideslope to zero" );
|
||||||
fgSetDouble("/sim/presets/glideslope-deg", 0);
|
fgSetDouble("/sim/presets/glideslope-deg", 0);
|
||||||
fgSetBool("/sim/presets/onground", true);
|
fgSetBool("/sim/presets/onground", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1716,7 +1721,7 @@ bool fgInitSubsystems() {
|
||||||
current_panel->bind();
|
current_panel->bind();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Initialize the default (kludged) properties.
|
// Initialize the default (kludged) properties.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1747,6 +1752,18 @@ bool fgInitSubsystems() {
|
||||||
globals->get_subsystem_mgr()->init();
|
globals->get_subsystem_mgr()->init();
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef FG_MPLAYER_AS
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Initialize multiplayer subsystem
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
globals->set_multiplayer_tx_mgr(new FGMultiplayTxMgr);
|
||||||
|
globals->get_multiplayer_tx_mgr()->init();
|
||||||
|
|
||||||
|
globals->set_multiplayer_rx_mgr(new FGMultiplayRxMgr);
|
||||||
|
globals->get_multiplayer_rx_mgr()->init();
|
||||||
|
#endif
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
// End of subsystem initialization.
|
// End of subsystem initialization.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -57,6 +57,10 @@
|
||||||
#include <Network/ray.hxx>
|
#include <Network/ray.hxx>
|
||||||
#include <Network/rul.hxx>
|
#include <Network/rul.hxx>
|
||||||
|
|
||||||
|
#ifdef FG_MPLAYER_AS
|
||||||
|
#include <Network/multiplay.hxx>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "globals.hxx"
|
#include "globals.hxx"
|
||||||
#include "fg_io.hxx"
|
#include "fg_io.hxx"
|
||||||
|
|
||||||
|
@ -155,6 +159,17 @@ FGIO::parse_port_config( const string& config )
|
||||||
} else if ( protocol == "rul" ) {
|
} else if ( protocol == "rul" ) {
|
||||||
FGRUL *rul = new FGRUL;
|
FGRUL *rul = new FGRUL;
|
||||||
io = rul;
|
io = rul;
|
||||||
|
|
||||||
|
#ifdef FG_MPLAYER_AS
|
||||||
|
} else if ( protocol == "multiplay" ) {\
|
||||||
|
//Determine dir, rate, host & port
|
||||||
|
string dir = tokens[1];
|
||||||
|
string rate = tokens[2];
|
||||||
|
string host = tokens[3];
|
||||||
|
string port = tokens[4];
|
||||||
|
return new FGMultiplay(dir, atoi(rate.c_str()), host, atoi(port.c_str()));
|
||||||
|
#endif
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -204,7 +219,7 @@ FGIO::parse_port_config( const string& config )
|
||||||
SG_LOG( SG_IO, SG_INFO, " hostname = " << hostname );
|
SG_LOG( SG_IO, SG_INFO, " hostname = " << hostname );
|
||||||
SG_LOG( SG_IO, SG_INFO, " port = " << port );
|
SG_LOG( SG_IO, SG_INFO, " port = " << port );
|
||||||
SG_LOG( SG_IO, SG_INFO, " style = " << style );
|
SG_LOG( SG_IO, SG_INFO, " style = " << style );
|
||||||
|
|
||||||
io->set_io_channel( new SGSocket( hostname, port, style ) );
|
io->set_io_channel( new SGSocket( hostname, port, style ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,7 +232,7 @@ FGIO::parse_port_config( const string& config )
|
||||||
void
|
void
|
||||||
FGIO::init()
|
FGIO::init()
|
||||||
{
|
{
|
||||||
// SG_LOG( SG_IO, SG_INFO, "I/O Channel initialization, " <<
|
// SG_LOG( SG_IO, SG_INFO, "I/O Channel initialization, " <<
|
||||||
// globals->get_channel_options_list()->size() << " requests." );
|
// globals->get_channel_options_list()->size() << " requests." );
|
||||||
|
|
||||||
FGProtocol *p;
|
FGProtocol *p;
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
#include "fgfs.hxx"
|
#include "fgfs.hxx"
|
||||||
|
|
||||||
|
|
||||||
SG_USING_STD( vector );
|
SG_USING_STD( vector );
|
||||||
SG_USING_STD( string );
|
SG_USING_STD( string );
|
||||||
|
|
||||||
|
@ -67,6 +68,10 @@ class FGIO;
|
||||||
class FGModelLoader;
|
class FGModelLoader;
|
||||||
class FGModelMgr;
|
class FGModelMgr;
|
||||||
class FGScenery;
|
class FGScenery;
|
||||||
|
#ifdef FG_MPLAYER_AS
|
||||||
|
class FGMultiplayRxMgr;
|
||||||
|
class FGMultiplayTxMgr;
|
||||||
|
#endif
|
||||||
class FGSoundMgr;
|
class FGSoundMgr;
|
||||||
class FGTextureLoader;
|
class FGTextureLoader;
|
||||||
class FGTileMgr;
|
class FGTileMgr;
|
||||||
|
@ -170,6 +175,13 @@ private:
|
||||||
|
|
||||||
FGIO* io;
|
FGIO* io;
|
||||||
|
|
||||||
|
#ifdef FG_MPLAYER_AS
|
||||||
|
//Mulitplayer managers
|
||||||
|
FGMultiplayTxMgr *multiplayer_tx_mgr;
|
||||||
|
|
||||||
|
FGMultiplayRxMgr *multiplayer_rx_mgr;
|
||||||
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
FGGlobals();
|
FGGlobals();
|
||||||
|
@ -236,8 +248,8 @@ public:
|
||||||
inline void set_ATC_mgr( FGATCMgr *a ) {ATC_mgr = a; }
|
inline void set_ATC_mgr( FGATCMgr *a ) {ATC_mgr = a; }
|
||||||
|
|
||||||
inline FGATCDisplay *get_ATC_display() const { return ATC_display; }
|
inline FGATCDisplay *get_ATC_display() const { return ATC_display; }
|
||||||
inline void set_ATC_display( FGATCDisplay *d ) {ATC_display = d; }
|
inline void set_ATC_display( FGATCDisplay *d ) {ATC_display = d; }
|
||||||
|
|
||||||
inline FGAIMgr *get_AI_mgr() const { return AI_mgr; }
|
inline FGAIMgr *get_AI_mgr() const { return AI_mgr; }
|
||||||
inline void set_AI_mgr( FGAIMgr *a ) {AI_mgr = a; }
|
inline void set_AI_mgr( FGAIMgr *a ) {AI_mgr = a; }
|
||||||
|
|
||||||
|
@ -285,6 +297,22 @@ public:
|
||||||
model_mgr = mgr;
|
model_mgr = mgr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef FG_MPLAYER_AS
|
||||||
|
inline FGMultiplayTxMgr *get_multiplayer_tx_mgr () { return multiplayer_tx_mgr; }
|
||||||
|
|
||||||
|
inline void set_multiplayer_tx_mgr (FGMultiplayTxMgr * mgr)
|
||||||
|
{
|
||||||
|
multiplayer_tx_mgr = mgr;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline FGMultiplayRxMgr *get_multiplayer_rx_mgr () { return multiplayer_rx_mgr; }
|
||||||
|
|
||||||
|
inline void set_multiplayer_rx_mgr (FGMultiplayRxMgr * mgr)
|
||||||
|
{
|
||||||
|
multiplayer_rx_mgr = mgr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
inline string_list *get_channel_options_list () {
|
inline string_list *get_channel_options_list () {
|
||||||
return channel_options_list;
|
return channel_options_list;
|
||||||
}
|
}
|
||||||
|
@ -300,6 +328,7 @@ public:
|
||||||
|
|
||||||
FGIO* get_io() const { return io; }
|
FGIO* get_io() const { return io; }
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save the current state as the initial state.
|
* Save the current state as the initial state.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -109,6 +109,12 @@ SG_USING_STD(endl);
|
||||||
#ifdef FG_NETWORK_OLK
|
#ifdef FG_NETWORK_OLK
|
||||||
#include <NetworkOLK/network.h>
|
#include <NetworkOLK/network.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef FG_MPLAYER_AS
|
||||||
|
#include <MultiPlayer/multiplaytxmgr.hxx>
|
||||||
|
#include <MultiPlayer/multiplayrxmgr.hxx>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <Objects/matlib.hxx>
|
#include <Objects/matlib.hxx>
|
||||||
#include <Scenery/scenery.hxx>
|
#include <Scenery/scenery.hxx>
|
||||||
#include <Scenery/tilemgr.hxx>
|
#include <Scenery/tilemgr.hxx>
|
||||||
|
@ -433,7 +439,7 @@ void trRenderFrame( void ) {
|
||||||
|
|
||||||
// Update all Visuals (redraws anything graphics related)
|
// Update all Visuals (redraws anything graphics related)
|
||||||
void fgRenderFrame() {
|
void fgRenderFrame() {
|
||||||
|
|
||||||
GLfloat black[4] = { 0.0, 0.0, 0.0, 1.0 };
|
GLfloat black[4] = { 0.0, 0.0, 0.0, 1.0 };
|
||||||
GLfloat white[4] = { 1.0, 1.0, 1.0, 1.0 };
|
GLfloat white[4] = { 1.0, 1.0, 1.0, 1.0 };
|
||||||
|
|
||||||
|
@ -484,7 +490,7 @@ void fgRenderFrame() {
|
||||||
// GLfloat terrain_color[4] = { 0.54, 0.44, 0.29, 1.0 };
|
// GLfloat terrain_color[4] = { 0.54, 0.44, 0.29, 1.0 };
|
||||||
// GLfloat mat_shininess[] = { 10.0 };
|
// GLfloat mat_shininess[] = { 10.0 };
|
||||||
GLbitfield clear_mask;
|
GLbitfield clear_mask;
|
||||||
|
|
||||||
if ( idle_state != 1000 ) {
|
if ( idle_state != 1000 ) {
|
||||||
// still initializing, draw the splash screen
|
// still initializing, draw the splash screen
|
||||||
if ( fgGetBool("/sim/startup/splash-screen") ) {
|
if ( fgGetBool("/sim/startup/splash-screen") ) {
|
||||||
|
@ -533,12 +539,12 @@ void fgRenderFrame() {
|
||||||
if ( fgGetBool("/sim/rendering/skyblend") ) {
|
if ( fgGetBool("/sim/rendering/skyblend") ) {
|
||||||
if ( fgGetBool("/sim/rendering/textures") ) {
|
if ( fgGetBool("/sim/rendering/textures") ) {
|
||||||
// glClearColor(black[0], black[1], black[2], black[3]);
|
// glClearColor(black[0], black[1], black[2], black[3]);
|
||||||
glClearColor(l->adj_fog_color[0], l->adj_fog_color[1],
|
glClearColor(l->adj_fog_color[0], l->adj_fog_color[1],
|
||||||
l->adj_fog_color[2], l->adj_fog_color[3]);
|
l->adj_fog_color[2], l->adj_fog_color[3]);
|
||||||
clear_mask |= GL_COLOR_BUFFER_BIT;
|
clear_mask |= GL_COLOR_BUFFER_BIT;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
glClearColor(l->sky_color[0], l->sky_color[1],
|
glClearColor(l->sky_color[0], l->sky_color[1],
|
||||||
l->sky_color[2], l->sky_color[3]);
|
l->sky_color[2], l->sky_color[3]);
|
||||||
clear_mask |= GL_COLOR_BUFFER_BIT;
|
clear_mask |= GL_COLOR_BUFFER_BIT;
|
||||||
}
|
}
|
||||||
|
@ -591,7 +597,7 @@ void fgRenderFrame() {
|
||||||
globals->get_ephem()->getPlanets(),
|
globals->get_ephem()->getPlanets(),
|
||||||
globals->get_ephem()->getNumStars(),
|
globals->get_ephem()->getNumStars(),
|
||||||
globals->get_ephem()->getStars() );
|
globals->get_ephem()->getStars() );
|
||||||
|
|
||||||
/* cout << "thesky->reposition( view_pos = " << view_pos[0] << " "
|
/* cout << "thesky->reposition( view_pos = " << view_pos[0] << " "
|
||||||
<< view_pos[1] << " " << view_pos[2] << endl;
|
<< view_pos[1] << " " << view_pos[2] << endl;
|
||||||
cout << " zero_elev = " << zero_elev[0] << " "
|
cout << " zero_elev = " << zero_elev[0] << " "
|
||||||
|
@ -601,7 +607,7 @@ void fgRenderFrame() {
|
||||||
cout << " sun_rot = " << cur_light_params.sun_rotation
|
cout << " sun_rot = " << cur_light_params.sun_rotation
|
||||||
<< " gst = " << SGTime::cur_time_params->getGst() << endl;
|
<< " gst = " << SGTime::cur_time_params->getGst() << endl;
|
||||||
cout << " sun ra = " << globals->get_ephem()->getSunRightAscension()
|
cout << " sun ra = " << globals->get_ephem()->getSunRightAscension()
|
||||||
<< " sun dec = " << globals->get_ephem()->getSunDeclination()
|
<< " sun dec = " << globals->get_ephem()->getSunDeclination()
|
||||||
<< " moon ra = " << globals->get_ephem()->getMoonRightAscension()
|
<< " moon ra = " << globals->get_ephem()->getMoonRightAscension()
|
||||||
<< " moon dec = " << globals->get_ephem()->getMoonDeclination() << endl; */
|
<< " moon dec = " << globals->get_ephem()->getMoonDeclination() << endl; */
|
||||||
|
|
||||||
|
@ -693,6 +699,11 @@ void fgRenderFrame() {
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
#ifdef FG_MPLAYER_AS
|
||||||
|
// Update any multiplayer models
|
||||||
|
globals->get_multiplayer_rx_mgr()->Update();
|
||||||
|
#endif
|
||||||
|
|
||||||
if ( fgGetBool("/sim/rendering/skyblend") ) {
|
if ( fgGetBool("/sim/rendering/skyblend") ) {
|
||||||
// draw the sky backdrop
|
// draw the sky backdrop
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@ static double
|
||||||
atof( const string& str )
|
atof( const string& str )
|
||||||
{
|
{
|
||||||
|
|
||||||
#ifdef __MWERKS__
|
#ifdef __MWERKS__
|
||||||
// -dw- if ::atof is called, then we get an infinite loop
|
// -dw- if ::atof is called, then we get an infinite loop
|
||||||
return std::atof( str.c_str() );
|
return std::atof( str.c_str() );
|
||||||
#else
|
#else
|
||||||
|
@ -93,7 +93,7 @@ atof( const string& str )
|
||||||
static int
|
static int
|
||||||
atoi( const string& str )
|
atoi( const string& str )
|
||||||
{
|
{
|
||||||
#ifdef __MWERKS__
|
#ifdef __MWERKS__
|
||||||
// -dw- if ::atoi is called, then we get an infinite loop
|
// -dw- if ::atoi is called, then we get an infinite loop
|
||||||
return std::atoi( str.c_str() );
|
return std::atoi( str.c_str() );
|
||||||
#else
|
#else
|
||||||
|
@ -106,7 +106,7 @@ atoi( const string& str )
|
||||||
* Set a few fail-safe default property values.
|
* Set a few fail-safe default property values.
|
||||||
*
|
*
|
||||||
* These should all be set in $FG_ROOT/preferences.xml, but just
|
* These should all be set in $FG_ROOT/preferences.xml, but just
|
||||||
* in case, we provide some initial sane values here. This method
|
* in case, we provide some initial sane values here. This method
|
||||||
* should be invoked *before* reading any init files.
|
* should be invoked *before* reading any init files.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
|
@ -224,6 +224,15 @@ fgSetDefaults ()
|
||||||
fgSetBool("/sim/freeze/position", false);
|
fgSetBool("/sim/freeze/position", false);
|
||||||
fgSetBool("/sim/freeze/clock", false);
|
fgSetBool("/sim/freeze/clock", false);
|
||||||
fgSetBool("/sim/freeze/fuel", 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
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -506,20 +515,22 @@ parse_fov( const string& arg ) {
|
||||||
// baud = {300, 1200, 2400, ..., 230400}
|
// baud = {300, 1200, 2400, ..., 230400}
|
||||||
//
|
//
|
||||||
// Socket exacmple "--native=socket,dir,hz,machine,port,style" where
|
// Socket exacmple "--native=socket,dir,hz,machine,port,style" where
|
||||||
//
|
//
|
||||||
// machine = machine name or ip address if client (leave empty if server)
|
// machine = machine name or ip address if client (leave empty if server)
|
||||||
// port = port, leave empty to let system choose
|
// port = port, leave empty to let system choose
|
||||||
// style = tcp or udp
|
// style = tcp or udp
|
||||||
//
|
//
|
||||||
// File example "--garmin=file,dir,hz,filename" where
|
// File example "--garmin=file,dir,hz,filename" where
|
||||||
//
|
//
|
||||||
// filename = file system file name
|
// filename = file system file name
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
add_channel( const string& type, const string& channel_str ) {
|
add_channel( const string& type, const string& channel_str ) {
|
||||||
// cout << "Channel string = " << channel_str << endl;
|
cout << "Channel string = " << channel_str << endl;
|
||||||
|
|
||||||
globals->get_channel_options_list()->push_back( type + "," + channel_str );
|
globals->get_channel_options_list()->push_back( type + "," + channel_str );
|
||||||
|
|
||||||
|
cout << "here" << endl;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1156,8 +1167,8 @@ struct OptionDesc {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Parse a single option
|
// Parse a single option
|
||||||
static int
|
static int
|
||||||
parse_option (const string& arg)
|
parse_option (const string& arg)
|
||||||
{
|
{
|
||||||
#ifdef NEW_OPTION_PARSING
|
#ifdef NEW_OPTION_PARSING
|
||||||
if ( fgOptionMap.size() == 0 ) {
|
if ( fgOptionMap.size() == 0 ) {
|
||||||
|
@ -1287,7 +1298,7 @@ parse_option (const string& arg)
|
||||||
} else if ( arg == "--enable-game-mode" ) {
|
} else if ( arg == "--enable-game-mode" ) {
|
||||||
fgSetBool("/sim/startup/game-mode", true);
|
fgSetBool("/sim/startup/game-mode", true);
|
||||||
} else if ( arg == "--disable-splash-screen" ) {
|
} else if ( arg == "--disable-splash-screen" ) {
|
||||||
fgSetBool("/sim/startup/splash-screen", false);
|
fgSetBool("/sim/startup/splash-screen", false);
|
||||||
} else if ( arg == "--enable-splash-screen" ) {
|
} else if ( arg == "--enable-splash-screen" ) {
|
||||||
fgSetBool("/sim/startup/splash-screen", true);
|
fgSetBool("/sim/startup/splash-screen", true);
|
||||||
} else if ( arg == "--disable-intro-music" ) {
|
} else if ( arg == "--disable-intro-music" ) {
|
||||||
|
@ -1559,6 +1570,10 @@ parse_option (const string& arg)
|
||||||
add_channel( "atc610x", "dummy" );
|
add_channel( "atc610x", "dummy" );
|
||||||
} else if ( arg.find( "--atlas=" ) == 0 ) {
|
} else if ( arg.find( "--atlas=" ) == 0 ) {
|
||||||
add_channel( "atlas", arg.substr(8) );
|
add_channel( "atlas", arg.substr(8) );
|
||||||
|
|
||||||
|
} else if ( arg.find( "--multiplay=" ) == 0 ) {
|
||||||
|
add_channel( "multiplay", arg.substr(12) );
|
||||||
|
|
||||||
} else if ( arg.find( "--httpd=" ) == 0 ) {
|
} else if ( arg.find( "--httpd=" ) == 0 ) {
|
||||||
add_channel( "httpd", arg.substr(8) );
|
add_channel( "httpd", arg.substr(8) );
|
||||||
#ifdef FG_JPEG_SERVER
|
#ifdef FG_JPEG_SERVER
|
||||||
|
@ -1604,6 +1619,12 @@ parse_option (const string& arg)
|
||||||
} else if ( arg.find( "--net-id=") == 0 ) {
|
} else if ( arg.find( "--net-id=") == 0 ) {
|
||||||
fgSetString("sim/networking/call-sign", arg.substr(9).c_str());
|
fgSetString("sim/networking/call-sign", arg.substr(9).c_str());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef FG_MPLAYER_AS
|
||||||
|
} else if ( arg.find( "--callsign=") == 0 ) {
|
||||||
|
fgSetString("sim/multiplay/callsign", arg.substr(11).c_str());
|
||||||
|
#endif
|
||||||
|
|
||||||
} else if ( arg.find( "--prop:" ) == 0 ) {
|
} else if ( arg.find( "--prop:" ) == 0 ) {
|
||||||
string assign = arg.substr(7);
|
string assign = arg.substr(7);
|
||||||
string::size_type pos = assign.find('=');
|
string::size_type pos = assign.find('=');
|
||||||
|
@ -1640,7 +1661,7 @@ parse_option (const string& arg)
|
||||||
} else {
|
} else {
|
||||||
default_view_offset = atof( woffset.c_str() ) * SGD_DEGREES_TO_RADIANS;
|
default_view_offset = atof( woffset.c_str() ) * SGD_DEGREES_TO_RADIANS;
|
||||||
}
|
}
|
||||||
/* apparently not used (CLO, 11 Jun 2002)
|
/* apparently not used (CLO, 11 Jun 2002)
|
||||||
FGViewer *pilot_view =
|
FGViewer *pilot_view =
|
||||||
(FGViewer *)globals->get_viewmgr()->get_view( 0 ); */
|
(FGViewer *)globals->get_viewmgr()->get_view( 0 ); */
|
||||||
// this will work without calls to the viewer...
|
// this will work without calls to the viewer...
|
||||||
|
|
|
@ -4,18 +4,24 @@ else
|
||||||
WEATHER_DIR = Environment
|
WEATHER_DIR = Environment
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if ENABLE_NETWORK_OLK
|
|
||||||
NETWORK_DIRS = Network NetworkOLK
|
|
||||||
else
|
|
||||||
NETWORK_DIRS = Network
|
|
||||||
endif
|
|
||||||
|
|
||||||
if HAVE_PLIB_PSL
|
if HAVE_PLIB_PSL
|
||||||
SCRIPTING_DIRS = Scripting
|
SCRIPTING_DIRS = Scripting
|
||||||
else
|
else
|
||||||
SCRIPTING_DIRS =
|
SCRIPTING_DIRS =
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if ENABLE_MPLAYER_AS
|
||||||
|
MPLAYER_DIRS = MultiPlayer
|
||||||
|
else
|
||||||
|
MPLAYER_DIRS =
|
||||||
|
endif
|
||||||
|
|
||||||
|
if ENABLE_NETWORK_OLK
|
||||||
|
NETWORK_DIRS = NetworkOLK
|
||||||
|
else
|
||||||
|
NETWORK_DIRS =
|
||||||
|
endif
|
||||||
|
|
||||||
SUBDIRS = \
|
SUBDIRS = \
|
||||||
Include \
|
Include \
|
||||||
Aircraft \
|
Aircraft \
|
||||||
|
@ -30,6 +36,8 @@ SUBDIRS = \
|
||||||
Instrumentation \
|
Instrumentation \
|
||||||
Model \
|
Model \
|
||||||
Navaids \
|
Navaids \
|
||||||
|
Network \
|
||||||
|
$(MPLAYER_DIRS) \
|
||||||
$(NETWORK_DIRS) \
|
$(NETWORK_DIRS) \
|
||||||
Objects \
|
Objects \
|
||||||
Scenery \
|
Scenery \
|
||||||
|
|
|
@ -649,9 +649,8 @@ FGModelPlacement::update ()
|
||||||
_location->setPosition( _lon_deg, _lat_deg, _elev_ft );
|
_location->setPosition( _lon_deg, _lat_deg, _elev_ft );
|
||||||
_location->setOrientation( _roll_deg, _pitch_deg, _heading_deg );
|
_location->setOrientation( _roll_deg, _pitch_deg, _heading_deg );
|
||||||
|
|
||||||
sgMat4 POS;
|
|
||||||
sgCopyMat4(POS, _location->getTransformMatrix());
|
sgCopyMat4(POS, _location->getTransformMatrix());
|
||||||
|
|
||||||
sgVec3 trans;
|
sgVec3 trans;
|
||||||
sgCopyVec3(trans, _location->get_view_pos());
|
sgCopyVec3(trans, _location->get_view_pos());
|
||||||
|
|
||||||
|
|
|
@ -228,7 +228,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
// Model placement.
|
// Model placement.
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -271,9 +271,13 @@ public:
|
||||||
virtual void setHeadingDeg (double heading_deg);
|
virtual void setHeadingDeg (double heading_deg);
|
||||||
virtual void setOrientation (double roll_deg, double pitch_deg,
|
virtual void setOrientation (double roll_deg, double pitch_deg,
|
||||||
double heading_deg);
|
double heading_deg);
|
||||||
|
|
||||||
|
// Addition by Diarmuid Tyson for Multiplayer Support
|
||||||
|
// Allows multiplayer to get players position transform
|
||||||
|
virtual const sgVec4 *get_POS() { return POS; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// Geodetic position
|
// Geodetic position
|
||||||
double _lon_deg;
|
double _lon_deg;
|
||||||
double _lat_deg;
|
double _lat_deg;
|
||||||
|
@ -290,6 +294,12 @@ private:
|
||||||
// Location
|
// Location
|
||||||
FGLocation * _location;
|
FGLocation * _location;
|
||||||
|
|
||||||
|
|
||||||
|
// Addition by Diarmuid Tyson for Multiplayer Support
|
||||||
|
// Moved from update method
|
||||||
|
// POS for transformation Matrix
|
||||||
|
sgMat4 POS;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __MODEL_HXX
|
#endif // __MODEL_HXX
|
||||||
|
|
3
src/MultiPlayer/.cvsignore
Normal file
3
src/MultiPlayer/.cvsignore
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
.deps
|
||||||
|
Makefile.in
|
||||||
|
Makefile
|
7
src/MultiPlayer/Makefile.am
Normal file
7
src/MultiPlayer/Makefile.am
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
noinst_LIBRARIES = libMultiPlayer.a
|
||||||
|
|
||||||
|
libMultiPlayer_a_SOURCES = multiplayrxmgr.cxx multiplayrxmgr.hxx multiplaytxmgr.cxx multiplaytxmgr.hxx mpplayer.cxx mpplayer.hxx mpmessages.hxx
|
||||||
|
|
||||||
|
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
|
||||||
|
|
||||||
|
|
68
src/MultiPlayer/mpmessages.hxx
Normal file
68
src/MultiPlayer/mpmessages.hxx
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
#ifndef MPMESSAGES_H
|
||||||
|
#define MPMESSAGES_H
|
||||||
|
|
||||||
|
#define MPMESSAGES_HID "$Id$"
|
||||||
|
|
||||||
|
/****************************************************************
|
||||||
|
* @version $Id$
|
||||||
|
*
|
||||||
|
* Description: Each message used for multiplayer communications
|
||||||
|
* consists of a header and optionally a block of data. The combined
|
||||||
|
* header and data is sent as one IP packet.
|
||||||
|
*
|
||||||
|
******************************************************************/
|
||||||
|
|
||||||
|
#include <plib/sg.h>
|
||||||
|
|
||||||
|
// Message identifiers
|
||||||
|
#define CHAT_MSG_ID 1
|
||||||
|
#define POS_DATA_ID 2
|
||||||
|
|
||||||
|
#define MAX_CALLSIGN_LEN 10
|
||||||
|
/** Header for use with all messages sent */
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
/** Message identifier */
|
||||||
|
char MsgId;
|
||||||
|
|
||||||
|
/** Length of the message inclusive of this header */
|
||||||
|
unsigned int iMsgLen;
|
||||||
|
|
||||||
|
/** IP address for reply to message (player's receiver address) */
|
||||||
|
unsigned long int lReplyAddress;
|
||||||
|
|
||||||
|
/** Port for replies (player's receiver port) */
|
||||||
|
unsigned int iReplyPort;
|
||||||
|
|
||||||
|
/** Callsign used by the player */
|
||||||
|
char sCallsign[MAX_CALLSIGN_LEN];
|
||||||
|
|
||||||
|
} T_MsgHdr;
|
||||||
|
|
||||||
|
#define MAX_CHAT_MSG_LEN 50
|
||||||
|
/** Chat message */
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
/** Text of chat message */
|
||||||
|
char sText[MAX_CHAT_MSG_LEN];
|
||||||
|
|
||||||
|
} T_ChatMsg;
|
||||||
|
|
||||||
|
|
||||||
|
#define MAX_MODEL_NAME_LEN 50
|
||||||
|
/** Aircraft position message */
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
/** Name of the aircraft model */
|
||||||
|
char sModel[MAX_MODEL_NAME_LEN];
|
||||||
|
|
||||||
|
/** Position data for the aircraft */
|
||||||
|
sgMat4 PlayerPos;
|
||||||
|
|
||||||
|
} T_PositionMsg;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
294
src/MultiPlayer/mpplayer.cxx
Normal file
294
src/MultiPlayer/mpplayer.cxx
Normal file
|
@ -0,0 +1,294 @@
|
||||||
|
// mpplayer.cxx -- routines for a player within a multiplayer Flightgear
|
||||||
|
//
|
||||||
|
// Written by Duncan McCreanor, started February 2003.
|
||||||
|
// duncan.mccreanor@airservicesaustralia.com
|
||||||
|
//
|
||||||
|
// Copyright (C) 2003 Airservices Australia
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Description: Provides a container for a player in a multiplayer
|
||||||
|
* game. The players network address, model, callsign and positoin
|
||||||
|
* are held. When the player is created and open called, the player's
|
||||||
|
* model is loaded onto the scene. The position transform matrix
|
||||||
|
* is updated by calling SetPosition. When Draw is called the
|
||||||
|
* elapsed time since the last update is checked. If the model
|
||||||
|
* position information has been updated in the last TIME_TO_LIVE
|
||||||
|
* seconds then the model position is updated on the scene.
|
||||||
|
*
|
||||||
|
******************************************************************/
|
||||||
|
|
||||||
|
#include "mpplayer.hxx"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <plib/netSocket.h>
|
||||||
|
|
||||||
|
#include <Main/globals.hxx>
|
||||||
|
#include <Model/loader.hxx>
|
||||||
|
#include <Scenery/scenery.hxx>
|
||||||
|
|
||||||
|
|
||||||
|
// These constants are provided so that the ident command can list file versions.
|
||||||
|
const char sMPPLAYER_BID[] = "$Id$";
|
||||||
|
const char sMPPLAYER_HID[] = MPPLAYER_HID;
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: MPPlayer
|
||||||
|
* Description: Constructor.
|
||||||
|
******************************************************************/
|
||||||
|
MPPlayer::MPPlayer() {
|
||||||
|
|
||||||
|
// Initialise private members
|
||||||
|
m_bInitialised = false;
|
||||||
|
m_LastUpdate = 0;
|
||||||
|
m_PlayerAddress.set("localhost", 0);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: ~MPPlayer
|
||||||
|
* Description: Destructor.
|
||||||
|
******************************************************************/
|
||||||
|
MPPlayer::~MPPlayer() {
|
||||||
|
|
||||||
|
Close();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: Open
|
||||||
|
* Description: Initialises class.
|
||||||
|
******************************************************************/
|
||||||
|
bool MPPlayer::Open(const string &sAddress, const int &iPort, const string &sCallsign, const string &sModelName, bool bLocalPlayer) {
|
||||||
|
|
||||||
|
bool bSuccess = true;
|
||||||
|
|
||||||
|
if (!m_bInitialised) {
|
||||||
|
|
||||||
|
m_PlayerAddress.set(sAddress.c_str(), iPort);
|
||||||
|
m_sCallsign = sCallsign;
|
||||||
|
m_sModelName = sModelName;
|
||||||
|
m_bLocalPlayer = bLocalPlayer;
|
||||||
|
|
||||||
|
// If the player is remote then load the model
|
||||||
|
if (!bLocalPlayer) {
|
||||||
|
|
||||||
|
LoadModel();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
m_bInitialised = bSuccess;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
cerr << "MPPlayer::Open - Attempt to open an already open player connection." << endl;
|
||||||
|
bSuccess = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return true if open succeeds */
|
||||||
|
return bSuccess;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: Close
|
||||||
|
* Description: Resets the object.
|
||||||
|
******************************************************************/
|
||||||
|
void MPPlayer::Close(void) {
|
||||||
|
|
||||||
|
|
||||||
|
// Remove the model from the game
|
||||||
|
if (!m_bLocalPlayer) {
|
||||||
|
globals->get_scenery()->get_scene_graph()->removeKid(m_ModelSel);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_bInitialised = false;
|
||||||
|
m_bUpdated = false;
|
||||||
|
m_LastUpdate = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: SetPosition
|
||||||
|
* Description: Updates position data held for this player and resets
|
||||||
|
* the last update time.
|
||||||
|
******************************************************************/
|
||||||
|
void MPPlayer::SetPosition(const sgMat4 PlayerPosMat4) {
|
||||||
|
|
||||||
|
|
||||||
|
// Save the position matrix and update time
|
||||||
|
if (m_bInitialised) {
|
||||||
|
memcpy(m_ModelPos, PlayerPosMat4, sizeof(sgMat4));
|
||||||
|
time(&m_LastUpdate);
|
||||||
|
m_bUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: Draw
|
||||||
|
* Description: Updates the position for the player's model
|
||||||
|
* The state of the player (old, initialised etc)
|
||||||
|
* is returned.
|
||||||
|
******************************************************************/
|
||||||
|
int MPPlayer::Draw(void) {
|
||||||
|
|
||||||
|
int iResult = PLAYER_DATA_NOT_AVAILABLE;
|
||||||
|
|
||||||
|
sgCoord sgPlayerCoord;
|
||||||
|
|
||||||
|
if (m_bInitialised) {
|
||||||
|
if ((time(NULL) - m_LastUpdate < TIME_TO_LIVE)) {
|
||||||
|
// Peform an update if it has changed since the last update
|
||||||
|
if (m_bUpdated) {
|
||||||
|
|
||||||
|
// Transform and update player model
|
||||||
|
m_ModelSel->select(1);
|
||||||
|
sgSetCoord( &sgPlayerCoord, m_ModelPos);
|
||||||
|
m_ModelTrans->setTransform( &sgPlayerCoord );
|
||||||
|
|
||||||
|
iResult = PLAYER_DATA_AVAILABLE;
|
||||||
|
|
||||||
|
// Clear the updated flag so that the position data
|
||||||
|
// is only available if it has changed
|
||||||
|
m_bUpdated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data has not been updated for some time.
|
||||||
|
} else {
|
||||||
|
iResult = PLAYER_DATA_EXPIRED;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return iResult;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: Callsign
|
||||||
|
* Description: Returns the player's callsign.
|
||||||
|
******************************************************************/
|
||||||
|
string MPPlayer::Callsign(void) const {
|
||||||
|
|
||||||
|
return m_sCallsign;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: CompareCallsign
|
||||||
|
* Description: Returns true if the player's callsign matches
|
||||||
|
* the given callsign.
|
||||||
|
******************************************************************/
|
||||||
|
bool MPPlayer::CompareCallsign(const char *sCallsign) const {
|
||||||
|
|
||||||
|
return (m_sCallsign == sCallsign);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: LoadModel
|
||||||
|
* Description: Loads the player's aircraft model.
|
||||||
|
******************************************************************/
|
||||||
|
void MPPlayer::LoadModel(void) {
|
||||||
|
|
||||||
|
|
||||||
|
m_ModelSel = new ssgSelector;
|
||||||
|
m_ModelTrans = new ssgTransform;
|
||||||
|
|
||||||
|
ssgEntity *Model = globals->get_model_loader()->load_model(m_sModelName);
|
||||||
|
Model->clrTraversalMaskBits( SSGTRAV_HOT );
|
||||||
|
m_ModelTrans->addKid( Model );
|
||||||
|
m_ModelSel->addKid( m_ModelTrans );
|
||||||
|
ssgFlatten( Model );
|
||||||
|
ssgStripify( m_ModelSel );
|
||||||
|
|
||||||
|
globals->get_scenery()->get_scene_graph()->addKid( m_ModelSel );
|
||||||
|
globals->get_scenery()->get_scene_graph()->addKid( Model );
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: FillPosMsg
|
||||||
|
* Description: Populates the header and data for a position message.
|
||||||
|
******************************************************************/
|
||||||
|
void MPPlayer::FillPosMsg(T_MsgHdr *MsgHdr, T_PositionMsg *PosMsg) {
|
||||||
|
|
||||||
|
FillMsgHdr(MsgHdr, POS_DATA_ID);
|
||||||
|
|
||||||
|
strncpy(PosMsg->sModel, m_sModelName.c_str(), MAX_MODEL_NAME_LEN);
|
||||||
|
PosMsg->sModel[MAX_MODEL_NAME_LEN - 1] = '\0';
|
||||||
|
|
||||||
|
memcpy(PosMsg->PlayerPos, m_ModelPos, sizeof(sgMat4));
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: FillMsgHdr
|
||||||
|
* Description: Populates the header of a multiplayer message.
|
||||||
|
******************************************************************/
|
||||||
|
void MPPlayer::FillMsgHdr(T_MsgHdr *MsgHdr, const int iMsgId) {
|
||||||
|
|
||||||
|
struct in_addr address;
|
||||||
|
|
||||||
|
MsgHdr->MsgId = iMsgId;
|
||||||
|
|
||||||
|
switch (iMsgId) {
|
||||||
|
case CHAT_MSG_ID:
|
||||||
|
MsgHdr->iMsgLen = sizeof(T_MsgHdr) + sizeof(T_ChatMsg);
|
||||||
|
break;
|
||||||
|
case POS_DATA_ID:
|
||||||
|
MsgHdr->iMsgLen = sizeof(T_MsgHdr) + sizeof(T_PositionMsg);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
MsgHdr->iMsgLen = sizeof(T_MsgHdr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
inet_aton(m_PlayerAddress.getHost(), &address);
|
||||||
|
MsgHdr->lReplyAddress = address.s_addr;
|
||||||
|
|
||||||
|
MsgHdr->iReplyPort = m_PlayerAddress.getPort();
|
||||||
|
|
||||||
|
strncpy(MsgHdr->sCallsign, m_sCallsign.c_str(), MAX_CALLSIGN_LEN);
|
||||||
|
MsgHdr->sCallsign[MAX_CALLSIGN_LEN - 1] = '\0';
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
153
src/MultiPlayer/mpplayer.hxx
Normal file
153
src/MultiPlayer/mpplayer.hxx
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
// mpplayer.hxx -- routines for a player within a multiplayer Flightgear
|
||||||
|
//
|
||||||
|
// Written by Duncan McCreanor, started February 2003.
|
||||||
|
// duncan.mccreanor@airservicesaustralia.com
|
||||||
|
//
|
||||||
|
// Copyright (C) 2003 Airservices Australia
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef MPPLAYER_H
|
||||||
|
#define MPPLAYER_H
|
||||||
|
|
||||||
|
#define MPPLAYER_HID "$Id$"
|
||||||
|
|
||||||
|
/****************************************************************
|
||||||
|
* @version $Id$
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
*
|
||||||
|
******************************************************************/
|
||||||
|
|
||||||
|
#include "mpmessages.hxx"
|
||||||
|
|
||||||
|
#include <plib/ssg.h>
|
||||||
|
#include <plib/sg.h>
|
||||||
|
#include <plib/netSocket.h>
|
||||||
|
#include <simgear/io/sg_socket_udp.hxx>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include STL_STRING
|
||||||
|
SG_USING_STD(string);
|
||||||
|
|
||||||
|
// Number of seconds before a player is consider to be lost
|
||||||
|
#define TIME_TO_LIVE 10
|
||||||
|
|
||||||
|
#define PLAYER_DATA_NOT_AVAILABLE 0
|
||||||
|
#define PLAYER_DATA_AVAILABLE 1
|
||||||
|
#define PLAYER_DATA_EXPIRED 2
|
||||||
|
|
||||||
|
class MPPlayer {
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** Constructor */
|
||||||
|
MPPlayer();
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~MPPlayer();
|
||||||
|
|
||||||
|
/** Initialises the class.
|
||||||
|
* @param sIP IP address or host name for sending data to the player
|
||||||
|
* @param sPort Port number for sending data to the player
|
||||||
|
* @param sCallsign Callsign of the player (must be unique across all instances of MPPlayer).
|
||||||
|
* @param sModelName Path and name of the aircraft model file for the player
|
||||||
|
* @param bLocalPlayer True if this player is the local player, else false
|
||||||
|
* @return True if class opens successfully, else false
|
||||||
|
*/
|
||||||
|
bool Open(const string &sIP, const int &iPort, const string &sCallsign,
|
||||||
|
const string &sModelName, const bool bLocalPlayer);
|
||||||
|
|
||||||
|
/** Initialises the player count for all instances of this object to zero. */
|
||||||
|
static void ResetPlayerCnt(void);
|
||||||
|
|
||||||
|
/** Closes the player connection */
|
||||||
|
void Close(void);
|
||||||
|
|
||||||
|
/** Sets the positioning matrix held for this player
|
||||||
|
* @param PlayerPosMat4 Matrix for positioning player's aircraft
|
||||||
|
*/
|
||||||
|
void SetPosition(const sgMat4 PlayerPosMat4);
|
||||||
|
|
||||||
|
/** Transform and place model for player
|
||||||
|
*/
|
||||||
|
int Draw(void);
|
||||||
|
|
||||||
|
/** Returns the callsign for the player
|
||||||
|
* @return Aircraft's callsign
|
||||||
|
*/
|
||||||
|
string Callsign(void) const;
|
||||||
|
|
||||||
|
/** Compares the player's callsign with the given callsign
|
||||||
|
* @param sCallsign Callsign to compare
|
||||||
|
* @return True if callsign matches
|
||||||
|
*/
|
||||||
|
bool CompareCallsign(const char *sCallsign) const;
|
||||||
|
|
||||||
|
/** Loads the model of the aircraft */
|
||||||
|
void LoadModel(void);
|
||||||
|
|
||||||
|
/** Populates a position message for the player
|
||||||
|
* @param MsgHdr Header to be populated
|
||||||
|
* @param PosMsg Position message to be populated
|
||||||
|
*/
|
||||||
|
void FillPosMsg(T_MsgHdr *MsgHdr, T_PositionMsg *PosMsg);
|
||||||
|
|
||||||
|
/** Populates a mesage header with information for the player
|
||||||
|
* @param MsgHdr Header to be populated
|
||||||
|
* @param iMsgId Message type identifier to insert into header
|
||||||
|
*/
|
||||||
|
void FillMsgHdr(T_MsgHdr *MsgHdr, const int iMsgId);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** True if object is initialised */
|
||||||
|
bool m_bInitialised;
|
||||||
|
|
||||||
|
/** Position matrix for the player's aircraft */
|
||||||
|
sgMat4 m_ModelPos;
|
||||||
|
|
||||||
|
/** Used to remove player if no activity */
|
||||||
|
time_t m_LastUpdate;
|
||||||
|
|
||||||
|
/** Set when the player data is updated and cleared when read */
|
||||||
|
bool m_bUpdated;
|
||||||
|
|
||||||
|
/** Player's callsign */
|
||||||
|
string m_sCallsign;
|
||||||
|
|
||||||
|
/** Aircraft model for player */
|
||||||
|
string m_sModelName;
|
||||||
|
|
||||||
|
/** Simgear model selection */
|
||||||
|
ssgSelector *m_ModelSel;
|
||||||
|
|
||||||
|
/** Simgear model transform */
|
||||||
|
ssgTransform *m_ModelTrans;
|
||||||
|
|
||||||
|
/** True if this player is the local player */
|
||||||
|
bool m_bLocalPlayer;
|
||||||
|
|
||||||
|
/** Address information for the player */
|
||||||
|
netAddress m_PlayerAddress;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
346
src/MultiPlayer/multiplayrxmgr.cxx
Normal file
346
src/MultiPlayer/multiplayrxmgr.cxx
Normal file
|
@ -0,0 +1,346 @@
|
||||||
|
// multiplayrxmgr.cxx -- routines for receiving multiplayer data
|
||||||
|
// for Flightgear
|
||||||
|
//
|
||||||
|
// Written by Duncan McCreanor, started February 2003.
|
||||||
|
// duncan.mccreanor@airservicesaustralia.com
|
||||||
|
//
|
||||||
|
// Copyright (C) 2003 Airservices Australia
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Description: The multiplayer rx manager provides control over
|
||||||
|
* multiplayer data reception and processing for an interactive
|
||||||
|
* multiplayer FlightGear simulation.
|
||||||
|
*
|
||||||
|
* The objects that hold player information are accessed via
|
||||||
|
* a fixed size array. A fixed array is used since it provides
|
||||||
|
* speed benefits over working with linked lists and is easier
|
||||||
|
* to code. Also, there is no point allowing for an unlimited
|
||||||
|
* number of players as too many players will slow the game
|
||||||
|
* down to the point where it is unplayable.
|
||||||
|
*
|
||||||
|
* When player position data is received, the callsign of
|
||||||
|
* the player is checked against existing players. If the
|
||||||
|
* player does not exist, a new player is created in the
|
||||||
|
* next free slot of the player array. If the player does
|
||||||
|
* exist, the player's positional matrix is updated.
|
||||||
|
*
|
||||||
|
* The Update method is used to move the players on the
|
||||||
|
* scene. The return value from calling MPPlayer::Draw
|
||||||
|
* indicates the state of the player. If data for a player
|
||||||
|
* has not been received data for some time, the player object
|
||||||
|
* is deleted and the array element freed.
|
||||||
|
*
|
||||||
|
******************************************************************/
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <plib/netSocket.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <Main/fg_props.hxx>
|
||||||
|
|
||||||
|
#include "multiplayrxmgr.hxx"
|
||||||
|
#include "mpmessages.hxx"
|
||||||
|
#include "mpplayer.hxx"
|
||||||
|
|
||||||
|
#define MAX_PACKET_SIZE 1024
|
||||||
|
|
||||||
|
// These constants are provided so that the ident command can list file versions.
|
||||||
|
const char sMULTIPLAYTXMGR_BID[] = "$Id$";
|
||||||
|
const char sMULTIPLAYRXMGR_HID[] = MULTIPLAYRXMGR_HID;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: FGMultiplayRxMgr
|
||||||
|
* Description: Constructor.
|
||||||
|
******************************************************************/
|
||||||
|
FGMultiplayRxMgr::FGMultiplayRxMgr() {
|
||||||
|
|
||||||
|
int iPlayerCnt; // Count of players in player array
|
||||||
|
|
||||||
|
// Initialise private members
|
||||||
|
m_sRxAddress = "0";
|
||||||
|
m_iRxPort = 0;
|
||||||
|
m_bInitialised = false;
|
||||||
|
|
||||||
|
// Clear the player array
|
||||||
|
for (iPlayerCnt = 0; iPlayerCnt < MAX_PLAYERS; iPlayerCnt++) {
|
||||||
|
m_Player[iPlayerCnt] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: ~FGMultiplayRxMgr
|
||||||
|
* Description: Destructor. Closes and deletes objects owned by
|
||||||
|
* this object.
|
||||||
|
******************************************************************/
|
||||||
|
FGMultiplayRxMgr::~FGMultiplayRxMgr() {
|
||||||
|
|
||||||
|
Close();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: init
|
||||||
|
* Description: Initialises multiplayer receive.
|
||||||
|
******************************************************************/
|
||||||
|
bool FGMultiplayRxMgr::init(void) {
|
||||||
|
|
||||||
|
bool bSuccess = true; // Result of initialisation
|
||||||
|
|
||||||
|
// Initialise object if not already done
|
||||||
|
if (!m_bInitialised) {
|
||||||
|
|
||||||
|
// Set members from property values
|
||||||
|
m_sCallsign = fgGetString("/sim/multiplay/callsign");
|
||||||
|
m_sRxAddress = fgGetString("/sim/multiplay/rxhost");
|
||||||
|
m_iRxPort = fgGetInt("/sim/multiplay/rxport");
|
||||||
|
|
||||||
|
cout << "FGMultiplayRxMgr::init - rxaddress= " << m_sRxAddress << endl;
|
||||||
|
cout << "FGMultiplayRxMgr::init - rxport= " << m_iRxPort << endl;
|
||||||
|
cout << "FGMultiplayRxMgr::init - callsign= " << m_sCallsign << endl;
|
||||||
|
|
||||||
|
// Create and open rx socket
|
||||||
|
mDataRxSocket = new netSocket();
|
||||||
|
if (!mDataRxSocket->open(false)) {
|
||||||
|
// Failed to open rx socket
|
||||||
|
cerr << "FGMultiplayRxMgr::Open - Failed to create data receive socket" << endl;
|
||||||
|
bSuccess = false;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Configure the socket
|
||||||
|
mDataRxSocket->setBlocking(false);
|
||||||
|
mDataRxSocket->setBroadcast(true);
|
||||||
|
if (mDataRxSocket->bind(m_sRxAddress.c_str(), m_iRxPort) != 0) {
|
||||||
|
perror("bind");
|
||||||
|
// Failed to bind
|
||||||
|
cerr << "FGMultiplayRxMgr::Open - Failed to bind receive socket" << endl;
|
||||||
|
bSuccess = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save manager state
|
||||||
|
m_bInitialised = bSuccess;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
cerr << "FGMultiplayRxMgr::OpenRx - Receiver open requested when receiver is already open" << endl;
|
||||||
|
bSuccess = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if open succeeds */
|
||||||
|
return bSuccess;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: Close
|
||||||
|
* Description: Closes and deletes and player connections. Closes
|
||||||
|
* and deletes the rx socket. Resets the object state
|
||||||
|
* to unitialised.
|
||||||
|
******************************************************************/
|
||||||
|
void FGMultiplayRxMgr::Close(void) {
|
||||||
|
|
||||||
|
int iPlayerCnt; // Count of players in player array
|
||||||
|
|
||||||
|
// Delete any existing players
|
||||||
|
for (iPlayerCnt = 0; iPlayerCnt < MAX_PLAYERS; iPlayerCnt++) {
|
||||||
|
if (m_Player[iPlayerCnt] != NULL) {
|
||||||
|
delete m_Player[iPlayerCnt];
|
||||||
|
m_Player[iPlayerCnt] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete socket
|
||||||
|
if (mDataRxSocket) {
|
||||||
|
mDataRxSocket->close();
|
||||||
|
delete mDataRxSocket;
|
||||||
|
mDataRxSocket = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_bInitialised = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: ProcessData
|
||||||
|
* Description: Processes data waiting at the receive socket. The
|
||||||
|
* processing ends when there is no more data at the socket.
|
||||||
|
******************************************************************/
|
||||||
|
void FGMultiplayRxMgr::ProcessData(void) {
|
||||||
|
|
||||||
|
char sMsg[MAX_PACKET_SIZE]; // Buffer for received message
|
||||||
|
int iBytes; // Bytes received
|
||||||
|
T_MsgHdr *MsgHdr; // Pointer to header in received data
|
||||||
|
T_ChatMsg *ChatMsg; // Pointer to chat message in received data
|
||||||
|
T_PositionMsg *PosMsg; // Pointer to position message in received data
|
||||||
|
char *sIpAddress; // Address information from header
|
||||||
|
char *sModelName; // Model that the remote player is using
|
||||||
|
char *sCallsign; // Callsign of the remote player
|
||||||
|
struct in_addr PlayerAddress; // Used for converting the player's address into dot notation
|
||||||
|
int iPlayerCnt; // Count of players in player array
|
||||||
|
bool bActivePlayer = false; // The state of the player that sent the data
|
||||||
|
int iPort; // Port that the remote player receives on
|
||||||
|
|
||||||
|
|
||||||
|
if (m_bInitialised) {
|
||||||
|
|
||||||
|
// Read the receive socket and process any data
|
||||||
|
do {
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
iBytes = mDataRxSocket->recv(sMsg, MAX_PACKET_SIZE, 0);
|
||||||
|
|
||||||
|
// Data received
|
||||||
|
if (iBytes > 0) {
|
||||||
|
if (iBytes >= sizeof(MsgHdr)) {
|
||||||
|
|
||||||
|
// Read header
|
||||||
|
MsgHdr = (T_MsgHdr *)sMsg;
|
||||||
|
PlayerAddress.s_addr = MsgHdr->lReplyAddress;
|
||||||
|
sIpAddress = inet_ntoa(PlayerAddress);
|
||||||
|
iPort = MsgHdr->iReplyPort;
|
||||||
|
sCallsign = MsgHdr->sCallsign;
|
||||||
|
|
||||||
|
// Process the player data unless we generated it
|
||||||
|
if (m_sCallsign != string(MsgHdr->sCallsign)) {
|
||||||
|
|
||||||
|
|
||||||
|
// Process messages
|
||||||
|
switch(MsgHdr->MsgId) {
|
||||||
|
case CHAT_MSG_ID:
|
||||||
|
if (MsgHdr->iMsgLen == sizeof(T_MsgHdr) + sizeof(T_ChatMsg)) {
|
||||||
|
ChatMsg = (T_ChatMsg *)(sMsg + sizeof(T_MsgHdr));
|
||||||
|
cout << "Chat [" << MsgHdr->sCallsign << "]" << " " << ChatMsg->sText << endl;
|
||||||
|
} else {
|
||||||
|
cerr << "FGMultiplayRxMgr::MP_ProcessData - Chat message received with insufficient data" << endl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case POS_DATA_ID:
|
||||||
|
if (MsgHdr->iMsgLen == sizeof(T_MsgHdr) + sizeof(T_PositionMsg)) {
|
||||||
|
PosMsg = (T_PositionMsg *)(sMsg + sizeof(T_MsgHdr));
|
||||||
|
sModelName = PosMsg->sModel;
|
||||||
|
|
||||||
|
// Check if the player is already in the game by using the Callsign.
|
||||||
|
bActivePlayer = false;
|
||||||
|
for (iPlayerCnt = 0; iPlayerCnt < MAX_PLAYERS; iPlayerCnt++) {
|
||||||
|
if (m_Player[iPlayerCnt] != NULL) {
|
||||||
|
if (m_Player[iPlayerCnt]->CompareCallsign(MsgHdr->sCallsign)) {
|
||||||
|
|
||||||
|
// Player found. Update the data for the player.
|
||||||
|
m_Player[iPlayerCnt]->SetPosition(PosMsg->PlayerPos);
|
||||||
|
bActivePlayer = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Player not active, so add as new player
|
||||||
|
if (!bActivePlayer) {
|
||||||
|
iPlayerCnt = 0;
|
||||||
|
do {
|
||||||
|
if (m_Player[iPlayerCnt] == NULL) {
|
||||||
|
cout << "FGMultiplayRxMgr::ProcessRxData - Add new player. IP: " << sIpAddress
|
||||||
|
<< ", Call: " << sCallsign << ", model: " << sModelName << endl;
|
||||||
|
m_Player[iPlayerCnt] = new MPPlayer;
|
||||||
|
m_Player[iPlayerCnt]->Open(string(sIpAddress), iPort, string(sCallsign), string(sModelName), false);
|
||||||
|
m_Player[iPlayerCnt]->SetPosition(PosMsg->PlayerPos);
|
||||||
|
bActivePlayer = true;
|
||||||
|
}
|
||||||
|
iPlayerCnt++;
|
||||||
|
} while (iPlayerCnt < MAX_PLAYERS && !bActivePlayer);
|
||||||
|
|
||||||
|
// Check if the player was added
|
||||||
|
if (!bActivePlayer) {
|
||||||
|
if (iPlayerCnt == MAX_PLAYERS) {
|
||||||
|
cerr << "FGMultiplayRxMgr::MP_ProcessData - Unable to add new player (" << sCallsign << "). Too many players." << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
cerr << "FGMultiplayRxMgr::MP_ProcessData - Position message received with insufficient data" << endl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
cerr << "FGMultiplayRxMgr::MP_ProcessData - Unknown message Id received: " << MsgHdr->MsgId << endl;
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Error or no data
|
||||||
|
} else if (iBytes == -1) {
|
||||||
|
if (errno != EAGAIN) {
|
||||||
|
perror("FGMultiplayRxMgr::MP_ProcessData");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (iBytes > 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: Update
|
||||||
|
* Description: 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 FGMultiplayRxMgr::Update(void) {
|
||||||
|
|
||||||
|
int iPlayerDataState;
|
||||||
|
int iPlayerId;
|
||||||
|
|
||||||
|
for (iPlayerId = 0; iPlayerId < MAX_PLAYERS; iPlayerId++) {
|
||||||
|
if (m_Player[iPlayerId] != NULL) {
|
||||||
|
iPlayerDataState = m_Player[iPlayerId]->Draw();
|
||||||
|
|
||||||
|
// If the player has not received an update for some
|
||||||
|
// time then assume that the player has quit.
|
||||||
|
if (iPlayerDataState == PLAYER_DATA_EXPIRED) {
|
||||||
|
delete m_Player[iPlayerId];
|
||||||
|
m_Player[iPlayerId] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
111
src/MultiPlayer/multiplayrxmgr.hxx
Normal file
111
src/MultiPlayer/multiplayrxmgr.hxx
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
// multiplayrxmgr.hxx -- routines for receiving multiplayer data
|
||||||
|
// for Flghtgear
|
||||||
|
//
|
||||||
|
// Written by Duncan McCreanor, started February 2003.
|
||||||
|
// duncan.mccreanor@airservicesaustralia.com
|
||||||
|
//
|
||||||
|
// Copyright (C) 2003 Airservices Australia
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef MULTIPLAYRXMGR_H
|
||||||
|
#define MULTIPLAYRXMGR_H
|
||||||
|
|
||||||
|
#define MULTIPLAYRXMGR_HID "$Id$"
|
||||||
|
|
||||||
|
|
||||||
|
#include "mpplayer.hxx"
|
||||||
|
#include "mpmessages.hxx"
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include STL_STRING
|
||||||
|
SG_USING_STD(string);
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
#include <plib/ssg.h>
|
||||||
|
#include <plib/netSocket.h>
|
||||||
|
|
||||||
|
// Maximum number of players that can exist at any time
|
||||||
|
#define MAX_PLAYERS 10
|
||||||
|
|
||||||
|
/****************************************************************
|
||||||
|
* @version $Id$
|
||||||
|
*
|
||||||
|
* Description: The multiplay rx manager is responsible for
|
||||||
|
* receiving and processing data from other players.
|
||||||
|
|
||||||
|
* Data from remote players is read from the network and processed
|
||||||
|
* via calling ProcessData. The models for the remote player are
|
||||||
|
* positioned onto the scene by calling Update.
|
||||||
|
*
|
||||||
|
*******************************************************************/
|
||||||
|
class FGMultiplayRxMgr {
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** Constructor */
|
||||||
|
FGMultiplayRxMgr();
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~FGMultiplayRxMgr();
|
||||||
|
|
||||||
|
/** Initialises the multiplayer receiver.
|
||||||
|
* @return True if initialisation succeeds, else false
|
||||||
|
*/
|
||||||
|
bool init(void);
|
||||||
|
|
||||||
|
/** Initiates processing of any data waiting at the rx socket.
|
||||||
|
*/
|
||||||
|
void ProcessData(void);
|
||||||
|
|
||||||
|
/** Updates the model positions for the players
|
||||||
|
*/
|
||||||
|
void Update(void);
|
||||||
|
|
||||||
|
/** Closes the multiplayer manager. Stops any further player packet processing.
|
||||||
|
*/
|
||||||
|
void Close(void);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
|
||||||
|
/** Holds the players that exist in the game */
|
||||||
|
MPPlayer *m_Player[MAX_PLAYERS];
|
||||||
|
|
||||||
|
/** Socket for receiving data from the server or another player */
|
||||||
|
netSocket *mDataRxSocket;
|
||||||
|
|
||||||
|
/** True if multiplay receive is initialised */
|
||||||
|
bool m_bInitialised;
|
||||||
|
|
||||||
|
/** Receive address for multiplayer messages */
|
||||||
|
string m_sRxAddress;
|
||||||
|
|
||||||
|
/** Receive port for multiplayer messages */
|
||||||
|
int m_iRxPort;
|
||||||
|
|
||||||
|
/** Local player's callsign */
|
||||||
|
string m_sCallsign;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
229
src/MultiPlayer/multiplaytxmgr.cxx
Normal file
229
src/MultiPlayer/multiplaytxmgr.cxx
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
// multiplaytxmgr.cxx -- routines for transmitting multiplayer data
|
||||||
|
// for Flightgear
|
||||||
|
//
|
||||||
|
// Written by Duncan McCreanor, started February 2003.
|
||||||
|
// duncan.mccreanor@airservicesaustralia.com
|
||||||
|
//
|
||||||
|
// Copyright (C) 2003 Airservices Australia
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Description: The multiplayer tx manager provides is used
|
||||||
|
* to send data to another player or a server for an
|
||||||
|
* interactive multiplayer FlightGear simulation.
|
||||||
|
*
|
||||||
|
******************************************************************/
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <plib/netSocket.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <Main/fg_props.hxx>
|
||||||
|
#include "multiplaytxmgr.hxx"
|
||||||
|
#include "mpmessages.hxx"
|
||||||
|
#include "mpplayer.hxx"
|
||||||
|
|
||||||
|
// These constants are provided so that the ident command can list file versions.
|
||||||
|
const char sMULTIPLAYTXMGR_BID[] = "$Id$";
|
||||||
|
const char sMULTIPLAYTXMGR_HID[] = MULTIPLAYTXMGR_HID;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: FGMultiplayTxMgr
|
||||||
|
* Description: Constructor.
|
||||||
|
******************************************************************/
|
||||||
|
FGMultiplayTxMgr::FGMultiplayTxMgr() {
|
||||||
|
|
||||||
|
int iPlayerCnt; // Count of players in player array
|
||||||
|
|
||||||
|
// Initialise private members
|
||||||
|
m_bInitialised = false;
|
||||||
|
mLocalPlayer = NULL;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: ~FGMultiplayTxMgr
|
||||||
|
* Description: Destructor. Closes and deletes objects owned by
|
||||||
|
* this object.
|
||||||
|
******************************************************************/
|
||||||
|
FGMultiplayTxMgr::~FGMultiplayTxMgr() {
|
||||||
|
|
||||||
|
Close();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: init
|
||||||
|
* Description: Initialises multiplayer transmit
|
||||||
|
******************************************************************/
|
||||||
|
bool FGMultiplayTxMgr::init(void) {
|
||||||
|
|
||||||
|
|
||||||
|
string sTxAddress; // Destination address
|
||||||
|
int iTxPort;
|
||||||
|
bool bSuccess = true; // Result of initialisation
|
||||||
|
|
||||||
|
// Initialise object if not already done
|
||||||
|
if (!m_bInitialised) {
|
||||||
|
|
||||||
|
// Set members from property values
|
||||||
|
string sTxAddress = fgGetString("/sim/multiplay/txhost");
|
||||||
|
iTxPort = fgGetInt("/sim/multiplay/txport");
|
||||||
|
|
||||||
|
cout << "FGMultiplayTxMgr::init - txaddress= " << sTxAddress << endl;
|
||||||
|
cout << "FGMultiplayTxMgr::init - txport= " << iTxPort << endl;
|
||||||
|
|
||||||
|
if (iTxPort > 0) {
|
||||||
|
|
||||||
|
|
||||||
|
// Create and open tx socket
|
||||||
|
mDataTxSocket = new netSocket();
|
||||||
|
if (!mDataTxSocket->open(false)) {
|
||||||
|
// Failed to open tx socket
|
||||||
|
cerr << "FGMultiplayTxMgr::init - Failed to create data transmit socket" << endl;
|
||||||
|
bSuccess = false;
|
||||||
|
} else {
|
||||||
|
mDataTxSocket->setBroadcast(true);
|
||||||
|
if (mDataTxSocket->connect(sTxAddress.c_str(), iTxPort) != 0) {
|
||||||
|
// Failed to connect tx socket
|
||||||
|
cerr << "FGMultiplayTxMgr::init - Failed to connect data transmit socket" << endl;
|
||||||
|
bSuccess = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a player object for the local player
|
||||||
|
if (bSuccess) {
|
||||||
|
mLocalPlayer = new MPPlayer();
|
||||||
|
if (!mLocalPlayer->Open(fgGetString("/sim/multiplay/rxaddress"), fgGetInt("/sim/multiplay/rxport"),
|
||||||
|
fgGetString("/sim/multiplay/callsign"), fgGetString("/sim/model/path"), true)) {
|
||||||
|
cerr << "FGMultiplayTxMgr::init - Failed to create player object for local player" << endl;
|
||||||
|
bSuccess = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If Tx port == zero then don't initialise
|
||||||
|
} else {
|
||||||
|
|
||||||
|
cout << "FGMultiplayTxMgr::init - Tx Port is zero. Multiplay out disabled." << endl;
|
||||||
|
bSuccess = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save manager state
|
||||||
|
m_bInitialised = bSuccess;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
cerr << "FGMultiplayTxMgr::init - Attempt to init object that is already opened" << endl;
|
||||||
|
bSuccess = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return true if init succeeds */
|
||||||
|
return bSuccess;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: Close
|
||||||
|
* Description: Closes and deletes the local player object. Closes
|
||||||
|
* and deletes the tx socket. Resets the object state to unitialised.
|
||||||
|
******************************************************************/
|
||||||
|
void FGMultiplayTxMgr::Close(void) {
|
||||||
|
|
||||||
|
|
||||||
|
// Delete local player
|
||||||
|
if (mLocalPlayer) {
|
||||||
|
delete mLocalPlayer;
|
||||||
|
mLocalPlayer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete socket
|
||||||
|
if (mDataTxSocket) {
|
||||||
|
mDataTxSocket->close();
|
||||||
|
delete mDataTxSocket;
|
||||||
|
mDataTxSocket = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_bInitialised = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: SendMyPosition
|
||||||
|
* Description: Sends the position data for the local position.
|
||||||
|
******************************************************************/
|
||||||
|
void FGMultiplayTxMgr::SendMyPosition(const sgMat4 PlayerPosMat4) {
|
||||||
|
|
||||||
|
T_MsgHdr MsgHdr;
|
||||||
|
T_PositionMsg PosMsg;
|
||||||
|
char sMsg[sizeof(T_MsgHdr) + sizeof(T_PositionMsg)];
|
||||||
|
|
||||||
|
if (m_bInitialised) {
|
||||||
|
mLocalPlayer->SetPosition(PlayerPosMat4);
|
||||||
|
mLocalPlayer->FillPosMsg(&MsgHdr, &PosMsg);
|
||||||
|
memcpy(sMsg, &MsgHdr, sizeof(T_MsgHdr));
|
||||||
|
memcpy(sMsg + sizeof(T_MsgHdr), &PosMsg, sizeof(T_PositionMsg));
|
||||||
|
mDataTxSocket->send(sMsg, sizeof(T_MsgHdr) + sizeof(T_PositionMsg), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: SendTextMessage
|
||||||
|
* Description: Sends a message to the player. The message must
|
||||||
|
* contain a valid and correctly filled out header and optional
|
||||||
|
* message body.
|
||||||
|
******************************************************************/
|
||||||
|
void FGMultiplayTxMgr::SendTextMessage(const string &sMsgText) const {
|
||||||
|
|
||||||
|
bool bResult = false;
|
||||||
|
T_MsgHdr MsgHdr;
|
||||||
|
T_ChatMsg ChatMsg;
|
||||||
|
int iNextBlockPosition = 0;
|
||||||
|
char sMsg[sizeof(T_MsgHdr) + sizeof(T_ChatMsg)];
|
||||||
|
|
||||||
|
if (m_bInitialised) {
|
||||||
|
|
||||||
|
mLocalPlayer->FillMsgHdr(&MsgHdr, CHAT_MSG_ID);
|
||||||
|
|
||||||
|
// Divide the text string into blocks that fit in the message
|
||||||
|
// and send the blocks.
|
||||||
|
while (iNextBlockPosition < sMsgText.length()) {
|
||||||
|
strncpy(ChatMsg.sText, sMsgText.substr(iNextBlockPosition, MAX_CHAT_MSG_LEN - 1).c_str(), MAX_CHAT_MSG_LEN);
|
||||||
|
ChatMsg.sText[MAX_CHAT_MSG_LEN - 1] = '\0';
|
||||||
|
memcpy(sMsg, &MsgHdr, sizeof(T_MsgHdr));
|
||||||
|
memcpy(sMsg + sizeof(T_MsgHdr), &ChatMsg, sizeof(T_ChatMsg));
|
||||||
|
mDataTxSocket->send(sMsg, sizeof(T_MsgHdr) + sizeof(T_ChatMsg), 0);
|
||||||
|
iNextBlockPosition += MAX_CHAT_MSG_LEN - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
102
src/MultiPlayer/multiplaytxmgr.hxx
Normal file
102
src/MultiPlayer/multiplaytxmgr.hxx
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
// multiplaytxmgr.hxx -- routines for transmitting multiplayer data
|
||||||
|
// for Flghtgear
|
||||||
|
//
|
||||||
|
// Written by Duncan McCreanor, started February 2003.
|
||||||
|
// duncan.mccreanor@airservicesaustralia.com
|
||||||
|
//
|
||||||
|
// Copyright (C) 2003 Airservices Australia
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef MULTIPLAYTXMGR_H
|
||||||
|
#define MULTIPLAYTXMGR_H
|
||||||
|
|
||||||
|
#define MULTIPLAYTXMGR_HID "$Id$"
|
||||||
|
|
||||||
|
|
||||||
|
#include "mpplayer.hxx"
|
||||||
|
#include "mpmessages.hxx"
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include STL_STRING
|
||||||
|
SG_USING_STD(string);
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
#include <plib/ssg.h>
|
||||||
|
#include <plib/netSocket.h>
|
||||||
|
|
||||||
|
// Maximum number of players that can exist at any time
|
||||||
|
#define MAX_PLAYERS 10
|
||||||
|
|
||||||
|
/****************************************************************
|
||||||
|
* @version $Id$
|
||||||
|
*
|
||||||
|
* Description: The multiplay tx manager is responsible for
|
||||||
|
* sending data to another player or a multiplayer server.
|
||||||
|
*
|
||||||
|
* The position information for the local player is transmitted
|
||||||
|
* on each call to SendMyPosition.
|
||||||
|
*
|
||||||
|
*******************************************************************/
|
||||||
|
class FGMultiplayTxMgr {
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** Constructor */
|
||||||
|
FGMultiplayTxMgr();
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~FGMultiplayTxMgr();
|
||||||
|
|
||||||
|
/** Initialises the multiplayer transmitter.
|
||||||
|
* @return True if initialisation succeeds, else false
|
||||||
|
*/
|
||||||
|
bool init(void);
|
||||||
|
|
||||||
|
/** Sends the position data for the local player
|
||||||
|
* @param PlayerPosMat4 Transformation matrix for the player's position
|
||||||
|
*/
|
||||||
|
void SendMyPosition(const sgMat4 PlayerPosMat4);
|
||||||
|
|
||||||
|
/** Sends a tex chat message.
|
||||||
|
* @param sMsgText Message text to send
|
||||||
|
*/
|
||||||
|
void SendTextMessage(const string &sMsgText) const;
|
||||||
|
|
||||||
|
/** Closes the multiplayer manager. Stops any further player packet processing.
|
||||||
|
*/
|
||||||
|
void Close(void);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** The local player */
|
||||||
|
MPPlayer *mLocalPlayer;
|
||||||
|
|
||||||
|
/** Socket for sending to the server or another player if playing point to point */
|
||||||
|
netSocket *mDataTxSocket;
|
||||||
|
|
||||||
|
/** True if multiplay transmit is initialised */
|
||||||
|
bool m_bInitialised;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ libNetwork_a_SOURCES = \
|
||||||
net_ctrls.hxx net_fdm.hxx net_fdm_mini.hxx \
|
net_ctrls.hxx net_fdm.hxx net_fdm_mini.hxx \
|
||||||
nmea.cxx nmea.hxx \
|
nmea.cxx nmea.hxx \
|
||||||
opengc.cxx opengc.hxx opengc_data.hxx \
|
opengc.cxx opengc.hxx opengc_data.hxx \
|
||||||
|
multiplay.cxx multiplay.hxx \
|
||||||
props.cxx props.hxx \
|
props.cxx props.hxx \
|
||||||
pve.cxx pve.hxx \
|
pve.cxx pve.hxx \
|
||||||
ray.cxx ray.hxx \
|
ray.cxx ray.hxx \
|
||||||
|
|
135
src/Network/multiplay.cxx
Normal file
135
src/Network/multiplay.cxx
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
// multiplay.cxx -- protocol object for multiplay in Flightgear
|
||||||
|
//
|
||||||
|
// Written by Diarmuid Tyson, started February 2003.
|
||||||
|
// diarmuid.tyson@airservicesaustralia.com
|
||||||
|
//
|
||||||
|
// Copyright (C) 2003 Airservices Australia
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
|
#include STL_STRING
|
||||||
|
|
||||||
|
#include <iostream.h>
|
||||||
|
|
||||||
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
|
||||||
|
#include "multiplay.hxx"
|
||||||
|
|
||||||
|
SG_USING_STD(string);
|
||||||
|
|
||||||
|
|
||||||
|
// These constants are provided so that the ident command can list file versions.
|
||||||
|
const char sFG_MULTIPLAY_BID[] = "$Id$";
|
||||||
|
const char sFG_MULTIPLAY_HID[] = FG_MULTIPLAY_HID;
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: FGMultiplay
|
||||||
|
* Description: Constructor. Initialises the protocol and stores
|
||||||
|
* host and port information.
|
||||||
|
******************************************************************/
|
||||||
|
FGMultiplay::FGMultiplay (const string &dir, const int rate, const string &host, const int port) {
|
||||||
|
|
||||||
|
set_hz(rate);
|
||||||
|
|
||||||
|
set_direction(dir);
|
||||||
|
|
||||||
|
if (get_direction() == SG_IO_IN) {
|
||||||
|
|
||||||
|
fgSetInt("/sim/multiplay/rxport", port);
|
||||||
|
fgSetString("/sim/multiplay/rxhost", host.c_str());
|
||||||
|
|
||||||
|
} else if (get_direction() == SG_IO_OUT) {
|
||||||
|
|
||||||
|
fgSetInt("/sim/multiplay/txport", port);
|
||||||
|
fgSetString("/sim/multiplay/txhost", host.c_str());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: ~FGMultiplay
|
||||||
|
* Description: Destructor.
|
||||||
|
******************************************************************/
|
||||||
|
FGMultiplay::~FGMultiplay () {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: open
|
||||||
|
* Description: Enables the protocol.
|
||||||
|
******************************************************************/
|
||||||
|
bool FGMultiplay::open() {
|
||||||
|
|
||||||
|
if ( is_enabled() ) {
|
||||||
|
SG_LOG( SG_IO, SG_ALERT, "This shouldn't happen, but the channel "
|
||||||
|
<< "is already in use, ignoring" );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_enabled(true);
|
||||||
|
|
||||||
|
return is_enabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: process
|
||||||
|
* Description: Prompts the multiplayer mgr to either send
|
||||||
|
* or receive data over the network
|
||||||
|
******************************************************************/
|
||||||
|
bool FGMultiplay::process() {
|
||||||
|
|
||||||
|
if (get_direction() == SG_IO_IN) {
|
||||||
|
|
||||||
|
globals->get_multiplayer_rx_mgr()->ProcessData();
|
||||||
|
|
||||||
|
} else if (get_direction() == SG_IO_OUT) {
|
||||||
|
|
||||||
|
globals->get_multiplayer_tx_mgr()->
|
||||||
|
SendMyPosition(globals->get_aircraft_model()->get3DModel()->get_POS());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* Name: close
|
||||||
|
* Description: Closes the multiplayer mgrs to stop any further
|
||||||
|
* network processing
|
||||||
|
******************************************************************/
|
||||||
|
bool FGMultiplay::close() {
|
||||||
|
|
||||||
|
if (get_direction() == SG_IO_IN) {
|
||||||
|
|
||||||
|
globals->get_multiplayer_rx_mgr()->Close();
|
||||||
|
|
||||||
|
} else if (get_direction() == SG_IO_OUT) {
|
||||||
|
|
||||||
|
globals->get_multiplayer_tx_mgr()->Close();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
81
src/Network/multiplay.hxx
Normal file
81
src/Network/multiplay.hxx
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
// multiplay.hxx -- protocol object for multiplay in Flightgear
|
||||||
|
//
|
||||||
|
// Written by Diarmuid Tyson, started February 2003.
|
||||||
|
// diarmuid.tyson@airservicesaustralia.com
|
||||||
|
//
|
||||||
|
// Copyright (C) 2003 Airservices Australia
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef _FG_MULTIPLAY_HXX
|
||||||
|
#define _FG_MULTIPLAY_HXX
|
||||||
|
|
||||||
|
#define FG_MULTIPLAY_HID "$Id$"
|
||||||
|
|
||||||
|
#include STL_STRING
|
||||||
|
SG_USING_STD(string);
|
||||||
|
|
||||||
|
#include "protocol.hxx"
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
#include <Main/globals.hxx>
|
||||||
|
#include <Main/fg_props.hxx>
|
||||||
|
#include <Model/acmodel.hxx>
|
||||||
|
#include <Model/model.hxx>
|
||||||
|
#include <MultiPlayer/multiplaytxmgr.hxx>
|
||||||
|
#include <MultiPlayer/multiplayrxmgr.hxx>
|
||||||
|
|
||||||
|
/****************************************************************
|
||||||
|
* @version $Id$
|
||||||
|
*
|
||||||
|
* Description: FGMultiplay is an FGProtocol object used as the basic
|
||||||
|
* interface for the multiplayer code into FlightGears generic IO
|
||||||
|
* subsystem. It only implements the basic FGProtocol methods: open(),
|
||||||
|
* process() and close(). It does not use Sim Gear's IO channels, as
|
||||||
|
* the MultiplayMgrs creates their own sockets through plib.
|
||||||
|
*
|
||||||
|
* It will set up it's direction and rate protocol properties when
|
||||||
|
* created. Subsequent calls to process will prompt the
|
||||||
|
* MultiplayMgr to either send or receive data over the network.
|
||||||
|
*
|
||||||
|
******************************************************************/
|
||||||
|
|
||||||
|
class FGMultiplay : public FGProtocol {
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** Constructor */
|
||||||
|
FGMultiplay (const string &dir, const int rate, const string &host, const int port);
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~FGMultiplay ();
|
||||||
|
|
||||||
|
/** Enables the FGMultiplay object
|
||||||
|
*/
|
||||||
|
bool open();
|
||||||
|
|
||||||
|
/** Tells the multiplayer_mgr to send/receive data.
|
||||||
|
*/
|
||||||
|
bool process();
|
||||||
|
|
||||||
|
/** Closes the multiplayer_mgr.
|
||||||
|
*/
|
||||||
|
bool close();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _FG_MULTIPLAY_HXX
|
Loading…
Reference in a new issue