1 // multiplaytxmgr.cxx -- routines for transmitting multiplayer data
4 // Written by Duncan McCreanor, started February 2003.
5 // duncan.mccreanor@airservicesaustralia.com
7 // Copyright (C) 2003 Airservices Australia
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License as
11 // published by the Free Software Foundation; either version 2 of the
12 // License, or (at your option) any later version.
14 // This program is distributed in the hope that it will be useful, but
15 // WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // General Public License for more details.
19 // You should have received a copy of the GNU General Public License
20 // along with this program; if not, write to the Free Software
21 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 /******************************************************************
27 * Description: The multiplayer tx manager provides is used
28 * to send data to another player or a server for an
29 * interactive multiplayer FlightGear simulation.
31 ******************************************************************/
33 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36 #include <plib/netSocket.h>
38 #include <Main/fg_props.hxx>
39 #include "multiplaytxmgr.hxx"
40 #include "mpmessages.hxx"
41 #include "mpplayer.hxx"
43 // These constants are provided so that the ident command can list file versions.
44 const char sMULTIPLAYTXMGR_BID[] = "$Id$";
45 const char sMULTIPLAYTXMGR_HID[] = MULTIPLAYTXMGR_HID;
49 /******************************************************************
50 * Name: FGMultiplayTxMgr
51 * Description: Constructor.
52 ******************************************************************/
53 FGMultiplayTxMgr::FGMultiplayTxMgr() {
55 int iPlayerCnt; // Count of players in player array
57 // Initialise private members
58 m_bInitialised = false;
64 /******************************************************************
65 * Name: ~FGMultiplayTxMgr
66 * Description: Destructor. Closes and deletes objects owned by
68 ******************************************************************/
69 FGMultiplayTxMgr::~FGMultiplayTxMgr() {
76 /******************************************************************
78 * Description: Initialises multiplayer transmit
79 ******************************************************************/
80 bool FGMultiplayTxMgr::init(void) {
83 string sTxAddress; // Destination address
85 bool bSuccess = true; // Result of initialisation
87 // Initialise object if not already done
88 if (!m_bInitialised) {
90 // Set members from property values
91 string sTxAddress = fgGetString("/sim/multiplay/txhost");
92 iTxPort = fgGetInt("/sim/multiplay/txport");
94 cout << "FGMultiplayTxMgr::init - txaddress= " << sTxAddress << endl;
95 cout << "FGMultiplayTxMgr::init - txport= " << iTxPort << endl;
100 // Create and open tx socket
101 mDataTxSocket = new netSocket();
102 if (!mDataTxSocket->open(false)) {
103 // Failed to open tx socket
104 cerr << "FGMultiplayTxMgr::init - Failed to create data transmit socket" << endl;
107 mDataTxSocket->setBroadcast(true);
108 if (mDataTxSocket->connect(sTxAddress.c_str(), iTxPort) != 0) {
109 // Failed to connect tx socket
110 cerr << "FGMultiplayTxMgr::init - Failed to connect data transmit socket" << endl;
115 // Create a player object for the local player
117 mLocalPlayer = new MPPlayer();
118 if (!mLocalPlayer->Open(fgGetString("/sim/multiplay/rxaddress"), fgGetInt("/sim/multiplay/rxport"),
119 fgGetString("/sim/multiplay/callsign"), fgGetString("/sim/model/path"), true)) {
120 cerr << "FGMultiplayTxMgr::init - Failed to create player object for local player" << endl;
125 // If Tx port == zero then don't initialise
128 cout << "FGMultiplayTxMgr::init - Tx Port is zero. Multiplay out disabled." << endl;
133 // Save manager state
134 m_bInitialised = bSuccess;
137 cerr << "FGMultiplayTxMgr::init - Attempt to init object that is already opened" << endl;
142 /* Return true if init succeeds */
148 /******************************************************************
150 * Description: Closes and deletes the local player object. Closes
151 * and deletes the tx socket. Resets the object state to unitialised.
152 ******************************************************************/
153 void FGMultiplayTxMgr::Close(void) {
156 // Delete local player
164 mDataTxSocket->close();
165 delete mDataTxSocket;
166 mDataTxSocket = NULL;
169 m_bInitialised = false;
174 /******************************************************************
175 * Name: SendMyPosition
176 * Description: Sends the position data for the local position.
177 ******************************************************************/
178 void FGMultiplayTxMgr::SendMyPosition(const sgMat4 PlayerPosMat4) {
181 T_PositionMsg PosMsg;
182 char sMsg[sizeof(T_MsgHdr) + sizeof(T_PositionMsg)];
184 if (m_bInitialised) {
185 mLocalPlayer->SetPosition(PlayerPosMat4);
186 mLocalPlayer->FillPosMsg(&MsgHdr, &PosMsg);
187 memcpy(sMsg, &MsgHdr, sizeof(T_MsgHdr));
188 memcpy(sMsg + sizeof(T_MsgHdr), &PosMsg, sizeof(T_PositionMsg));
189 mDataTxSocket->send(sMsg, sizeof(T_MsgHdr) + sizeof(T_PositionMsg), 0);
197 /******************************************************************
198 * Name: SendTextMessage
199 * Description: Sends a message to the player. The message must
200 * contain a valid and correctly filled out header and optional
202 ******************************************************************/
203 void FGMultiplayTxMgr::SendTextMessage(const string &sMsgText) const {
205 bool bResult = false;
208 int iNextBlockPosition = 0;
209 char sMsg[sizeof(T_MsgHdr) + sizeof(T_ChatMsg)];
211 if (m_bInitialised) {
213 mLocalPlayer->FillMsgHdr(&MsgHdr, CHAT_MSG_ID);
215 // Divide the text string into blocks that fit in the message
216 // and send the blocks.
217 while (iNextBlockPosition < sMsgText.length()) {
218 strncpy(ChatMsg.sText, sMsgText.substr(iNextBlockPosition, MAX_CHAT_MSG_LEN - 1).c_str(), MAX_CHAT_MSG_LEN);
219 ChatMsg.sText[MAX_CHAT_MSG_LEN - 1] = '\0';
220 memcpy(sMsg, &MsgHdr, sizeof(T_MsgHdr));
221 memcpy(sMsg + sizeof(T_MsgHdr), &ChatMsg, sizeof(T_ChatMsg));
222 mDataTxSocket->send(sMsg, sizeof(T_MsgHdr) + sizeof(T_ChatMsg), 0);
223 iNextBlockPosition += MAX_CHAT_MSG_LEN - 1;