Hello ,
I resubmit my patch .
This reason of this patch is to have a better behavior of flightgear when you
fly
in multi screen configuration with multi-player mode .
When you setup a multi-monitor configuration you have multi instances
of flightgear ( see http://www.inkdrop.net/dave/multimon.pdf ) .
Currently i play with the bo105 , without patchs i had bad second effects .
1) A part of instruments are not synchronized , and the animation too .
It's the why i had wrote :
patch_001_helico.v4.txt
=> add some helicopter specifics fields in the layer commnunication
between flightgear instance .
patch_006_netfdm_gear_agl.txt
=> add another field in the layer commnunication between flightgear
instance .
2) On the second screen , i dont see multiplayer .
A small solution to solve the problem was to resend the packet coming from
the multiplayer server to the other instance of flightgear .
- patch_002_multiplayer.txt
3) Scenery objects are not syncronized between differents instance of
flightgear,
and i prefer to see only real player .
So i had a option to disable all ai objects except multiplayer .
- patch_003_no_ai_except_multiplayer.txt
In attachement 4 patchs for the cvs of fligtgear .
Who can push this patch in the cvs ?
--
Erwan MAS
Index: src/Network/net_fdm.hxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Network/net_fdm.hxx,v
retrieving revision 1.24
diff -u -r1.24 net_fdm.hxx
--- src/Network/net_fdm.hxx 21 Mar 2006 18:51:57 -0000 1.24
+++ src/Network/net_fdm.hxx 17 Aug 2008 20:23:56 -0000
@@ -22,7 +22,7 @@
// I am not aware of any platforms that don't use 4 bytes for float
// and 8 bytes for double.
-const uint32_t FG_NET_FDM_VERSION = 24;
+const uint32_t FG_NET_FDM_VERSION = 25;
// Define a structure containing the top level flight dynamics model
@@ -35,7 +35,9 @@
enum {
FG_MAX_ENGINES = 4,
FG_MAX_WHEELS = 3,
- FG_MAX_TANKS = 4
+ FG_MAX_TANKS = 4,
+ FG_MAX_ROTOR_BLADE = 4 ,
+ FG_MAX_TAIL_BLADE = 2
};
uint32_t version; // increment when data values change
@@ -83,6 +85,10 @@
uint32_t num_engines; // Number of valid engines
uint32_t eng_state[FG_MAX_ENGINES];// Engine state (off, cranking, running)
float rpm[FG_MAX_ENGINES]; // Engine RPM rev/min
+ float n1_pct[FG_MAX_ENGINES]; //
+ float n2_pct[FG_MAX_ENGINES]; //
+ float n1_rpm[FG_MAX_ENGINES]; //
+ float n2_rpm[FG_MAX_ENGINES]; //
float fuel_flow[FG_MAX_ENGINES]; // Fuel flow gallons/hr
float fuel_px[FG_MAX_ENGINES]; // Fuel pressure psi
float egt[FG_MAX_ENGINES]; // Exhuast gas temp deg F
@@ -120,6 +126,21 @@
float nose_wheel;
float speedbrake;
float spoilers;
+
+ // helicopter variables
+ float rotors_main_rpm ;
+ float rotors_main_roll ;
+ float rotors_main_yaw ;
+ float rotors_gear_total_torque ;
+ uint32_t num_rotors_main_blade ;
+ float rotors_main_blade_flap[FG_MAX_ROTOR_BLADE];
+ float rotors_main_blade_incidence[FG_MAX_ROTOR_BLADE];
+ float rotors_main_blade_position[FG_MAX_ROTOR_BLADE];
+ uint32_t num_rotors_tail_blade ;
+ float rotors_tail_rpm ;
+ float rotors_tail_blade_incidence[FG_MAX_TAIL_BLADE];
+ float rotors_tail_blade_position[FG_MAX_TAIL_BLADE];
+
};
Index: src/Network/native_fdm.cxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Network/native_fdm.cxx,v
retrieving revision 1.32
diff -u -r1.32 native_fdm.cxx
--- src/Network/native_fdm.cxx 7 Nov 2007 17:41:31 -0000 1.32
+++ src/Network/native_fdm.cxx 17 Aug 2008 20:23:56 -0000
@@ -170,6 +170,10 @@
net->eng_state[i] = 0;
}
net->rpm[i] = node->getDoubleValue( "rpm" );
+ net->n1_pct[i] = node->getDoubleValue( "n1-pct" );
+ net->n2_pct[i] = node->getDoubleValue( "n2-pct" );
+ net->n1_rpm[i] = node->getDoubleValue( "n1-rpm" );
+ net->n2_rpm[i] = node->getDoubleValue( "n2-rpm" );
net->fuel_flow[i] = node->getDoubleValue( "fuel-flow-gph" );
net->fuel_px[i] = node->getDoubleValue( "fuel-px-psi" );
net->egt[i] = node->getDoubleValue( "egt-degf" );
@@ -197,14 +201,41 @@
net->gear_steer[i] = node->getDoubleValue("steering-norm");
net->gear_compression[i] = node->getDoubleValue("compression-norm");
}
-
+ // ----------------------------------------------
+ // helicopter -- main rotor
+ SGPropertyNode *node = fgGetNode("/rotors/main", true);
+ net->rotors_main_rpm = node->getDoubleValue("rpm") ;
+ net->rotors_main_roll = node->getDoubleValue("roll-deg");
+ net->rotors_main_yaw = node->getDoubleValue("yaw-deg");
+ // helicopter -- total-torque
+ node = fgGetNode("/rotors/gear", true);
+ net->rotors_gear_total_torque = node->getDoubleValue("total-torque") ;
+ // helicopter -- blade for main rotor
+ net->num_rotors_main_blade = FGNetFDM::FG_MAX_ROTOR_BLADE;
+ for (i = 0; i < net->num_rotors_main_blade; ++i ) {
+ SGPropertyNode *node = fgGetNode("/rotors/main/blade", i, true);
+ net->rotors_main_blade_flap[i] = node->getDoubleValue("flap-deg");
+ net->rotors_main_blade_incidence[i] =
node->getDoubleValue("incidence-deg");
+ net->rotors_main_blade_position[i] =
node->getDoubleValue("position-deg");
+ }
+ // helicopter -- tail rotor
+ node = fgGetNode("/rotors/tail", true);
+ net->rotors_tail_rpm = node->getDoubleValue("rpm") ;
+ // helicopter -- blade for main rotor
+ net->num_rotors_tail_blade = FGNetFDM::FG_MAX_TAIL_BLADE;
+ for (i = 0; i < net->num_rotors_tail_blade; ++i ) {
+ SGPropertyNode *node = fgGetNode("/rotors/tail/blade", i, true);
+ net->rotors_tail_blade_incidence[i] =
node->getDoubleValue("incidence-deg");
+ net->rotors_tail_blade_position[i] =
node->getDoubleValue("position-deg");
+ }
+ // ----------------------------------------------
// the following really aren't used in this context
net->cur_time = globals->get_time_params()->get_cur_time();
net->warp = globals->get_warp();
net->visibility = fgGetDouble("/environment/visibility-m");
// Control surface positions
- SGPropertyNode *node = fgGetNode("/surface-positions", true);
+ node = fgGetNode("/surface-positions", true);
net->elevator = node->getDoubleValue( "elevator-pos-norm" );
net->elevator_trim_tab
= node->getDoubleValue( "elevator-trim-tab-pos-norm" );
@@ -254,6 +285,10 @@
for ( i = 0; i < net->num_engines; ++i ) {
net->eng_state[i] = htonl(net->eng_state[i]);
htonf(net->rpm[i]);
+ htonf(net->n1_pct[i]);
+ htonf(net->n2_pct[i]);
+ htonf(net->n1_rpm[i]);
+ htonf(net->n2_rpm[i]);
htonf(net->fuel_flow[i]);
htonf(net->fuel_px[i]);
htonf(net->egt[i]);
@@ -292,6 +327,25 @@
htonf(net->nose_wheel);
htonf(net->speedbrake);
htonf(net->spoilers);
+
+ htonf(net->rotors_main_rpm);
+ htonf(net->rotors_main_roll);
+ htonf(net->rotors_main_yaw);
+ htonf(net->rotors_gear_total_torque);
+
+ for (i = 0; i < net->num_rotors_main_blade; ++i ) {
+ htonf(net->rotors_main_blade_flap[i]);
+ htonf(net->rotors_main_blade_incidence[i]);
+ htonf(net->rotors_main_blade_position[i]);
+ }
+ net->num_rotors_main_blade=htonl(net->num_rotors_main_blade);
+ htonf(net->rotors_tail_rpm);
+ for (i = 0; i < net->num_rotors_tail_blade; ++i ) {
+ htonf(net->rotors_tail_blade_incidence[i]);
+ htonf(net->rotors_tail_blade_position[i]);
+ }
+ net->num_rotors_tail_blade=htonl(net->num_rotors_tail_blade);
+
}
}
@@ -336,6 +390,10 @@
for ( i = 0; i < net->num_engines; ++i ) {
net->eng_state[i] = htonl(net->eng_state[i]);
htonf(net->rpm[i]);
+ htonf(net->n1_pct[i]);
+ htonf(net->n2_pct[i]);
+ htonf(net->n1_rpm[i]);
+ htonf(net->n2_rpm[i]);
htonf(net->fuel_flow[i]);
htonf(net->fuel_px[i]);
htonf(net->egt[i]);
@@ -373,6 +431,24 @@
htonf(net->nose_wheel);
htonf(net->speedbrake);
htonf(net->spoilers);
+
+ htonf(net->rotors_main_rpm);
+ htonf(net->rotors_main_roll);
+ htonf(net->rotors_main_yaw);
+ htonf(net->rotors_gear_total_torque);
+ net->num_rotors_main_blade = htonl(net->num_rotors_main_blade);
+ for (i = 0; i < net->num_rotors_main_blade; ++i ) {
+ htonf(net->rotors_main_blade_flap[i]);
+ htonf(net->rotors_main_blade_incidence[i]);
+ htonf(net->rotors_main_blade_position[i]);
+ }
+ htonf(net->rotors_tail_rpm);
+ net->num_rotors_tail_blade = htonl(net->num_rotors_tail_blade);
+ for (i = 0; i < net->num_rotors_tail_blade; ++i ) {
+ htonf(net->rotors_tail_blade_incidence[i]);
+ htonf(net->rotors_tail_blade_position[i]);
+ }
+
}
if ( net->version == FG_NET_FDM_VERSION ) {
@@ -436,6 +512,10 @@
node->setDoubleValue( "rpm", net->rpm[i] );
node->setDoubleValue( "fuel-flow-gph", net->fuel_flow[i] );
+ node->setDoubleValue( "n1-pct", net->n1_pct[i] );
+ node->setDoubleValue( "n2-pct", net->n2_pct[i] );
+ node->setDoubleValue( "n1-rpm", net->n1_rpm[i] );
+ node->setDoubleValue( "n2-rpm", net->n2_rpm[i] );
node->setDoubleValue( "fuel-px-psi", net->fuel_px[i] );
node->setDoubleValue( "egt-degf", net->egt[i] );
node->setDoubleValue( "cht-degf", net->cht[i] );
@@ -458,7 +538,32 @@
node->setDoubleValue("steering-norm", net->gear_steer[i] );
node->setDoubleValue("compression-norm", net->gear_compression[i] );
}
-
+ // ----------------------------------------------
+ // helicopter -- main rotor
+ SGPropertyNode *node = fgGetNode("/rotors/main", true);
+ node->setDoubleValue("rpm", net->rotors_main_rpm );
+ node->setDoubleValue("roll-deg", net->rotors_main_roll );
+ node->setDoubleValue("yaw-deg", net->rotors_main_yaw );
+ // helicopter -- total-torque
+ node = fgGetNode("/rotors/gear", true);
+ node->setDoubleValue("total-torque", net->rotors_gear_total_torque
);
+ // helicopter -- blade for main rotor
+ for (i = 0; i < net->num_rotors_main_blade; ++i ) {
+ SGPropertyNode *node = fgGetNode("/rotors/main/blade", i, true);
+ node->setDoubleValue("flap-deg",net->rotors_main_blade_flap[i]
);
+
node->setDoubleValue("incidence-deg",net->rotors_main_blade_incidence[i] );
+
node->setDoubleValue("position-deg",net->rotors_main_blade_position[i] );
+ }
+ // helicopter -- tail rotor
+ node = fgGetNode("/rotors/tail", true);
+ node->setDoubleValue("rpm", net->rotors_tail_rpm );
+ // helicopter -- blade for main rotor
+ for (i = 0; i < net->num_rotors_tail_blade; ++i ) {
+ SGPropertyNode *node = fgGetNode("/rotors/tail/blade", i, true);
+
node->setDoubleValue("incidence-deg",net->rotors_tail_blade_incidence[i] );
+
node->setDoubleValue("position-deg",net->rotors_tail_blade_position[i] );
+ }
+ // ----------------------------------------------
/* these are ignored for now ... */
/*
if ( net->cur_time ) {
@@ -469,7 +574,7 @@
last_warp = net->warp;
*/
- SGPropertyNode *node = fgGetNode("/surface-positions", true);
+ node = fgGetNode("/surface-positions", true);
node->setDoubleValue("elevator-pos-norm", net->elevator);
node->setDoubleValue("elevator-trim-tab-pos-norm",
net->elevator_trim_tab);
Index: src/Main/options.cxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Main/options.cxx,v
retrieving revision 1.108
diff -u -r1.108 options.cxx
--- src/Main/options.cxx 1 May 2008 21:14:02 -0000 1.108
+++ src/Main/options.cxx 15 Jun 2008 15:24:23 -0000
@@ -239,8 +239,10 @@
fgSetString("/sim/multiplay/callsign", "callsign");
fgSetString("/sim/multiplay/rxhost", "0");
fgSetString("/sim/multiplay/txhost", "0");
+ fgSetString("/sim/multiplay/repeathost", "0");
fgSetInt("/sim/multiplay/rxport", 0);
fgSetInt("/sim/multiplay/txport", 0);
+ fgSetInt("/sim/multiplay/repeatport", 0);
}
static bool
Index: src/MultiPlayer/multiplaymgr.cxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/MultiPlayer/multiplaymgr.cxx,v
retrieving revision 1.23
diff -u -r1.23 multiplaymgr.cxx
--- src/MultiPlayer/multiplaymgr.cxx 3 Jun 2008 15:57:33 -0000 1.23
+++ src/MultiPlayer/multiplaymgr.cxx 15 Jun 2008 15:24:23 -0000
@@ -200,6 +200,7 @@
mSocket = 0;
mInitialised = false;
mHaveServer = false;
+ repeatHaveServer = false ;
} // FGMultiplayMgr::FGMultiplayMgr()
//////////////////////////////////////////////////////////////////////
@@ -255,6 +256,12 @@
"FGMultiplayMgr - No receiver port, Multiplayermode disabled");
return (false);
}
+ short repeatPort = fgGetInt("/sim/multiplay/repeatport");
+ string repeatAddress = fgGetString("/sim/multiplay/repeathost");
+ if (repeatPort > 0 && !repeatAddress.empty()) {
+ repeatHaveServer = true;
+ repeatServer.set(repeatAddress.c_str(), repeatPort);
+ }
if (mCallsign.empty())
mCallsign = "JohnDoe"; // FIXME: use getpwuid
SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-txaddress= "<<txAddress);
@@ -262,6 +269,8 @@
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);
+ SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-repeataddress=
"<<repeatAddress);
+ SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-repeatport= "<<repeatPort );
Close(); // Should Init be called twice, close Socket first
// A memory leak was reported here by valgrind
mSocket = new netSocket();
@@ -521,6 +530,7 @@
int bytes;
do {
char Msg[MAX_PACKET_SIZE];
+ char MsgOriginal[MAX_PACKET_SIZE];
//////////////////////////////////////////////////
// Although the recv call asks for
// MAX_PACKET_SIZE of data, the number of bytes
@@ -545,6 +555,9 @@
//////////////////////////////////////////////////
// Read header
//////////////////////////////////////////////////
+ if (repeatHaveServer ) {
+ memcpy(MsgOriginal,Msg,MAX_PACKET_SIZE) ;
+ }
T_MsgHdr* MsgHdr = (T_MsgHdr *)Msg;
MsgHdr->Magic = XDR_decode_uint32 (MsgHdr->Magic);
MsgHdr->Version = XDR_decode_uint32 (MsgHdr->Version);
@@ -574,6 +587,9 @@
ProcessChatMsg(Msg, SenderAddress);
break;
case POS_DATA_ID:
+ if ( repeatHaveServer ) {
+ mSocket->sendto(MsgOriginal, bytes, 0, &repeatServer);
+ }
ProcessPosMsg(Msg, SenderAddress, bytes, stamp);
break;
case UNUSABLE_POS_DATA_ID:
Index: src/MultiPlayer/multiplaymgr.hxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/MultiPlayer/multiplaymgr.hxx,v
retrieving revision 1.6
diff -u -r1.6 multiplaymgr.hxx
--- src/MultiPlayer/multiplaymgr.hxx 22 Mar 2008 09:31:09 -0000 1.6
+++ src/MultiPlayer/multiplaymgr.hxx 15 Jun 2008 15:24:23 -0000
@@ -88,7 +88,9 @@
netSocket* mSocket;
netAddress mServer;
+ netAddress repeatServer;
bool mHaveServer;
+ bool repeatHaveServer ;
bool mInitialised;
string mCallsign;
};
Index: src/Network/multiplay.cxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Network/multiplay.cxx,v
retrieving revision 1.15
diff -u -r1.15 multiplay.cxx
--- src/Network/multiplay.cxx 10 Oct 2006 05:17:07 -0000 1.15
+++ src/Network/multiplay.cxx 15 Jun 2008 15:24:23 -0000
@@ -59,6 +59,11 @@
set_hz(rate);
+ if (dir == "repeat" ) {
+ set_direction("out");
+ fgSetInt("/sim/multiplay/repeatport", port);
+ fgSetString("/sim/multiplay/repeathost", host.c_str());
+ } else {
set_direction(dir);
if (get_direction() == SG_IO_IN) {
@@ -72,6 +77,7 @@
fgSetString("/sim/multiplay/txhost", host.c_str());
}
+ }
}
Index: src/Main/options.cxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/Main/options.cxx,v
retrieving revision 1.108
diff -u -r1.108 options.cxx
--- src/Main/options.cxx 1 May 2008 21:14:02 -0000 1.108
+++ src/Main/options.cxx 15 Jun 2008 15:48:03 -0000
@@ -236,6 +236,8 @@
fgSetBool("/sim/freeze/clock", false);
fgSetBool("/sim/freeze/fuel", false);
+ fgSetBool("/sim/ai/restrict-multiplayer", false);
+
fgSetString("/sim/multiplay/callsign", "callsign");
fgSetString("/sim/multiplay/rxhost", "0");
fgSetString("/sim/multiplay/txhost", "0");
@@ -1266,6 +1268,8 @@
{"enable-real-weather-fetch", false, OPTION_BOOL,
"/environment/params/real-world-weather-fetch", true, "", 0 },
{"disable-ai-models", false, OPTION_BOOL, "/sim/ai/enabled",
false, "", 0 },
{"enable-ai-models", false, OPTION_BOOL, "/sim/ai/enabled",
true, "", 0 },
+ {"enable-ai-restrict-multiplayer", false, OPTION_BOOL,
"/sim/ai/restrict-multiplayer", true , "", 0 },
+ {"disable-ai-restrict-multiplayer", false, OPTION_BOOL,
"/sim/ai/restrict-multiplayer", false, "", 0 },
{"disable-freeze", false, OPTION_BOOL,
"/sim/freeze/master", false, "", 0 },
{"enable-freeze", false, OPTION_BOOL,
"/sim/freeze/master", true, "", 0 },
{"disable-fuel-freeze", false, OPTION_BOOL, "/sim/freeze/fuel",
false, "", 0 },
Index: src/AIModel/AIManager.hxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/AIModel/AIManager.hxx,v
retrieving revision 1.47
diff -u -r1.47 AIManager.hxx
--- src/AIModel/AIManager.hxx 22 Mar 2008 09:31:07 -0000 1.47
+++ src/AIModel/AIManager.hxx 15 Jun 2008 15:48:03 -0000
@@ -94,6 +94,7 @@
private:
bool enabled;
+ bool restrict_multiplayer;
int mNumAiTypeModels[FGAIBase::MAX_OBJECTS];
int mNumAiModels;
Index: src/AIModel/AIManager.cxx
===================================================================
RCS file: /var/cvs/FlightGear-0.9/source/src/AIModel/AIManager.cxx,v
retrieving revision 1.84
diff -u -r1.84 AIManager.cxx
--- src/AIModel/AIManager.cxx 1 Jun 2008 14:59:20 -0000 1.84
+++ src/AIModel/AIManager.cxx 15 Jun 2008 15:48:03 -0000
@@ -61,6 +61,8 @@
enabled = root->getNode("enabled", true)->getBoolValue();
+ restrict_multiplayer = root->getNode("restrict-multiplayer",
true)->getBoolValue();
+
if (!enabled)
return;
@@ -183,6 +185,13 @@
SGPropertyNode* p;
int i;
+ // restrict_multiplayer => only static and otMultiplayer are display
+ if ( ( restrict_multiplayer ) &&
+ ( model->getType()!=FGAIBase::otMultiplayer &&
model->getType()!=FGAIBase::otStatic ) ) {
+ return ;
+ }
+
+
// find free index in the property tree, if we have
// more than 10000 mp-aircrafts in the property tree we should optimize
the mp-server
for (i = 0; i < 10000; i++) {
--- src/Network/net_fdm.hxx~ 2008-05-25 12:14:16.000000000 +0200
+++ src/Network/net_fdm.hxx 2008-06-18 23:22:44.000000000 +0200
@@ -48,6 +48,7 @@
double latitude; // geodetic (radians)
double altitude; // above sea level (meters)
float agl; // above ground level (meters)
+ float gearagl; // above ground level (meters)
float phi; // roll (radians)
float theta; // pitch (radians)
float psi; // yaw or true heading (radians)
--- src/Network/native_fdm.cxx~ 2008-05-25 12:12:01.000000000 +0200
+++ src/Network/native_fdm.cxx 2008-06-18 23:27:25.000000000 +0200
@@ -225,6 +225,9 @@
net->rotors_tail_blade_position[i] =
node->getDoubleValue("position-deg");
}
// ----------------------------------------------
+ node = fgGetNode("/position",true) ;
+ net->gearagl=node->getDoubleValue("gear-agl-m") ;
+ // ----------------------------------------------
// the following really aren't used in this context
net->cur_time = globals->get_time_params()->get_cur_time();
net->warp = globals->get_warp();
@@ -309,6 +312,8 @@
net->warp = htonl( net->warp );
htonf(net->visibility);
+ htonf(net->gearagl);
+
htonf(net->elevator);
htonf(net->elevator_trim_tab);
htonf(net->left_flap);
@@ -409,6 +414,8 @@
net->warp = ntohl(net->warp);
htonf(net->visibility);
+ htonf(net->gearagl);
+
htonf(net->elevator);
htonf(net->elevator_trim_tab);
htonf(net->left_flap);
@@ -557,6 +564,9 @@
globals->set_warp( net->warp );
last_warp = net->warp;
*/
+ // ----------------------------------------------
+ node = fgGetNode("/position",true) ;
+ node->setDoubleValue("gear-agl-m",net->gearagl) ;
node = fgGetNode("/surface-positions", true);
node->setDoubleValue("elevator-pos-norm", net->elevator);
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Flightgear-devel mailing list
Flightgear-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/flightgear-devel