From f36f6ae12572a50c45c40c52c95a47098425a89c Mon Sep 17 00:00:00 2001 From: Nathan Date: Thu, 17 Apr 2025 14:16:57 -0500 Subject: [PATCH] work on ClientModule, add ChatServer --- include/utils/App/App.h | 4 +- include/utils/Module/Module.h | 4 +- modules/ClientModule/src/ClientEvents.h | 6 +- modules/ClientModule/src/ClientModule.cpp | 126 +++++++++++++++++- modules/ClientModule/src/ClientModule.h | 42 ++++++ modules/ServerModule/src/ServerEvents.h | 6 +- modules/ServerModule/src/ServerModule.cpp | 80 ++++++----- modules/ServerModule/src/ServerModule.h | 25 +++- modules/Terminal/src/Terminal.cpp | 4 +- modules/WindowModule/src/WindowModule.h | 1 + .../examples/ChatServer/src/ChatServer.cpp | 40 ++++++ modules/examples/ChatServer/src/ChatServer.h | 29 ++++ 12 files changed, 314 insertions(+), 53 deletions(-) create mode 100644 modules/examples/ChatServer/src/ChatServer.cpp create mode 100644 modules/examples/ChatServer/src/ChatServer.h diff --git a/include/utils/App/App.h b/include/utils/App/App.h index 112befc..0c0cc08 100644 --- a/include/utils/App/App.h +++ b/include/utils/App/App.h @@ -60,13 +60,13 @@ namespace Archimedes { unsigned int getEventType(std::string event) { return eventTypes[event]; } - void addEventType(std::string type) { + void registerEvent(std::string type) { //only add each type once if(eventTypes.find(type) == eventTypes.end()) eventTypes[type] = nextEventType++; } - void removeEventType(std::string type) { + void unregisterEvent(std::string type) { //only erase registered types auto it = eventTypes.find(type); if(it != eventTypes.end()) diff --git a/include/utils/Module/Module.h b/include/utils/Module/Module.h index 0561efa..600c63e 100644 --- a/include/utils/Module/Module.h +++ b/include/utils/Module/Module.h @@ -19,13 +19,15 @@ namespace Archimedes { Module(App* a, void* h) : app(a), handle(h) {} + Module() : app(nullptr), handle(nullptr) {} + virtual ~Module() {} virtual void run() {} virtual bool onEvent(const Event& e) { return false; } virtual void onLoad() {}; - std::string getName() const { return name; } + operator std::string() const { return name; } void* getHandle() { return handle; } //std::any getData(std::string s) { return data[s.c_str()]; }; diff --git a/modules/ClientModule/src/ClientEvents.h b/modules/ClientModule/src/ClientEvents.h index 25d44a7..4bc5e55 100644 --- a/modules/ClientModule/src/ClientEvents.h +++ b/modules/ClientModule/src/ClientEvents.h @@ -14,7 +14,7 @@ namespace CMEvent { DataRecievedEvent(ISteamNetworkingMessage* m) : msg(m) {} - operator std::string() const { return "DataRecievedEvent"; } + operator std::string() const { return "CMEvent::DataRecievedEvent"; } ISteamNetworkingMessage* msg; @@ -28,7 +28,7 @@ namespace CMEvent { DataSentEvent(ISteamNetworkingMessage* m) : msg(m) {} - operator std::string() const { return "DataSentEvent"; } + operator std::string() const { return "CMEvent::DataSentEvent"; } ISteamNetworkingMessage* msg; }; @@ -41,7 +41,7 @@ namespace CMEvent { ConnectionStatusChangedEvent(SteamNetConnectionStatusChangedCallback_t* i) : info(i) {} - operator std::string() const { return "ConnectionStatusChangedEvent"; } + operator std::string() const { return "CMEvent::ConnectionStatusChangedEvent"; } SteamNetConnectionStatusChangedCallback_t* info; }; diff --git a/modules/ClientModule/src/ClientModule.cpp b/modules/ClientModule/src/ClientModule.cpp index 740fd62..974810e 100644 --- a/modules/ClientModule/src/ClientModule.cpp +++ b/modules/ClientModule/src/ClientModule.cpp @@ -5,17 +5,137 @@ ClientModule::ClientModule(Archimedes::App* a, void* h) : Archimedes::Module(a, } ClientModule::~ClientModule() { - GameNetworkingSockets_Kill(); + if(app) { + app->unregisterEvent(CMEvent::DataRecievedEvent()); + app->unregisterEvent(CMEvent::DataSentEvent()); + app->unregisterEvent(CMEvent::ConnectionStatusChangedEvent()); + + GameNetworkingSockets_Kill(); + } } void ClientModule::onLoad() { + + app->registerEvent(CMEvent::DataSentEvent()); + app->registerEvent(CMEvent::DataRecievedEvent()); + app->registerEvent(CMEvent::ConnectionStatusChangedEvent()); + SteamDatagramErrMsg errMsg; if ( !GameNetworkingSockets_Init( nullptr, errMsg ) ) { //FatalError( "GameNetworkingSockets_Init failed. %s", errMsg ); std::cerr << "GameNetworkingSockets_Init() Failed: " << errMsg << std::endl; } - //g_logTimeZero = SteamNetworkingUtils()->GetLocalTimestamp(); - //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 ); + //Printf( "Connecting to chat server at %s", szAddr ); + 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("ConnectionStatusChangedEvent")) { + + CMEvent::ConnectionStatusChangedEvent& e = (CMEvent::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; + 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("DataRecievedEvent")) { + return true; + } else if(eventsToHandle & CMEventEnum::DataSent && type == app->getEventType("DataSentEvent")) { + return true; + } + + return false; +} + +void ClientModule::pollIncomingData() { + + while ( running ) + { + 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 CMEvent::DataRecievedEvent(pIncomingMsg)); + } } diff --git a/modules/ClientModule/src/ClientModule.h b/modules/ClientModule/src/ClientModule.h index 03f249a..512ffb5 100644 --- a/modules/ClientModule/src/ClientModule.h +++ b/modules/ClientModule/src/ClientModule.h @@ -3,6 +3,8 @@ #include #include +#include "ClientEvents.h" + class ClientModule : public Archimedes::Module { public: @@ -10,9 +12,49 @@ class ClientModule : public Archimedes::Module { ~ClientModule(); void onLoad(); void run(); + bool onEvent(const Archimedes::Event&); + void startClient(SteamNetworkingIPAddr&); + void stopClient(); + + void sendReliable(const void* data, uint32 byteCount) { + interface->SendMessageToConnection(connection, data, byteCount, k_nSteamNetworkingSend_Reliable, nullptr); + + } + + void pollIncomingData(); + + void shouldHandleEvents(unsigned int events) { eventsToHandle = events; } + + enum CMEventEnum { + None = 0, + ConnectionStatusChanged = 1 << 0, + DataRecieved = 1 << 1, + DataSent = 1 << 2 + }; private: + unsigned int eventsToHandle = CMEventEnum::ConnectionStatusChanged | CMEventEnum::DataSent | CMEventEnum::DataRecieved; + + bool running = false; + + ISteamNetworkingSockets* interface; + HSteamNetConnection connection; + + inline static ClientModule* callbackInstance = nullptr; + + static void SteamNetConnectionStatusChangedCallback( SteamNetConnectionStatusChangedCallback_t *pInfo ) { + callbackInstance->OnSteamNetConnectionStatusChanged( pInfo ); + } + + void OnSteamNetConnectionStatusChanged( SteamNetConnectionStatusChangedCallback_t *pInfo ) { + app->emitEvent(new CMEvent::ConnectionStatusChangedEvent(pInfo)); + } + + void PollConnectionStateChanges() { + callbackInstance = this; + interface->RunCallbacks(); + } }; #ifdef CLIENTMODULE_DYNAMIC diff --git a/modules/ServerModule/src/ServerEvents.h b/modules/ServerModule/src/ServerEvents.h index 99f6307..5fa909c 100644 --- a/modules/ServerModule/src/ServerEvents.h +++ b/modules/ServerModule/src/ServerEvents.h @@ -19,7 +19,7 @@ namespace SMEvent { DataRecievedEvent(ISteamNetworkingMessage* m) : msg(m) {} - operator std::string() const { return "DataRecievedEvent"; } + operator std::string() const { return "SMEvent::DataRecievedEvent"; } ISteamNetworkingMessage* msg; @@ -38,7 +38,7 @@ namespace SMEvent { DataSentEvent(ISteamNetworkingMessage* m) : msg(m) {} - operator std::string() const { return "DataSentEvent"; } + operator std::string() const { return "SMEvent::DataSentEvent"; } ISteamNetworkingMessage* msg; }; @@ -51,7 +51,7 @@ namespace SMEvent { ConnectionStatusChangedEvent(SteamNetConnectionStatusChangedCallback_t* i) : info(i) {} - operator std::string() const { return "ConnectionStatusChangedEvent"; } + operator std::string() const { return "SMEvent::ConnectionStatusChangedEvent"; } SteamNetConnectionStatusChangedCallback_t* info; }; diff --git a/modules/ServerModule/src/ServerModule.cpp b/modules/ServerModule/src/ServerModule.cpp index f539b43..6a7b094 100644 --- a/modules/ServerModule/src/ServerModule.cpp +++ b/modules/ServerModule/src/ServerModule.cpp @@ -5,18 +5,20 @@ ServerModule::ServerModule(Archimedes::App* a, void* h) : Archimedes::Module(a, } ServerModule::~ServerModule() { - app->removeEventType(SMEvent::DataRecievedEvent()); - app->removeEventType(SMEvent::DataSentEvent()); - app->removeEventType(SMEvent::ConnectionStatusChangedEvent()); + if(app) { + app->unregisterEvent(SMEvent::DataRecievedEvent()); + app->unregisterEvent(SMEvent::DataSentEvent()); + app->unregisterEvent(SMEvent::ConnectionStatusChangedEvent()); - GameNetworkingSockets_Kill(); + GameNetworkingSockets_Kill(); + } } void ServerModule::onLoad() { - app->addEventType(SMEvent::DataRecievedEvent()); - app->addEventType(SMEvent::DataSentEvent()); - app->addEventType(SMEvent::ConnectionStatusChangedEvent()); + app->registerEvent(SMEvent::DataRecievedEvent()); + app->registerEvent(SMEvent::DataSentEvent()); + app->registerEvent(SMEvent::ConnectionStatusChangedEvent()); SteamDatagramErrMsg errMsg; @@ -28,26 +30,38 @@ void ServerModule::onLoad() { interface = SteamNetworkingSockets(); - 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; - //Printf( "Server listening on port %d\n", port ); +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; + //Printf( "Server listening on port %d\n", port ); + + running = true; + } +} + +void ServerModule::stopServer() { + running = false; } void ServerModule::run() { if(running) { pollIncomingData(); PollConnectionStateChanges(); - PollLocalUserInput(); } else if(port >= 0) { interface->CloseListenSocket(listenSock); @@ -56,18 +70,16 @@ void ServerModule::run() { interface->DestroyPollGroup(pollGroup); pollGroup = k_HSteamNetPollGroup_Invalid; - app->stopModule(getName()); - port = -1; //just in case + port = -1; } } -void ServerModule::OnSteamNetConnectionStatusChanged( SteamNetConnectionStatusChangedCallback_t *pInfo ) { - app->emitEvent(new SMEvent::ConnectionStatusChangedEvent(pInfo)); -} bool ServerModule::onEvent(const Archimedes::Event& event) { - if(eventsToHandle & SMEventEnum::ConnectionStatusChanged && app->getEventType(event) == app->getEventType("ConnectionStatusChangedEvent")) { + unsigned int type = app->getEventType(event); + + if(eventsToHandle & SMEventEnum::ConnectionStatusChanged && type == app->getEventType("ConnectionStatusChangedEvent")) { SMEvent::ConnectionStatusChangedEvent& e = (SMEvent::ConnectionStatusChangedEvent&) event; @@ -93,18 +105,18 @@ bool ServerModule::onEvent(const Archimedes::Event& event) { // Select appropriate log messages //const char *pszDebugLogAction; - if ( e.info->m_info.m_eState == k_ESteamNetworkingConnectionState_ProblemDetectedLocally ) + /*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 ); + 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() ); - } + 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 @@ -180,9 +192,9 @@ bool ServerModule::onEvent(const Archimedes::Event& event) { } return true; - } else if(eventsToHandle & SMEventEnum::DataRecieved && app->getEventType(event) == app->getEventType("DataRecievedEvent")) { + } else if(eventsToHandle & SMEventEnum::DataRecieved && type == app->getEventType("DataRecievedEvent")) { return true; - } else if(eventsToHandle & SMEventEnum::DataSent && app->getEventType(event) == app->getEventType("DataSentEvent")) { + } else if(eventsToHandle & SMEventEnum::DataSent && type == app->getEventType("DataSentEvent")) { return true; } diff --git a/modules/ServerModule/src/ServerModule.h b/modules/ServerModule/src/ServerModule.h index 4124b9a..e85e4d9 100644 --- a/modules/ServerModule/src/ServerModule.h +++ b/modules/ServerModule/src/ServerModule.h @@ -1,3 +1,6 @@ +#ifndef SERVERMODULE_H +#define SERVERMODULE_H + #include "Archimedes.h" #include @@ -9,6 +12,9 @@ class ServerModule : public Archimedes::Module { public: ServerModule(Archimedes::App*, void*); + + ServerModule() { name = "ServerModule"; } + ~ServerModule(); void onLoad(); bool onEvent(const Archimedes::Event&); @@ -26,7 +32,11 @@ class ServerModule : public Archimedes::Module { void shouldHandleEvents(unsigned int events) { eventsToHandle = events; } - void sendData() {} + void sendReliable(HSteamNetConnection client, const void* data, uint32 byteCount) { + interface->SendMessageToConnection(client, data, byteCount, k_nSteamNetworkingSend_Reliable, nullptr); + + } + void pollIncomingData(); private: @@ -48,16 +58,21 @@ class ServerModule : public Archimedes::Module { callbackInstance->OnSteamNetConnectionStatusChanged( pInfo ); } - void OnSteamNetConnectionStatusChanged( SteamNetConnectionStatusChangedCallback_t *pInfo ); - + void OnSteamNetConnectionStatusChanged( SteamNetConnectionStatusChangedCallback_t *pInfo ) { + app->emitEvent(new SMEvent::ConnectionStatusChangedEvent(pInfo)); + } std::map clients; - void PollConnectionStateChanges(); - void PollLocalUserInput(); + void PollConnectionStateChanges() { + callbackInstance = this; + interface->RunCallbacks(); + } }; #ifdef SERVERMODULE_DYNAMIC #define MODULE_TYPE ServerModule #include "endModule.h" #endif + +#endif diff --git a/modules/Terminal/src/Terminal.cpp b/modules/Terminal/src/Terminal.cpp index ba1eae6..0aefbaf 100644 --- a/modules/Terminal/src/Terminal.cpp +++ b/modules/Terminal/src/Terminal.cpp @@ -13,7 +13,7 @@ Terminal::Terminal(Archimedes::App* a, void* h) : Archimedes::Module(a, h) { name = "Terminal"; ImguiModule* im = new ImguiModule(a, h); - deps[im->getName()] = im; + deps[*im] = im; } Terminal::~Terminal() { @@ -22,7 +22,7 @@ Terminal::~Terminal() { void Terminal::onLoad() { - ImguiModule* im = (ImguiModule*) moduleInstances["ImguiModule"]; + ImguiModule* im = (ImguiModule*) moduleInstances[ImguiModule()]; if(!im) { std::cout << "No ImguiModule for Terminal!\n"; diff --git a/modules/WindowModule/src/WindowModule.h b/modules/WindowModule/src/WindowModule.h index 989b8ae..01166c0 100644 --- a/modules/WindowModule/src/WindowModule.h +++ b/modules/WindowModule/src/WindowModule.h @@ -13,6 +13,7 @@ class WindowModule : public Archimedes::Module { name = "WindowModule"; } + WindowModule() { name = "WindowModule"; } ~WindowModule(); diff --git a/modules/examples/ChatServer/src/ChatServer.cpp b/modules/examples/ChatServer/src/ChatServer.cpp new file mode 100644 index 0000000..b338251 --- /dev/null +++ b/modules/examples/ChatServer/src/ChatServer.cpp @@ -0,0 +1,40 @@ +#include "ChatServer.h" + +//void ChatServer::onLoad() {} + +//void ChatServer::run() {} + +bool ChatServer::onEvent(const Archimedes::Event& event) { + + unsigned int type = app->getEventType(event); + + + /*if(type == app->getEventType("DataSentEvent")) { + //we did this? + return true; + } else */ + + if(type == app->getEventType("DataRecievedEvent")) { + + static ServerModule* sm; { sm = (ServerModule*) moduleInstances[ServerModule()]; } + + SMEvent::DataRecievedEvent& e = (SMEvent::DataRecievedEvent&) event; + + static std::string s; s = std::string((const char*)e.msg->m_pData, e.msg->m_cbSize); + + std::cerr << "Data Recieved: " << s << std::endl; + + static std::string res; res = "Message Recieved: " + s; + + sm->sendReliable(e.msg->m_conn, res.c_str(), res.length()); + + } /*else if(type == app->getEventType("ConnectionStatusChangedEvent")) { + + //SMEvent::ConnectionStatusChangedEvent& e = (SMEvent::ConnectionStatusChangedEvent&) event; + + return false; + + }*/ + + return false; +} diff --git a/modules/examples/ChatServer/src/ChatServer.h b/modules/examples/ChatServer/src/ChatServer.h new file mode 100644 index 0000000..8df1ec0 --- /dev/null +++ b/modules/examples/ChatServer/src/ChatServer.h @@ -0,0 +1,29 @@ +#include "Archimedes.h" + +#include "modules/ServerModule/src/ServerModule.h" + +class ChatServer : public Archimedes::Module { + + public: + + ChatServer(Archimedes::App* a, void* h) : Module(a, h) { + + name = "ChatServer"; + + ServerModule* sm = new ServerModule(a, h); + deps[*sm] = sm; + sm->shouldHandleEvents(ServerModule::SMEventEnum::ConnectionStatusChanged | ServerModule::SMEventEnum::DataSent); + } + + ChatServer() { name = "ChatServer"; } + + ~ChatServer() { + if(app) {} + } + + //void onLoad(); + + //void run(); + + bool onEvent(const Archimedes::Event&); +};