#include "ClientModule.h" ClientModule::ClientModule(Archimedes::App* a, void* h) : Archimedes::Module(a, h) { name = "ClientModule"; } ClientModule::~ClientModule() { if(app) { app->unregisterEvent(Archimedes::DataRecievedEvent()); app->unregisterEvent(Archimedes::DataSentEvent()); app->unregisterEvent(Archimedes::ConnectionStatusChangedEvent()); GameNetworkingSockets_Kill(); } } void ClientModule::onLoad() { app->registerEvent(Archimedes::DataSentEvent()); app->registerEvent(Archimedes::DataRecievedEvent()); app->registerEvent(Archimedes::ConnectionStatusChangedEvent()); SteamDatagramErrMsg errMsg; if ( !GameNetworkingSockets_Init( nullptr, errMsg ) ) { //FatalError( "GameNetworkingSockets_Init failed. %s", errMsg ); std::cerr << "GameNetworkingSockets_Init() Failed: " << errMsg << std::endl; } //SteamNetworkingUtils()->SetDebugOutputFunction( k_ESteamNetworkingSocketsDebugOutputType_Msg, DebugOutput ); interface = SteamNetworkingSockets(); } void ClientModule::startClient(SteamNetworkingIPAddr& serverAddr) { if(!running) { // Start connecting char szAddr[ SteamNetworkingIPAddr::k_cchMaxString ]; serverAddr.ToString( szAddr, sizeof(szAddr), true ); std::cerr << "Connecting to chat server at " << szAddr << std::endl; SteamNetworkingConfigValue_t opt; opt.SetPtr( k_ESteamNetworkingConfig_Callback_ConnectionStatusChanged, (void*)SteamNetConnectionStatusChangedCallback ); connection = interface->ConnectByIPAddress( serverAddr, 1, &opt ); if ( connection == k_HSteamNetConnection_Invalid ) std::cerr << "Failed to create connection\n"; running = true; } } void ClientModule::stopClient() { running = false; } void ClientModule::run() { if(running) { pollIncomingData(); PollConnectionStateChanges(); } } bool ClientModule::onEvent(const Archimedes::Event& event) { unsigned int type = app->getEventType(event); if(eventsToHandle & CMEventEnum::ConnectionStatusChanged && type == app->getEventType(Archimedes::ConnectionStatusChangedEvent())) { Archimedes::ConnectionStatusChangedEvent& e = (Archimedes::ConnectionStatusChangedEvent&) event; switch(e.info->m_info.m_eState) { case k_ESteamNetworkingConnectionState_None: // NOTE: We will get callbacks here when we destroy connections. You can ignore these. break; case k_ESteamNetworkingConnectionState_ClosedByPeer: case k_ESteamNetworkingConnectionState_ProblemDetectedLocally: { // Ignore if they were not previously connected. (If they disconnected // before we accepted the connection.) if ( e.info->m_eOldState == k_ESteamNetworkingConnectionState_Connected ) { } else { assert( e.info->m_eOldState == k_ESteamNetworkingConnectionState_Connecting ); } // Clean up the connection. This is important! // The connection is "closed" in the network sense, but // it has not been destroyed. We must close it on our end, too // to finish up. The reason information do not matter in this case, // and we cannot linger because it's already closed on the other end, // so we just pass 0's. // // OnDisconnect interface->CloseConnection( e.info->m_hConn, 0, nullptr, false ); connection = k_HSteamNetConnection_Invalid; stopClient(); break; } case k_ESteamNetworkingConnectionState_Connecting: { break; } case k_ESteamNetworkingConnectionState_Connected: //OnConnect break; default: // Silences -Wswitch break; } return true; } else if(eventsToHandle & CMEventEnum::DataRecieved && type == app->getEventType(Archimedes::DataRecievedEvent())) { return true; } else if(eventsToHandle & CMEventEnum::DataSent && type == app->getEventType(Archimedes::DataSentEvent())) { return true; } return false; } void ClientModule::pollIncomingData() { while(running && connection != k_HSteamNetConnection_Invalid) { ISteamNetworkingMessage *pIncomingMsg = nullptr; int numMsgs = interface->ReceiveMessagesOnConnection( connection, &pIncomingMsg, 1 ); if ( numMsgs == 0 ) break; if ( numMsgs < 0 ) std::cerr << "Error checking for messages" << std::endl; assert( numMsgs == 1 && pIncomingMsg ); assert( pIncomingMsg->m_conn == connection ); app->emitEvent(new Archimedes::DataRecievedEvent(pIncomingMsg)); } }