This commit is contained in:
2025-05-12 00:14:11 -05:00
parent ec4b85587b
commit 700e422270
14 changed files with 70 additions and 71 deletions

View File

@@ -0,0 +1,223 @@
#include "ServerModule.h"
ServerModule::ServerModule(Archimedes::App* a, void* h) : Archimedes::Module(a, h) {
name = "ServerModule";
}
ServerModule::~ServerModule() {
if(app) {
app->unregisterEvent(Archimedes::DataRecievedEvent());
app->unregisterEvent(Archimedes::DataSentEvent());
app->unregisterEvent(Archimedes::ConnectionStatusChangedEvent());
GameNetworkingSockets_Kill();
}
}
void ServerModule::onLoad() {
app->registerEvent(Archimedes::DataRecievedEvent());
app->registerEvent(Archimedes::DataSentEvent());
app->registerEvent(Archimedes::ConnectionStatusChangedEvent());
SteamDatagramErrMsg errMsg;
if ( !GameNetworkingSockets_Init( nullptr, errMsg ) ) {
std::cerr << "GameNetworkingSockets_Init() Failed: " << errMsg << std::endl;
}
//SteamNetworkingUtils()->SetDebugOutputFunction( k_ESteamNetworkingSocketsDebugOutputType_Msg, DebugOutput );
interface = SteamNetworkingSockets();
}
void ServerModule::startServer(int p) {
if(!running) {
port = p;
SteamNetworkingIPAddr serverLocalAddr;
serverLocalAddr.Clear();
serverLocalAddr.m_port = port;
SteamNetworkingConfigValue_t opt;
opt.SetPtr(k_ESteamNetworkingConfig_Callback_ConnectionStatusChanged, (void*)SteamNetConnectionStatusChangedCallback);
listenSock = interface->CreateListenSocketIP( serverLocalAddr, 1, &opt );
if ( listenSock == k_HSteamListenSocket_Invalid )
std::cerr << "Failed to listen on port " << port << std::endl;
pollGroup = interface->CreatePollGroup();
if ( pollGroup == k_HSteamNetPollGroup_Invalid )
std::cerr << "Failed to listen on port " << port << std::endl;
std::cerr << "Server listening on port " << port << std::endl;
running = true;
}
}
void ServerModule::stopServer() {
disconnectAllClients();
running = false;
}
void ServerModule::run() {
if(running) {
pollIncomingData();
PollConnectionStateChanges();
} else if(port >= 0) {
interface->CloseListenSocket(listenSock);
listenSock = k_HSteamListenSocket_Invalid;
interface->DestroyPollGroup(pollGroup);
pollGroup = k_HSteamNetPollGroup_Invalid;
port = -1;
}
}
bool ServerModule::onEvent(const Archimedes::Event& event) {
unsigned int type = app->getEventType(event);
if(eventsToHandle & SMEventEnum::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 )
{
// Locate the client. Note that it should have been found, because this
// is the only codepath where we remove clients (except on shutdown),
// and connection change callbacks are dispatched in queue order.
auto itClient = clients.find( e.info->m_hConn );
assert( itClient != clients.end() );
// Select appropriate log messages
//const char *pszDebugLogAction;
/*if ( e.info->m_info.m_eState == k_ESteamNetworkingConnectionState_ProblemDetectedLocally )
{
pszDebugLogAction = "problem detected locally";
sprintf( temp, "Alas, %s hath fallen into shadow. (%s)", itClient->second.name.c_str(), e.info->m_info.m_szEndDebug );
}
else
{
// Note that here we could check the reason code to see if
// it was a "usual" connection or an "unusual" one.
pszDebugLogAction = "closed by peer"; (void)pszDebugLogAction;
sprintf( temp, "%s hath departed", itClient->second.name.c_str() );
}*/
// Spew something to our own log. Note that because we put their nick
// as the connection description, it will show up, along with their
// transport-specific data (e.g. their IP address)
/*Printf( "Connection %s %s, reason %d: %s\n",
e.info->m_info.m_szConnectionDescription,
pszDebugLogAction,
e.info->m_info.m_eEndReason,
e.info->m_info.m_szEndDebug
);*/
clients.erase( itClient );
// Send a message so everybody else knows what happened
//SendStringToAllClients( temp );
}
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.
interface->CloseConnection( e.info->m_hConn, 0, nullptr, false );
std::cerr << "Connection Closed.\n";
break;
}
case k_ESteamNetworkingConnectionState_Connecting:
{
// This must be a new connection
assert( clients.find( e.info->m_hConn ) == clients.end() );
//Printf( "Connection request from %s", e.info->m_info.m_szConnectionDescription );
// A client is attempting to connect
// Try to accept the connection.
if ( interface->AcceptConnection( e.info->m_hConn ) != k_EResultOK )
{
// This could fail. If the remote host tried to connect, but then
// disconnected, the connection may already be half closed. Just
// destroy whatever we have on our side.
interface->CloseConnection( e.info->m_hConn, 0, nullptr, false );
//Printf( "Can't accept connection. (It was already closed?)" );
break;
}
std::cerr << "Connection Accepted!\n";
// Assign the poll group
if ( !interface->SetConnectionPollGroup( e.info->m_hConn, pollGroup ) )
{
interface->CloseConnection( e.info->m_hConn, 0, nullptr, false );
//Printf( "Failed to set poll group?" );
break;
}
// Add them to the client list, using std::map wacky syntax
clients[ e.info->m_hConn ] = ++numClients;
//SetClientNick( e.info->m_hConn, nick );
break;
}
case k_ESteamNetworkingConnectionState_Connected:
// We will get a callback immediately after accepting the connection.
// Since we are the server, we can ignore this, it's not news to us.
break;
default:
// Silences -Wswitch
break;
}
return true;
} else if(eventsToHandle & SMEventEnum::DataRecieved && type == app->getEventType(Archimedes::DataRecievedEvent())) {
return true;
} else if(eventsToHandle & SMEventEnum::DataSent && type == app->getEventType(Archimedes::DataSentEvent())) {
return true;
}
return false;
}
void ServerModule::pollIncomingData() {
while ( running )
{
ISteamNetworkingMessage *pIncomingMsg = nullptr;
int numMsgs = interface->ReceiveMessagesOnPollGroup( pollGroup, &pIncomingMsg, 1 );
if ( numMsgs == 0 )
break;
if ( numMsgs < 0 )
std::cerr << "Error checking for messages" << std::endl;
assert( numMsgs == 1 && pIncomingMsg );
auto itClient = clients.find( pIncomingMsg->m_conn );
assert( itClient != clients.end() );
app->emitEvent(new Archimedes::DataRecievedEvent(pIncomingMsg));
}
}