flake parts

This commit is contained in:
2026-02-14 13:12:52 -06:00
parent f9f311c82b
commit 874de65dba
75 changed files with 495 additions and 341 deletions

View File

@@ -0,0 +1,355 @@
#include "Calculator.h"
#include "modules/ImguiModule/ImguiModule.h"
#include <sstream>
#include <cmath>
Calculator::Calculator(Archimedes::App* a, void* h) : Archimedes::Module(a, h) {
name = "Calculator";
ImguiModule* im = new ImguiModule(a, h);
deps[*im] = im;
}
Calculator::~Calculator() {
if(app) {
ImguiModule* im; { im = (ImguiModule*) moduleInstances[ImguiModule()]; }
im->releaseContext(ImGui::GetCurrentContext());
}
}
void Calculator::onLoad() {
ImguiModule* im; { im = (ImguiModule*) moduleInstances[ImguiModule()]; }
if(!im) {
std::cout << "No ImguiModule for Calculator!\n";
std::abort();
}
ImGui::SetCurrentContext(im->aquireContext());
}
void Calculator::run() {
if(open) {
basicCalculator();
} else {
app->emitEvent(new Archimedes::DoUnloadModuleEvent(name));
}
}
void Calculator::index(std::string equation, std::unordered_map<unsigned int, std::string>& nodes) {
unsigned int idx = 0;
nodes.clear();
const static std::string operators[] = {
"(",
")",
"^",
"*",
"/",
"+",
"-"
};
for(const std::string& s : operators) {
while(equation.find(s, idx) != std::string::npos) {
int next = equation.find(s, idx);
nodes[next] = equation.substr(next, s.length());
idx = next + s.length();
}
idx = 0;
}
// -3+8*6-(8+4)^9/5
for(unsigned int i = 0; i < equation.length(); i++) {
static unsigned int begin = 0, end = 0;
if(nodes.find(i) == nodes.end()) {
if(nodes.find(i - 1) != nodes.end() || i == 0) {
//first digit of expression
begin = i;
}
if(nodes.find(i + 1) != nodes.end() || i == equation.length() - 1) {
//character after last digit of expression
end = i + 1;
nodes[begin] = equation.substr(begin, end - begin);
nodes[end - 1] = equation.substr(begin, end - begin);
}
}
}
}
double Calculator::evaluate(std::string equation, std::unordered_map<char, std::string>& evalStr) {
char op = '^';
while(equation.find(op) == std::string::npos) {
switch(op) {
case '^':
op = '*';
break;
case '*':
op = '/';
break;
case '/':
op = '+';
break;
case '+':
op = '-';
break;
case '-':
//no operator
if(evalStr.find(equation.front()) != evalStr.end()) {
return evaluate(evalStr[equation.front()], evalStr);
} else {
return std::stod(equation);
}
break;
default:
break;
}
}
//op is now the appropriate operator
//if either term is a placeholder, evaluate and substitute.
double a, b;
if(evalStr.find(equation.front()) != evalStr.end()) {
a = evaluate(evalStr[equation.front()], evalStr);
} else {
if(equation.find(op) == 0 && op == '-') {
a = 0;
} else {
a = std::stod(equation.substr(0, equation.find(op)));
}
}
if(evalStr.find(equation.back()) != evalStr.end()) {
b = evaluate(evalStr[equation.back()], evalStr);
} else {
b = std::stod(equation.substr(equation.find(op) + 1));
}
switch(op) {
case '^':
return pow(a, b);
case '*':
return a * b;
case '/':
return a / b;
case '+':
return a + b;
case '-':
return a - b;
default:
break;
}
return 0;
}
std::string Calculator::calculate(std::string equation) {
//PEMDAS
while(equation.find(' ') != std::string::npos) {
equation.erase(equation.find(' '), 1);
}
while(equation.find('\t') != std::string::npos) {
equation.erase(equation.find('\t'), 1);
}
while(equation.find('\n') != std::string::npos) {
equation.erase(equation.find('\n'), 1);
}
std::unordered_map<unsigned int, std::string> nodes;
std::unordered_map<char, std::string> evalStr;
std::string eval = "a";
unsigned int idx = 0;
index(equation, nodes);
idx = 0;
// ()
while(equation.find(')', idx) != std::string::npos) {
int end = equation.find(')');
int begin = equation.rfind('(', end);
evalStr[eval.front()] = calculate(equation.substr(begin + 1, (end - begin) - 1));
equation.replace(begin, (end - begin) + 1, eval);
eval.front()++;
idx = end + 1;
}
idx = 0;
index(equation, nodes);
// ^
while(equation.find('^', idx) != std::string::npos) {
int mid = equation.find('^');
int begin = equation.find(nodes[mid - 1] + nodes[mid]);
int end = equation.find(nodes[mid] + nodes[mid + 1], begin) + (nodes[mid] + nodes[mid + 1]).length();
evalStr[eval.front()] = equation.substr(begin, end - begin);
equation.replace(begin, end - begin, eval);
eval.front()++;
idx = end + 1;
}
idx = 0;
index(equation, nodes);
// * or /
while(equation.find('*', idx) != std::string::npos || equation.find('/', idx) != std::string::npos) {
if(equation.find('*', idx) < equation.find('/', idx) && equation.find('*', idx) != std::string::npos) {
int mid = equation.find('*');
int begin = equation.find(nodes[mid - 1] + nodes[mid]);
int end = equation.find(nodes[mid] + nodes[mid + 1], begin) + (nodes[mid] + nodes[mid + 1]).length();
evalStr[eval.front()] = equation.substr(begin, end - begin);
equation.replace(begin, end - begin, eval);
eval.front()++;
idx = end + 1;
} else if(equation.find('/', idx) != std::string::npos) {
int mid = equation.find('/');
int begin = equation.find(nodes[mid - 1] + nodes[mid]);
int end = equation.find(nodes[mid] + nodes[mid + 1], begin) + (nodes[mid] + nodes[mid + 1]).length();
evalStr[eval.front()] = equation.substr(begin, end - begin);
equation.replace(begin, end - begin, eval);
eval.front()++;
idx = end + 1;
}
}
idx = 0;
index(equation, nodes);
// + or -
while(equation.find('+', idx) != std::string::npos || equation.find('-', idx) != std::string::npos) {
if(equation.find('+', idx) < equation.find('-', idx) && equation.find('+', idx) != std::string::npos) {
int mid = equation.find('+');
int begin = equation.find(nodes[mid - 1] + nodes[mid]);
int end = equation.find(nodes[mid] + nodes[mid + 1], begin) + (nodes[mid] + nodes[mid + 1]).length();
evalStr[eval.front()] = equation.substr(begin, end - begin);
equation.replace(begin, end - begin, eval);
eval.front()++;
idx = end + 1;
} else if(equation.find('-', idx) != std::string::npos) {
int mid = equation.find('-');
int begin = mid;
if(nodes.find(mid - 1) != nodes.end()) {
begin = equation.find(nodes[mid - 1] + nodes[mid]);
}
int end = equation.find(nodes[mid] + nodes[mid + 1], begin) + (nodes[mid] + nodes[mid + 1]).length();
evalStr[eval.front()] = equation.substr(begin, end - begin);
equation.replace(begin, end - begin, eval);
eval.front()++;
idx = end + 1;
}
}
return std::to_string(evaluate(equation, evalStr));
}
void Calculator::basicCalculator() {
static bool b = true;
static std::string s;
if(b) {
ImGui::Begin("Basic Calculator", &open);
ImGui::Text("%s", s.c_str());
ImGui::BeginGroup();
{
if(ImGui::Button("AC")) {
s.clear();
}
ImGui::SameLine();
if(ImGui::Button("(")) {
s += " ( ";
}
ImGui::SameLine();
if(ImGui::Button(")")) {
s += " ) ";
}
ImGui::SameLine();
if(ImGui::Button("^")) {
s += " ^ ";
}
ImGui::SameLine();
if(ImGui::Button("=")) {
s = calculate(s);
}
}
ImGui::EndGroup();
ImGui::BeginGroup();
{
for(int i = 1; i < 4; i++) {
ImGui::BeginGroup();
for(int j = 6; j >= 0; j -= 3) {
if(ImGui::Button(std::to_string(i + j).c_str())) {
s += std::to_string(i + j);
}
}
ImGui::EndGroup();
if(i < 3) {
ImGui::SameLine();
}
}
if(ImGui::Button("0")) {
s += "0";
}
ImGui::SameLine();
if(ImGui::Button(".")) {
s += ".";
}
ImGui::SameLine();
if(ImGui::Button("del")) {
if(!s.empty()) {
if(s.back() == ' ') {
s.pop_back();
if(s.back() == '(' || s.back() == ')') {
parenthesis = !parenthesis;
}
s.pop_back();
s.pop_back();
} else {
s.pop_back();
}
}
}
}
ImGui::EndGroup();
ImGui::SameLine();
ImGui::BeginGroup();
if(ImGui::Button("+")) {
s += " + ";
}
if(ImGui::Button("-")) {
s += " - ";
}
if(ImGui::Button("*")) {
s += " * ";
}
if(ImGui::Button("/")) {
s += " / ";
}
ImGui::EndGroup();
ImGui::End();
}
}
void Calculator::graphingCalculator() {
}

View File

@@ -0,0 +1,35 @@
#include "Archimedes.h"
class Calculator : public Archimedes::Module {
public:
Calculator(Archimedes::App*, void*);
Calculator() { name = "Calculator"; }
~Calculator();
void onLoad();
void run();
private:
bool open = true;
bool parenthesis = true;
//bool graphing = false;
void basicCalculator();
std::string calculate(std::string);
double evaluate(std::string, std::unordered_map<char, std::string>&);
void index(std::string, std::unordered_map<unsigned int, std::string>&);
void graphingCalculator();
};
#ifdef CALCULATOR_DYNAMIC
typedef Calculator mtype;
#include "endModule.h"
#endif

View File

@@ -0,0 +1,129 @@
#include "modules/ImguiModule/ImguiModule.h"
#include "modules/ClientModule/ClientModule.h"
#include "ChatClient.h"
ChatClient::ChatClient(Archimedes::App* a, void* h) : Module(a, h) {
name = "ChatClient";
ClientModule* cm = new ClientModule(a, h);
deps[*cm] = cm;
cm->shouldHandleEvents(ClientModule::CMEventEnum::ConnectionStatusChanged | ClientModule::CMEventEnum::DataSent);
ImguiModule* im = new ImguiModule(a, h);
deps[*im] = im;
}
ChatClient::~ChatClient() {
if(app) {
ImguiModule* im; { im = (ImguiModule*) moduleInstances[ImguiModule()]; }
im->releaseContext(ImGui::GetCurrentContext());
}
}
void ChatClient::onLoad() {
ImguiModule* im; { im = (ImguiModule*) moduleInstances[ImguiModule()]; }
if(!im) {
std::cout << "No ImguiModule for ChatClient!\n";
std::abort();
}
ImGui::SetCurrentContext(im->aquireContext());
ClientModule* cm; { cm = (ClientModule*) moduleInstances[ClientModule()]; }
if(!cm) {
std::cout << "No ClientModule for ChatClient!\n";
std::abort();
}
}
void ChatClient::run() {
static ClientModule* cm; { cm = (ClientModule*) moduleInstances[ClientModule()]; }
if(!cm) {
std::cout << "No ClientModule for ChatClient!\n";
std::abort();
}
if(open) {
static std::string s, addr = "127.0.0.1:9932";
ImGui::Begin("ChatClient Module", &open);
ImGui::InputText("Server Address: ", &addr);
if(cm->isRunning() && cm->isConnected()) {
if(ImGui::Button("Disconnect") && cm->isRunning()) {
cm->stopClient();
}
} else {
if(ImGui::Button("Connect") && !cm->isRunning()) {
static SteamNetworkingIPAddr serverAddr;
serverAddr.ParseString(addr.c_str());
cm->startClient(serverAddr);
}
}
ImGui::Text("%s", messages.c_str());
ImGui::InputText("Message: ", &s);
ImGui::SameLine();
if(ImGui::Button("send")) {
cm->sendReliable(s.c_str(), (uint32) s.length());
}
ImGui::End();
} else {
app->emitEvent(new Archimedes::DoUnloadModuleEvent(*cm));
}
}
bool ChatClient::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(Archimedes::DataRecievedEvent())) {
Archimedes::DataRecievedEvent& e = (Archimedes::DataRecievedEvent&) event;
static std::string s; s = std::string((const char*)e.msg->m_pData, e.msg->m_cbSize);
std::cerr << "Client Recieved: " << s << std::endl;
messages += "\n\n" + s;
return true;
}
/*else if(type == app->getEventType("ConnectionStatusChangedEvent")) {
//Archimedes::ConnectionStatusChangedEvent& e = (Archimedes::ConnectionStatusChangedEvent&) event;
return false;
}*/
return false;
}

View File

@@ -0,0 +1,28 @@
#include "Archimedes.h"
class ChatClient : public Archimedes::Module {
public:
ChatClient(Archimedes::App* a, void* h);
ChatClient() { name = "ChatClient"; }
~ChatClient();
void onLoad() override;
void run() override;
bool onEvent(const Archimedes::Event&) override;
private:
std::string messages = "";
bool open = true;
};
#ifdef CHATCLIENT_DYNAMIC
typedef ChatClient mtype;
#include "endModule.h"
#endif

View File

@@ -0,0 +1,56 @@
#include "ChatServer.h"
void ChatServer::onLoad() {
ServerModule* sm = (ServerModule*) moduleInstances[ServerModule()];
sm->startServer(9932);
}
//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(Archimedes::DataRecievedEvent())) {
static ServerModule* sm; { sm = (ServerModule*) moduleInstances[ServerModule()]; }
Archimedes::DataRecievedEvent& e = (Archimedes::DataRecievedEvent&) event;
static std::string s; s = std::string((const char*)e.msg->m_pData, e.msg->m_cbSize);
if(s == "/quit") {
sm->disconnectClient(e.msg->m_conn);
} else if(s == "/shutdown") {
sm->stopServer();
app->end();
}
std::cerr << "Server Recieved: " << s << std::endl;
for(auto& it : sm->getClients()) {
if(it.first != e.msg->m_conn)
sm->sendReliable(it.first, s.c_str(), s.length());
else
sm->sendReliable(e.msg->m_conn, "\nMessage sent\n", strlen("\nMessage sent\n"));
}
return true;
} /*else if(type == app->getEventType("ConnectionStatusChangedEvent")) {
//Archimedes::ConnectionStatusChangedEvent& e = (Archimedes::ConnectionStatusChangedEvent&) event;
return false;
}*/
return false;
}

View File

@@ -0,0 +1,34 @@
#include "Archimedes.h"
#include "modules/ServerModule/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&);
};
#ifdef CHATSERVER_DYNAMIC
typedef ChatServer mtype;
#include "endModule.h"
#endif

View File

@@ -0,0 +1,276 @@
#include "modules/ImguiModule/ImguiModule.h"
#include "modules/ClientModule/ClientModule.h"
#include "ChatClientVoice.h"
ChatClientVoice::ChatClientVoice(Archimedes::App* a, void* h) : Module(a, h) {
name = "ChatClientVoice";
ClientModule* cm = new ClientModule(a, h);
deps[*cm] = cm;
cm->shouldHandleEvents(ClientModule::CMEventEnum::ConnectionStatusChanged | ClientModule::CMEventEnum::DataSent);
ImguiModule* im = new ImguiModule(a, h);
deps[*im] = im;
}
ChatClientVoice::~ChatClientVoice() {
if(app) {
ImguiModule* im; { im = (ImguiModule*) moduleInstances[ImguiModule()]; }
im->releaseContext(ImGui::GetCurrentContext());
//if(buf)
// delete [] buf;
}
}
void ChatClientVoice::onLoad() {
ImguiModule* im; { im = (ImguiModule*) moduleInstances[ImguiModule()]; }
if(!im) {
std::cout << "No ImguiModule for ChatClientVoice!\n";
std::abort();
}
ImGui::SetCurrentContext(im->aquireContext());
ClientModule* cm; { cm = (ClientModule*) moduleInstances[ClientModule()]; }
if(!cm) {
std::cout << "No ClientModule for ChatClientVoice!\n";
std::abort();
}
if(!SDL_Init(SDL_INIT_AUDIO)) {
std::cout << "Audio init failed!\n";
std::abort();
}
mic = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_RECORDING, NULL, NULL, NULL);
SDL_GetAudioStreamFormat(mic, &spec, NULL);
speaker = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec, NULL, NULL);
//buf = new unsigned char[len];
}
void ChatClientVoice::run() {
static ClientModule* cm; { cm = (ClientModule*) moduleInstances[ClientModule()]; }
static unsigned char buf[10 * 1024];
if(!cm) {
std::cout << "No ClientModule for ChatClientVoice!\n";
std::abort();
}
if(open) {
static std::string s, addr = "127.0.0.1:9932";
ImGui::Begin("ChatClientVoice Module", &open);
ImGui::InputText("Server Address: ", &addr);
if(cm->isRunning() && cm->isConnected()) {
if(ImGui::Button("Disconnect") && cm->isRunning()) {
cm->sendReliable("srvcmd1", strlen("srvcmd1"));
//cm->stopClient();
}
} else {
if(ImGui::Button("Connect") && !cm->isRunning()) {
static SteamNetworkingIPAddr serverAddr;
serverAddr.ParseString(addr.c_str());
cm->startClient(serverAddr);
}
}
ImGui::Text("%s", messages.c_str());
ImGui::InputText("Message: ", &s);
if(cm->isConnected()) {
ImGui::SameLine();
if(ImGui::Button("send")) {
if(s == "/quit") {
cm->sendReliable("srvcmd1", strlen("srvcmd1"));
cm->stopClient();
} else if(s == "/shutdown") {
cm->sendReliable("srvcmd2", strlen("srvcmd2"));
//cm->stopClient();
} else {
s.insert(0, "client");
cm->sendReliable(s.c_str(), (uint32) s.length());
}
s.clear();
}
}
static float micVol = 1.0f;
static float speakerVol = 1.0f;
static bool micTest = false;
ImGui::SliderFloat("Mic Volume", &micVol, 0.0f, 1.0f);
ImGui::SliderFloat("Speaker Volume", &speakerVol, 0.0f, 1.0f);
ImGui::Checkbox("Mic test", &micTest);
if(!SDL_AudioStreamDevicePaused(mic)) {
SDL_SetAudioStreamGain(mic, micVol);
} else if(micTest) {
SDL_ClearAudioStream(mic);
SDL_ResumeAudioStreamDevice(mic);
SDL_SetAudioStreamGain(mic, micVol);
}
if(!SDL_AudioStreamDevicePaused(speaker)) {
SDL_SetAudioStreamGain(speaker, speakerVol);
} else if(micTest) {
SDL_ClearAudioStream(speaker);
SDL_ResumeAudioStreamDevice(speaker);
SDL_SetAudioStreamGain(speaker, speakerVol);
}
static int avail = 0;
if(micTest) {
avail = SDL_min(len, SDL_GetAudioStreamAvailable(mic));
if(avail > 10) {
avail = SDL_GetAudioStreamData(mic, buf, avail);
SDL_PutAudioStreamData(speaker, buf, avail);
}
} else if(cm->isConnected()){
// if not testing, send to server.
avail = SDL_min(len, SDL_GetAudioStreamAvailable(mic));
if(avail > 10) {
avail = SDL_GetAudioStreamData(mic, buf, avail);
cm->sendReliable(buf, avail);
}
}
ImGui::End();
} else {
app->emitEvent(new Archimedes::DoUnloadModuleEvent(*cm));
}
}
bool ChatClientVoice::onEvent(const Archimedes::Event& event) {
unsigned int type = app->getEventType(event);
static ClientModule* cm;
/*if(type == app->getEventType("DataSentEvent")) {
//we did this?
return true;
} else */
if(type == app->getEventType(Archimedes::DataRecievedEvent())) {
Archimedes::DataRecievedEvent& e = (Archimedes::DataRecievedEvent&) event;
{ cm = (ClientModule*) moduleInstances[ClientModule()]; }
static std::string s;
if(std::string((const char*)e.msg->m_pData, 6) == "client") {
s = std::string((const char*)e.msg->m_pData + 6, e.msg->m_cbSize - 6);
messages += "\n\n" + s;
} else if(std::string((const char*)e.msg->m_pData, 6) == "server") {
s = std::string((const char*)e.msg->m_pData + 6, e.msg->m_cbSize - 6);
int serverCode = stoi(s);
switch(serverCode) {
case 0:
//start voice
SDL_ClearAudioStream(mic);
SDL_ClearAudioStream(speaker);
SDL_ResumeAudioStreamDevice(mic);
SDL_ResumeAudioStreamDevice(speaker);
break;
case 1:
//stop voice and clear
SDL_PauseAudioStreamDevice(mic);
SDL_PauseAudioStreamDevice(speaker);
SDL_ClearAudioStream(mic);
SDL_ClearAudioStream(speaker);
break;
case 2:
//disconnect
cm->stopClient();
break;
default:
break;
}
} else /*if(std::string((const char*)e.msg->m_pData, 6) == "audio:")*/ {
s = "audio data";
SDL_PutAudioStreamData(speaker, e.msg->m_pData, e.msg->m_cbSize);
}
//std::cerr << "Client Recieved: " << s << std::endl;
return true;
} else if(type == app->getEventType("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:
{
SDL_PauseAudioStreamDevice(mic);
SDL_PauseAudioStreamDevice(speaker);
SDL_ClearAudioStream(mic);
SDL_ClearAudioStream(speaker);
break;
}
case k_ESteamNetworkingConnectionState_Connecting:
{
break;
}
case k_ESteamNetworkingConnectionState_Connected:
//OnConnect
break;
default:
// Silences -Wswitch
break;
}
return false;
}
return false;
}

View File

@@ -0,0 +1,36 @@
#include "Archimedes.h"
#include <SDL3/SDL.h>
#include <SDL3/SDL_audio.h>
class ChatClientVoice : public Archimedes::Module {
public:
ChatClientVoice(Archimedes::App* a, void* h);
ChatClientVoice() { name = "ChatClientVoice"; }
~ChatClientVoice();
void onLoad() override;
void run() override;
bool onEvent(const Archimedes::Event&) override;
private:
std::string messages = "";
bool open = true;
SDL_AudioSpec spec;
SDL_AudioStream *mic, *speaker;
const int len = 10 * 1024;
};
#ifdef CHATCLIENTVOICE_DYNAMIC
typedef ChatClientVoice mtype;
#include "endModule.h"
#endif

View File

@@ -0,0 +1,131 @@
#include "ChatServerVoice.h"
void ChatServerVoice::onLoad() {
ServerModule* sm = (ServerModule*) moduleInstances[ServerModule()];
sm->startServer(9932);
}
//void ChatServerVoice::run() {}
bool ChatServerVoice::onEvent(const Archimedes::Event& event) {
unsigned int type = app->getEventType(event);
static ServerModule* sm;
/*if(type == app->getEventType("DataSentEvent")) {
//we did this?
return true;
} else */
if(type == app->getEventType(Archimedes::DataRecievedEvent())) {
{ sm = (ServerModule*) moduleInstances[ServerModule()]; }
Archimedes::DataRecievedEvent& e = (Archimedes::DataRecievedEvent&) event;
static std::string s;
if(std::string((const char*)e.msg->m_pData, 6) == "client") {
s = std::string((const char*)e.msg->m_pData + 6, e.msg->m_cbSize - 6);
for(auto& it : sm->getClients()) {
if(it.first != e.msg->m_conn)
sm->sendReliable(it.first, e.msg->m_pData, e.msg->m_cbSize);
else
sm->sendReliable(e.msg->m_conn, "client\nMessage sent\n", strlen("client\nMessage sent\n"));
}
} else if(std::string((const char*)e.msg->m_pData, 6) == "srvcmd") {
s = std::string((const char*)e.msg->m_pData + 6, e.msg->m_cbSize - 6);
int cmdCode = stoi(s);
switch(cmdCode) {
case 0:
break;
case 1:
//disconnect
sm->disconnectClient(e.msg->m_conn);
break;
case 2:
for(auto& it : sm->getClients()) {
sm->sendReliable(it.first, "server2", strlen("server2"));
}
sm->stopServer();
app->end();
break;
default:
break;
}
} else /*if(std::string((const char*)e.msg->m_pData, 6) == "audio:")*/ {
s = "audio data";
for(auto& it : sm->getClients()) {
if(it.first != e.msg->m_conn)
sm->sendReliable(it.first, e.msg->m_pData, e.msg->m_cbSize);
}
}
//std::cerr << "Server Recieved: " << s << std::endl;
return true;
} else if(type == app->getEventType("ConnectionStatusChangedEvent")) {
Archimedes::ConnectionStatusChangedEvent& e = (Archimedes::ConnectionStatusChangedEvent&) event;
{ sm = (ServerModule*) moduleInstances[ServerModule()]; }
unsigned int numClients;
(void)sm->getClients(&numClients);
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:
{
if(numClients < 2) {
for(auto& it : sm->getClients()) {
sm->sendReliable(it.first, "server1", strlen("server1"));
}
}
break;
}
case k_ESteamNetworkingConnectionState_Connecting:
{
break;
}
case k_ESteamNetworkingConnectionState_Connected:
//OnConnect
if(numClients == 2) {
for(auto& it : sm->getClients()) {
sm->sendReliable(it.first, "server0", strlen("server0"));
}
} else if(numClients > 2) {
sm->sendReliable(e.info->m_hConn, "server0", strlen("server0"));
}
break;
default:
// Silences -Wswitch
break;
}
return false;
}
return false;
}

View File

@@ -0,0 +1,34 @@
#include "Archimedes.h"
#include "modules/ServerModule/ServerModule.h"
class ChatServerVoice : public Archimedes::Module {
public:
ChatServerVoice(Archimedes::App* a, void* h) : Module(a, h) {
name = "ChatServerVoice";
ServerModule* sm = new ServerModule(a, h);
deps[*sm] = sm;
sm->shouldHandleEvents(ServerModule::SMEventEnum::ConnectionStatusChanged | ServerModule::SMEventEnum::DataSent);
}
ChatServerVoice() { name = "ChatServerVoice"; }
~ChatServerVoice() {
if(app) {}
}
void onLoad();
//void run();
bool onEvent(const Archimedes::Event&);
};
#ifdef CHATSERVERVOICE_DYNAMIC
typedef ChatServerVoice mtype;
#include "endModule.h"
#endif

View File

@@ -0,0 +1,46 @@
#include "ChessServer.h"
void ChessServer::onLoad() {
ServerModule* sm = (ServerModule*) moduleInstances[ServerModule()];
sm->startServer(9932);
}
//void ChessServer::run() {}
bool ChessServer::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(Archimedes::DataRecievedEvent())) {
static ServerModule* sm; { sm = (ServerModule*) moduleInstances[ServerModule()]; }
Archimedes::DataRecievedEvent& e = (Archimedes::DataRecievedEvent&) event;
static std::string s; s = std::string((const char*)e.msg->m_pData, e.msg->m_cbSize);
for(auto& it : sm->getClients()) {
if(it.first != e.msg->m_conn)
sm->sendReliable(it.first, s.c_str(), s.length());
}
return true;
} /*else if(type == app->getEventType("ConnectionStatusChangedEvent")) {
//Archimedes::ConnectionStatusChangedEvent& e = (Archimedes::ConnectionStatusChangedEvent&) event;
return false;
}*/
return false;
}

View File

@@ -0,0 +1,34 @@
#include "Archimedes.h"
#include "modules/ServerModule/ServerModule.h"
class ChessServer : public Archimedes::Module {
public:
ChessServer(Archimedes::App* a, void* h) : Module(a, h) {
name = "ChessServer";
ServerModule* sm = new ServerModule(a, h);
deps[*sm] = sm;
sm->shouldHandleEvents(ServerModule::SMEventEnum::ConnectionStatusChanged | ServerModule::SMEventEnum::DataSent);
}
ChessServer() { name = "ChessServer"; }
~ChessServer() {
if(app) {}
}
void onLoad();
//void run();
bool onEvent(const Archimedes::Event&);
};
#ifdef CHESSSERVER_DYNAMIC
typedef ChessServer mtype;
#include "endModule.h"
#endif

View File

@@ -0,0 +1 @@
Example modules for Archimedes

View File

@@ -0,0 +1,126 @@
#include "Ollama.h"
#include "modules/ImguiModule/ImguiModule.h"
#include <sstream>
Ollama::Ollama(Archimedes::App* a, void* h) : Archimedes::Module(a, h) {
name = "Ollama";
ImguiModule* im = new ImguiModule(a, h);
deps[*im] = im;
}
Ollama::~Ollama() {
if(app) {
if(curl) {
curl_easy_cleanup(curl);
curl = nullptr;
}
curl_global_cleanup();
ImguiModule* im; { im = (ImguiModule*) moduleInstances[ImguiModule()]; }
im->releaseContext(ImGui::GetCurrentContext());
}
}
static size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::ostream* userp)
{
userp->write(static_cast<char*>(contents), size * nmemb);
return size * nmemb;
}
void Ollama::onLoad() {
ImguiModule* im; { im = (ImguiModule*) moduleInstances[ImguiModule()]; }
if(!im) {
std::cout << "No ImguiModule for Ollama!\n";
std::abort();
}
ImGui::SetCurrentContext(im->aquireContext());
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
}
void Ollama::run() {
ImGuiIO& io = ImGui::GetIO();
static std::string s, url = "https://ollama.blunkall.us", response = "";
static nlohmann::json sendObj;
static std::ostringstream oss;
static nlohmann::json jsonObj;
static std::future<CURLcode> result;
static bool inFlight = false;
ImGui::Begin("Ollama Module");
ImGui::InputText("url: ", &url);
static const std::string replace = "\\n";
static const std::string replace_by = "\n";
static std::string print = jsonObj["response"].dump(); print = jsonObj["response"].dump();
static auto pos = print.find(replace); pos = print.find(replace);
while (pos != std::string::npos) {
// Replace the substring with the specified string
print.replace(pos, replace.size(), replace_by);
// Find the next occurrence of the substring
pos = print.find(replace,
pos + replace_by.size());
}
print = "\n\n\n" + print + "\n\n\n";
ImGui::TextWrapped("%s", print.c_str());
ImGui::InputTextMultiline("prompt: ", &s);
if(ImGui::Button("send")) {
sendObj["model"] = "llama3.2";
sendObj["stream"] = false;
sendObj["prompt"] = s;
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_URL, (url + "/api/generate").c_str());
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &oss);
//curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
//curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, sendObj.dump().c_str());
result = std::async(std::launch::async, curl_easy_perform, curl);
inFlight = true;
}
ImGui::Text("ms per frame: %f", 1000 / io.Framerate);
ImGui::End();
if(curl) {
}
if(inFlight && result.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
CURLcode code = result.get();
response = oss.str();
oss.str("");
if(code != CURLE_OK) {
std::cerr << "curl_easy_perform() failed!: " << curl_easy_strerror(code) << std::endl;
app->emitEvent(new Archimedes::DoUnloadModuleEvent(name));
return;
} else {
jsonObj = nlohmann::json::parse(response);
std::cout << "Full json object:\n" << jsonObj.dump() << std::endl;
}
inFlight = false;
}
}

View File

@@ -0,0 +1,25 @@
#include "Archimedes.h"
#include "extratools.h"
class Ollama : public Archimedes::Module {
public:
Ollama(Archimedes::App*, void*);
Ollama() { name = "Ollama"; }
~Ollama();
void onLoad();
void run();
private:
CURL* curl;
};
#ifdef OLLAMA_DYNAMIC
typedef Ollama mtype;
#include "endModule.h"
#endif

View File

@@ -0,0 +1,17 @@
#include "Print.h"
Print::Print(Archimedes::App* a, void* h) : Archimedes::Module(a, h) {
name = "Print";
}
Print::~Print() {
if(app) {
std::cout << "Print Destroyed!\n";
}
}
void Print::run() {
std::cout << "Print lib loaded and run!\n";
app->emitEvent(new Archimedes::DoUnloadModuleEvent(name));
}

View File

@@ -0,0 +1,15 @@
#include "Archimedes.h"
class Print : public Archimedes::Module {
public:
Print(Archimedes::App*, void*);
Print() { name = "Print"; }
~Print();
void run();
};
#ifdef PRINT_DYNAMIC
typedef Print mtype;
#include "endModule.h"
#endif

View File

@@ -0,0 +1,191 @@
// This only works with opengl!!!!
#include "Sandbox.h"
Sandbox::Sandbox(Archimedes::App* a, void* h) : Archimedes::Module(a, h) {
name = "Sandbox";
WindowModule* wm = new WindowModule(a, h);
deps[*wm] = wm;
ImguiModule* im = new ImguiModule(a, h);
deps[*im] = im;
}
Sandbox::~Sandbox() {
if(app) {
WindowModule* wm; { wm = (WindowModule*) moduleInstances[WindowModule()]; }
ImguiModule* im; { im = (ImguiModule*) moduleInstances[ImguiModule()]; }
im->releaseContext(ImGui::GetCurrentContext());
wm->releaseWindow(window);
}
}
void Sandbox::onLoad() {
// get window
WindowModule* wm; { wm = (WindowModule*) moduleInstances[WindowModule()]; }
ImguiModule* im; { im = (ImguiModule*) moduleInstances[ImguiModule()]; }
if(!wm) {
std::cout << "No WindowModule for Sandbox!\n";
std::abort();
}
if(!im) {
std::cout << "No ImguiModule for Sandbox!\n";
std::abort();
}
window = wm->aquireWindow();
ImGui::SetCurrentContext(im->aquireContext());
window->getRenderer()->clearColor = { 0.2, 0.2, 0.4, 0.7 };
gridShader = Archimedes::Shader(cubeVS, gridFS, Archimedes::Shader::LoadType::FromSource);
window->getRenderer()->useShader(gridShader);
grid = Archimedes::RenderTarget(
Archimedes::VertexBuffer(gridVertices, 12 * sizeof(float)),
Archimedes::IndexArray(gridIndices, 6),
Archimedes::VertexLayout(),
gridShader
);
window->getRenderer()->useRenderTarget(grid);
cubeShader = Archimedes::Shader(cubeVS, cubeFS, Archimedes::Shader::LoadType::FromSource);
window->getRenderer()->useShader(cubeShader);
cube = Archimedes::RenderTarget(
Archimedes::VertexBuffer(vertices, 24 * sizeof(float)),
Archimedes::IndexArray(indices, 36),
Archimedes::VertexLayout(),
cubeShader
);
window->getRenderer()->useRenderTarget(cube);
int w, h;
window->getSize(w, h);
app->emitEvent(new Archimedes::ResizeWindowEvent(w, h));
}
void Sandbox::run() {
static float scale = 100.0f;
static glm::vec3 pos(0), rot(0);
static glm::vec3 camPos(0.0f, 0.0f, 3.0f), camRot(0.0f, 0.0f, 0.0f);
static glm::mat4 orthoCamera, perspCamera, cameraTransform;
cameraTransform = glm::mat4(1.0f);
cameraTransform = glm::translate(cameraTransform, camPos);
cameraTransform = glm::rotate(cameraTransform, camRot.x, glm::vec3(1.0f, 0.0f, 0.0f));
cameraTransform = glm::rotate(cameraTransform, camRot.y, glm::vec3(0.0f, 1.0f, 0.0f));
cameraTransform = glm::rotate(cameraTransform, camRot.z, glm::vec3(0.0f, 0.0f, 1.0f));
int w, h;
window->getSize(w, h);
orthoCamera = glm::ortho(-(float)w / 2.0f, (float)w / 2.0f, -(float)h / 2.0f, (float)h / 2.0f, 0.1f, 100.0f)
* cameraTransform;
perspCamera = glm::perspective(glm::radians(45.0f), (float)w/(float)h, 0.1f, 100.0f)
* cameraTransform;
glm::mat4& cubeTransform = cube.transform;
//glm::mat4& gridTransform = grid.transform;
cubeTransform = glm::mat4(1.0f);
cubeTransform = glm::translate(cubeTransform, pos);
cubeTransform = glm::rotate(cubeTransform, rot.x, glm::vec3(1.0f, 0.0f, 0.0f));
cubeTransform = glm::rotate(cubeTransform, rot.y, glm::vec3(0.0f, 1.0f, 0.0f));
cubeTransform = glm::rotate(cubeTransform, rot.z, glm::vec3(0.0f, 0.0f, 1.0f));
cubeTransform = glm::scale(cubeTransform, glm::vec3(scale));
//gridTransform = glm::mat4(1.0f);
//gridTransform = glm::scale(gridTransform, glm::vec3(800.0f));
cubeTransform = orthoCamera * cubeTransform;
//gridTransform = orthoCamera * gridTransform;
/*
cubeTransform = glm::perspective(glm::radians(45.0f), (float)w/(float)h, 0.1f, 100.0f)
* glm::lookAt(glm::vec3(0.0f, 0.0f, 3.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f))
* cubeTransform;
*/
//window->getRenderer()->draw(grid);
window->getRenderer()->draw(cube);
{
ImGuiIO& io = ImGui::GetIO();
static glm::vec4& clearColor = window->getRenderer()->clearColor;
ImGui::Begin("Sandbox Module");
ImGui::Text("Pick a clear color!");
ImGui::SliderFloat("r", &clearColor.r, 0.0f, 1.0f);
ImGui::SliderFloat("g", &clearColor.g, 0.0f, 1.0f);
ImGui::SliderFloat("b", &clearColor.b, 0.0f, 1.0f);
ImGui::SliderFloat("a", &clearColor.a, 0.0f, 1.0f);
ImGui::Text("Properties");
ImGui::SliderFloat("pitch", &rot.x, -3.14159265359f, 3.14159265359f);
ImGui::SliderFloat("yaw", &rot.y, -3.14159265359f, 3.14159265359f);
ImGui::SliderFloat("roll", &rot.z, -3.14159265359f, 3.14159265359f);
ImGui::SliderFloat("scale", &scale, 0.1f, 1000.0f);
ImGui::SliderFloat("x", &pos.x, -100.0f, 100.0f);
ImGui::SliderFloat("y", &pos.y, -100.0f, 100.0f);
ImGui::SliderFloat("z", &pos.z, -100.0f, 100.0f);
ImGui::Text("Camera Properties");
ImGui::SliderFloat("c_pitch", &camRot.x, -3.14159265359f, 3.14159265359f);
ImGui::SliderFloat("c_yaw", &camRot.y, -3.14159265359f, 3.14159265359f);
ImGui::SliderFloat("c_roll", &camRot.z, -3.14159265359f, 3.14159265359f);
ImGui::SliderFloat("c_x", &camPos.x, -100.0f, 100.0f);
ImGui::SliderFloat("c_y", &camPos.y, -100.0f, 100.0f);
ImGui::SliderFloat("c_z", &camPos.z, -100.0f, 100.0f);
if(ImGui::Button("Reset Window Size")) {
app->emitEvent(new Archimedes::ResizeWindowEvent(500, 500));
}
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
ImGui::End();
}
}
bool Sandbox::onEvent(const Archimedes::Event& e) {
return false;
}

View File

@@ -0,0 +1,161 @@
// This only works with opengl!!!!
#include "Archimedes.h"
#include "modules/WindowModule/WindowModule.h"
#include "modules/ImguiModule/ImguiModule.h"
class Sandbox : public Archimedes::Module {
public:
Sandbox(Archimedes::App*, void*);
Sandbox() { name = "Sandbox"; }
~Sandbox();
void onLoad() override;
void run() override;
bool onEvent(const Archimedes::Event& e) override;
private:
Archimedes::Window* window;
std::string cubeVS = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"uniform mat4 model;\n"
"uniform uvec2 res;\n"
"uniform vec4 clearColor;\n"
"void main()\n"
"{\n"
" gl_Position = model * vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";
std::string cubeFS = "#version 330 core\n"
"out vec4 FragColor;\n"
"uniform mat4 model;\n"
"uniform uvec2 res;\n"
"uniform vec4 clearColor;\n"
"void main()\n"
"{\n"
" FragColor = vec4(0.6f, 0.1f, 0.1f, 1.0f);\n"
"}\n\0";
std::string gridFS = "#version 330 core\n"
"out vec4 FragColor;\n"
"uniform mat4 model;\n"
"uniform uvec2 res;\n"
"uniform vec4 clearColor;\n"
"vec2 pos = gl_FragCoord.xy - res / 2.0f;\n"
"int gridSpacing = 50;"
"void main()\n"
"{\n"
" switch((int(pos.x)) * (int(pos.y))) {\n"
" case 0:\n"
" FragColor = vec4(1.0f);\n"
" break;\n"
" default:\n"
" switch((int(pos.x) % gridSpacing) * (int(pos.y) % gridSpacing)) {\n"
" case 0:\n"
" FragColor = vec4(0.7f, 0.7f, 0.7f, 1.0f);\n"
" break;\n"
" default:\n"
" discard;\n"
" break;\n"
" }\n"
" break;\n"
" }\n"
"}\n\0";
Archimedes::Shader cubeShader, gridShader;
Archimedes::RenderTarget cube, grid;
float gridVertices[24] = {
-1.0f, 0.0f, 1.0f,
1.0f, 0.0f, 1.0f,
1.0f, 0.0f, -1.0f,
-1.0f, 0.0f, -1.0f,
};
unsigned int gridIndices[6] = {
0,
1,
2,
2,
3,
0
};
float vertices[24] = {
-0.5f, -0.5f, 0.5f,
0.5f, -0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f, -0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
-0.5f, 0.5f, -0.5f,
};
unsigned int indices[36] = {
0,
1,
2,
2,
3,
0,
4,
5,
6,
6,
7,
4,
0,
1,
5,
5,
4,
0,
3,
2,
6,
6,
7,
3,
0,
3,
7,
7,
4,
0,
1,
2,
6,
6,
5,
1,
};
};
#ifdef SANDBOX_DYNAMIC
typedef Sandbox mtype;
#include "endModule.h"
#endif

View File

@@ -0,0 +1,93 @@
#include <errno.h>
#include <unistd.h>
#include <pty.h>
#include <fcntl.h>
#include "Terminal.h"
#include "modules/ImguiModule/ImguiModule.h"
Terminal::Terminal(Archimedes::App* a, void* h) : Archimedes::Module(a, h) {
name = "Terminal";
ImguiModule* im = new ImguiModule(a, h);
deps[*im] = im;
}
Terminal::~Terminal() {
if(app) {
ImguiModule* im; { im = (ImguiModule*) moduleInstances[ImguiModule()]; }
im->releaseContext(ImGui::GetCurrentContext());
}
}
void Terminal::onLoad() {
ImguiModule* im; { im = (ImguiModule*) moduleInstances[ImguiModule()]; }
if(!im) {
std::cout << "No ImguiModule for Terminal!\n";
std::abort();
}
ImGui::SetCurrentContext(im->aquireContext());
child_pid = forkpty(&master, nullptr, nullptr, nullptr);
if(!child_pid) {
char* const* args = nullptr;
execvp("bash", args);
}
//fcntl(master, F_SETFL, fcntl(master, F_GETFL, 0) | O_NONBLOCK);
/*
if (master >= 0)
(void)write(master, "ls\n", 3);
*/
}
void Terminal::run() {
static fd_set fds;
static int rc;
static char opArr[150];
static std::string input, output;
static timeval to; to = { 0, 0 };
FD_ZERO(&fds);
FD_SET(master, &fds);
rc = select(master + 1, &fds, NULL, NULL, &to);
switch(rc) {
case -1:
std::cerr << "Error " << errno << " on select()\n";
exit(1);
default:
if(FD_ISSET(master, &fds)) {
rc = read(master, opArr, 150);
if(rc < 0) {
//error on read
app->emitEvent(new Archimedes::DoUnloadModuleEvent(name));
} else {
if(input == "clear") output = "";
output += opArr;
}
}
}
ImGui::Begin("Terminal Module");
ImGui::TextWrapped("%s", output.c_str());
ImGui::InputText("input", &input);
if(ImGui::Button("send")) {
(void)write(master, (input + "\n").c_str(), input.length() + 1);
}
ImGui::End();
}

View File

@@ -0,0 +1,21 @@
#include "Archimedes.h"
class Terminal : public Archimedes::Module {
public:
Terminal(Archimedes::App*, void*);
Terminal() { name = "Terminal"; }
~Terminal();
void onLoad();
void run();
private:
int child_pid, master;
};
#ifdef TERMINAL_DYNAMIC
typedef Terminal mtype;
#include "endModule.h"
#endif

View File

@@ -0,0 +1,35 @@
#include "TestClay.h"
#define CLAY_IMPLIMENTATION
#include "clay.h"
#include <GLFW/glfw3.h>
TestClay::TestClay(void* h, Archimedes::App& a) : Archimedes::GuiModule(h, a) {
name = "TestClay";
}
TestClay::~TestClay() {
}
void TestClay::onLoad() {
createWindow();
window->getRenderer().init();
}
void TestClay::run() {
window->getRenderer().addRenderCmd([](){
});
if(window->shouldClose())
app.end();
window->doFrame();
}

View File

@@ -0,0 +1,25 @@
#include "Archimedes.h"
class TestClay : public Archimedes::Module {
public:
TestClay(void*, Archimedes::App&);
~TestClay();
void onLoad();
void run();
private:
};
extern "C" {
Archimedes::Module* create(void* handle, Archimedes::App& app) {
return new TestClay(handle, app);
}
}

View File

@@ -0,0 +1,56 @@
#include "TestImgui.h"
#include "modules/ImguiModule/ImguiModule.h"
TestImgui::TestImgui(Archimedes::App* a, void* h) : Archimedes::Module(a, h) {
name = "TestImgui";
ImguiModule* im = new ImguiModule(a, h);
deps[*im] = im;
}
TestImgui::~TestImgui() {
ImguiModule* im; { im = (ImguiModule*) moduleInstances[ImguiModule()]; }
im->releaseContext(ImGui::GetCurrentContext());
}
void TestImgui::onLoad() {
ImguiModule* im; { im = (ImguiModule*) moduleInstances[ImguiModule()]; }
if(!im) {
std::cout << "No ImguiModule for TestImgui!\n";
std::abort();
}
ImGui::SetCurrentContext(im->aquireContext());
}
void TestImgui::run() {
if(demo)
ImGui::ShowDemoWindow(&this->demo);
else
app->emitEvent(new Archimedes::DoUnloadModuleEvent(name));
{
ImGuiIO& io = ImGui::GetIO();
static float f = 0.0f;
static int counter = 0;
ImGui::Begin("TestImgui Module"); // Create a window called "Hello, world!" and append into it.
ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too)
ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
counter++;
ImGui::SameLine();
ImGui::Text("counter = %d", counter);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
ImGui::End();
}
}

View File

@@ -0,0 +1,24 @@
#include "Archimedes.h"
class TestImgui : public Archimedes::Module {
public:
TestImgui(Archimedes::App*, void*);
TestImgui() { name = "TestImgui"; }
~TestImgui();
void onLoad();
void run();
private:
bool demo = true;
};
#ifdef TESTIMGUI_DYNAMIC
typedef TestImgui mtype;
#include "endModule.h"
#endif

View File

@@ -0,0 +1,28 @@
#include "TestNotCurses.h"
TestNotCurses::TestNotCurses(Archimedes::App* a, void* h) : Archimedes::Module(a, h) {
name = "TestNotCurses";
}
TestNotCurses::~TestNotCurses() {
notcurses_stop(ncInstance);
}
void TestNotCurses::onLoad() {
setlocale(LC_ALL, "");
notcurses_options opts;
ncInstance = notcurses_init(&opts, NULL);
if(!ncInstance) {
app->emitEvent(new Archimedes::DoUnloadModuleEvent(name));
return;
}
}
void TestNotCurses::run() {
notcurses_render(ncInstance);
}

View File

@@ -0,0 +1,19 @@
#include "Archimedes.h"
#include <notcurses/notcurses.h>
class TestNotCurses : public Archimedes::Module {
public:
TestNotCurses(Archimedes::App*, void*);
~TestNotCurses();
void run();
void onLoad();
private:
notcurses* ncInstance;
};
#ifdef TESTNOTCURSES_DYNAMIC
typedef TestNotCurses mtype;
#include "endModule.h"
#endif

View File

@@ -0,0 +1,66 @@
// This only works with opengl!!!!
#include "TestTriangle.h"
TestTriangle::TestTriangle(Archimedes::App* a, void* h) : Archimedes::Module(a, h) {
name = "TestTriangle";
WindowModule* wm = new WindowModule(a, h);
deps[*wm] = wm;
}
TestTriangle::~TestTriangle() {
if(app) {
WindowModule* wm; { wm = (WindowModule*) moduleInstances[WindowModule()]; }
/*
#if WINDOW == 2
wm->removeEventFn(ecmd_it);
#endif
*/
wm->releaseWindow(window);
delete rt;
}
}
void TestTriangle::onLoad() {
// get window
WindowModule* wm; { wm = (WindowModule*) moduleInstances[WindowModule()]; }
if(!wm) {
std::cout << "No WindowModule TestTriangle!\n";
std::abort();
}
window = wm->aquireWindow();
window->getRenderer()->clearColor = { 0.2, 0.2, 0.4, 0.7 };
rt = window->getRenderer()->createRenderTarget(
vertices,
9 * sizeof(float),
indices,
3,
Archimedes::VertexLayout(),
vertexShaderSource,
fragmentShaderSource,
Archimedes::Shader::LoadType::FromSource
);
}
void TestTriangle::run() {
window->getRenderer()->draw(rt);
}
bool TestTriangle::onEvent(const Archimedes::Event& e) {
return false;
}

View File

@@ -0,0 +1,65 @@
// This only works with opengl!!!!
#include "Archimedes.h"
#include "modules/WindowModule/WindowModule.h"
#define GLEW_STATIC
#include <GL/glew.h>
class TestTriangle : public Archimedes::Module {
public:
TestTriangle(Archimedes::App*, void*);
TestTriangle() { name = "TestTriangle"; }
~TestTriangle();
void onLoad() override;
void run() override;
bool onEvent(const Archimedes::Event& e) override;
private:
Archimedes::Window* window;
const char *vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";
const char *fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
" FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0";
Archimedes::RenderTarget* rt;
float vertices[9] = {
-0.5f, -0.5f, 0.0f, // left
0.5f, -0.5f, 0.0f, // right
0.0f, 0.5f, 0.0f // top
};
unsigned int indices[3] = {
0, // left
1, // right
2 // top
};
unsigned int vao, vbo, ibo, shaderProgram;
};
#ifdef TESTTRIANGLE_DYNAMIC
typedef TestTriangle mtype;
#include "endModule.h"
#endif

View File

@@ -0,0 +1,141 @@
#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));
}
}

View File

@@ -0,0 +1,73 @@
#include "Archimedes.h"
#include <steam/steamnetworkingsockets.h>
#include <steam/isteamnetworkingutils.h>
#include "utils/Events/NetworkEvents.h"
class ClientModule : public Archimedes::Module {
public:
ClientModule(Archimedes::App*, void*);
ClientModule() { name = "ClientModule"; }
~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);
app->emitEvent(new Archimedes::DataSentEvent(data, byteCount));
}
bool isRunning() const { return running; }
bool isConnected() const { return connection != k_HSteamNetConnection_Invalid; }
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 Archimedes::ConnectionStatusChangedEvent(pInfo));
}
void PollConnectionStateChanges() {
callbackInstance = this;
interface->RunCallbacks();
}
};
#ifdef CLIENTMODULE_DYNAMIC
typedef ClientModule mtype;
#include "endModule.h"
#endif

View File

@@ -0,0 +1,116 @@
#include "ImguiModule.h"
#include "pch.hpp"
ImguiModule::ImguiModule(Archimedes::App* a, void* h = nullptr) : Archimedes::Module(a, h) {
name = "ImguiModule";
WindowModule* wm = new WindowModule(a, h);
deps[*wm] = wm;
}
ImguiModule::~ImguiModule() {
if(app) {
WindowModule* wm; { wm = (WindowModule*) moduleInstances[WindowModule()]; }
#ifdef WINDOW_SDL3
wm->removeEventFn(ecmd_it);
#endif
rendererShutdown();
windowShutdown();
ImGui::DestroyContext();
wm->releaseWindow(window);
}
}
void ImguiModule::onLoad() {
WindowModule* wm; { wm = (WindowModule*) moduleInstances[WindowModule()]; }
if(!wm) {
std::cout << "No WindowModule for ImguiModule!\n";
std::abort();
}
window = (Archimedes::WindowGLFW*) wm->aquireWindow();
#ifdef RENDERER_SDL3
renderer = window->getRenderer()->getRendererImpl()->renderer;
#endif
IMGUI_CHECKVERSION();
context = ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
#ifdef CUSTOMFONT
io.Fonts->AddFontFromFileTTF(STRINGIZE_VALUE_OF(CUSTOMFONT), 13.0f);
#endif
// Setup Dear ImGui style
ImGui::StyleColorsDark();
//ImGui::StyleColorsLight();
// Setup scaling
ImGuiStyle& style = ImGui::GetStyle();
io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now.
io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes.
// When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
style.WindowRounding = 0.0f;
style.Colors[ImGuiCol_WindowBg].w = 1.0f;
}
// Setup Platform/Renderer backends
if(!windowInit())
std::cout << "windowInit failed\n";
if(!rendererInit()) {
std::cout << "rendererInit failed!\n" << std::endl;
}
#ifdef WINDOW_SDL3
ecmd_it = wm->addEventFn([](Archimedes::Event* e){
if(e->userData.type() == typeid(SDL_Event*)) {
ImGui_ImplSDL3_ProcessEvent(std::any_cast<SDL_Event*>(e->userData));
}
});
#endif
//Compute first frame ahead of first WindowModule->run()
rendererNewFrame();
windowNewFrame();
ImGui::NewFrame();
}
void ImguiModule::run() {
ImGui::Render();
rendererRenderDrawData();
if(ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
window->getWindowImpl()->restoreContext();
}
rendererNewFrame();
windowNewFrame();
ImGui::NewFrame();
};
bool ImguiModule::onEvent(const Archimedes::Event &e) {
return false;
}

View File

@@ -0,0 +1,120 @@
#include "Archimedes.h"
#include "imgui.h"
#include "misc/cpp/imgui_stdlib.h"
#include "modules/WindowModule/WindowModule.h"
#ifdef RENDERER_OPENGL
#include "backends/imgui_impl_opengl3.h"
#endif
#ifdef RENDERER_SDL3
#include "backends/imgui_impl_sdlrenderer3.h"
#endif
#ifdef WINDOW_GLFW
#include "backends/imgui_impl_glfw.h"
#include <GLFW/glfw3.h>
#endif
#ifdef WINDOW_SDL3
#include "backends/imgui_impl_sdl3.h"
#include <SDL3/SDL.h>
#endif
class ImguiModule : public Archimedes::Module {
public:
ImguiModule(Archimedes::App*, void*);
ImguiModule() { name = "ImguiModule"; }
~ImguiModule();
void onLoad() override;
void run() override;
bool onEvent(const Archimedes::Event&) override;
ImGuiContext* aquireContext() {
contextRefs++;
return context;
}
void releaseContext(ImGuiContext* ctxt) {
if(ctxt == context && context != nullptr) {
if(--contextRefs == 0) {
app->emitEvent(new Archimedes::DoUnloadModuleEvent(name));
}
}
}
private:
int contextRefs = 0;
ImGuiContext* context;
Archimedes::WindowGLFW* window;
std::list<std::function<void()>>::iterator rcmd_it;
std::list<std::function<void(Archimedes::Event*)>>::iterator ecmd_it;
#ifdef RENDERER_OPENGL
auto rendererInit() { return ImGui_ImplOpenGL3_Init("#version 330"); }
void rendererShutdown() { ImGui_ImplOpenGL3_Shutdown(); }
void rendererNewFrame() { ImGui_ImplOpenGL3_NewFrame(); }
void rendererRenderDrawData() { ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); }
#endif
#ifdef RENDERER_SDL3
SDL_Renderer* renderer;
auto rendererInit() { return ImGui_ImplSDLRenderer3_Init(renderer); }
void rendererShutdown() { ImGui_ImplSDLRenderer3_Shutdown(); }
void rendererNewFrame() { ImGui_ImplSDLRenderer3_NewFrame(); }
void rendererRenderDrawData() { ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), renderer); }
#endif
#ifdef WINDOW_GLFW
#ifdef RENDERER_OPENGL
auto windowInit() { return ImGui_ImplGlfw_InitForOpenGL(window->getWindowImpl()->getWindow(), true); }
#endif
void windowShutdown() { ImGui_ImplGlfw_Shutdown(); }
void windowNewFrame() { ImGui_ImplGlfw_NewFrame(); }
#endif
#ifdef WINDOW_SDL3
#ifdef RENDERER_OPENGL
auto windowInit() { return ImGui_ImplSDL3_InitForOpenGL(window->getWindowImpl()->getWindow(), window->getWindowImpl()->getContext()); }
#endif
#ifdef RENDERER_SDL3
auto windowInit() { return ImGui_ImplSDL3_InitForSDLRenderer(window->getWindowImpl()->getWindow(), renderer); }
#endif
void windowShutdown() { ImGui_ImplSDL3_Shutdown(); }
void windowNewFrame() { ImGui_ImplSDL3_NewFrame(); }
#endif
};
#ifdef IMGUIMODULE_DYNAMIC
typedef ImguiModule mtype;
#include "endModule.h"
#endif

View File

@@ -0,0 +1,65 @@
#include "MainGUI.h"
#include "modules/ImguiModule/ImguiModule.h"
MainGUI::MainGUI(Archimedes::App* a, void* h) : Archimedes::Module(a, h) {
name = "MainGUI";
ImguiModule* im = new ImguiModule(a, h);
deps[*im] = im;
}
MainGUI::~MainGUI() {
if(app) {
ImguiModule* im; { im = (ImguiModule*) moduleInstances[ImguiModule()]; }
im->releaseContext(ImGui::GetCurrentContext());
}
}
void MainGUI::onLoad() {
ImguiModule* im; { im = (ImguiModule*) moduleInstances[ImguiModule()]; }
if(!im) {
std::cout << "No ImguiModule for MainGUI!\n";
std::abort();
}
ImGui::SetCurrentContext(im->aquireContext());
}
void MainGUI::run() {
if(open) {
ImGuiIO& io = ImGui::GetIO();
static std::string s;
ImGui::Begin("MainGUI Module", &open);
ImGui::Text("Active Modules:");
for(auto m : app->getModuleNames())
ImGui::Text("%s", m.c_str());
ImGui::Text("\nEnter a module to un/load:");
ImGui::InputText("module: ", &s);
if(ImGui::Button("load"))
app->emitEvent(new Archimedes::DoLoadModuleEvent(s));
ImGui::SameLine();
if(ImGui::Button("unload"))
app->emitEvent(new Archimedes::DoUnloadModuleEvent(s));
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
ImGui::End();
ImGui::ShowDemoWindow();
} else {
app->end();
}
}

View File

@@ -0,0 +1,22 @@
#include "Archimedes.h"
class MainGUI : public Archimedes::Module {
public:
MainGUI(Archimedes::App*, void*);
MainGUI() { name = "MainGUI"; }
~MainGUI();
void onLoad();
void run();
private:
bool open = true;
};
#ifdef MAINGUI_DYNAMIC
typedef MainGUI mtype;
#include "endModule.h"
#endif

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));
}
}

View File

@@ -0,0 +1,100 @@
#ifndef SERVERMODULE_H
#define SERVERMODULE_H
#include "Archimedes.h"
#include <steam/steamnetworkingsockets.h>
#include <steam/isteamnetworkingutils.h>
#include "utils/Events/NetworkEvents.h"
class ServerModule : public Archimedes::Module {
public:
ServerModule(Archimedes::App*, void*);
ServerModule() { name = "ServerModule"; }
~ServerModule();
void onLoad();
bool onEvent(const Archimedes::Event&);
void run();
void startServer(int);
void stopServer();
enum SMEventEnum {
None = 0,
ConnectionStatusChanged = 1 << 0,
DataRecieved = 1 << 1,
DataSent = 1 << 2
};
bool isRunning() const { return running; }
void shouldHandleEvents(unsigned int events) { eventsToHandle = events; }
void sendReliable(HSteamNetConnection client, const void* data, uint32 byteCount) {
interface->SendMessageToConnection(client, data, byteCount, k_nSteamNetworkingSend_Reliable, nullptr);
}
void disconnectClient(HSteamNetConnection c) {
if(clients.find(c) != clients.end()) {
interface->CloseConnection(c, 0, nullptr, false);
clients.erase(c);
}
}
void disconnectAllClients() {
while(!clients.empty()) {
disconnectClient(clients.begin()->first);
}
}
std::map<HSteamNetConnection, unsigned int> getClients(unsigned int* num = nullptr) const {
if(num) {
*num = numClients;
}
return clients;
}
void pollIncomingData();
private:
//handle all events by default
unsigned int eventsToHandle = SMEventEnum::ConnectionStatusChanged | SMEventEnum::DataSent | SMEventEnum::DataRecieved;
bool running = false;
int port = -1;
unsigned int numClients = 0;
HSteamListenSocket listenSock;
HSteamNetPollGroup pollGroup;
ISteamNetworkingSockets* interface;
inline static ServerModule *callbackInstance = nullptr;
static void SteamNetConnectionStatusChangedCallback( SteamNetConnectionStatusChangedCallback_t *pInfo ) {
callbackInstance->OnSteamNetConnectionStatusChanged( pInfo );
}
void OnSteamNetConnectionStatusChanged( SteamNetConnectionStatusChangedCallback_t *pInfo ) {
app->emitEvent(new Archimedes::ConnectionStatusChangedEvent(pInfo));
}
std::map<HSteamNetConnection, unsigned int> clients;
void PollConnectionStateChanges() {
callbackInstance = this;
interface->RunCallbacks();
}
};
#ifdef SERVERMODULE_DYNAMIC
typedef ServerModule mtype;
#include "endModule.h"
#endif
#endif

View File

@@ -0,0 +1,97 @@
#include "WindowModule.h"
WindowModule::~WindowModule() {
if(app) {
app->unregisterEvent(Archimedes::ResizeWindowEvent());
app->unregisterEvent(Archimedes::CloseWindowEvent());
app->unregisterEvent(Archimedes::KeyPressedWindowEvent());
app->unregisterEvent(Archimedes::KeyReleasedWindowEvent());
app->unregisterEvent(Archimedes::MouseButtonPressedWindowEvent());
app->unregisterEvent(Archimedes::MouseButtonReleasedWindowEvent());
app->unregisterEvent(Archimedes::ScrollWindowEvent());
app->unregisterEvent(Archimedes::MouseMovedWindowEvent());
app->unregisterEvent(Archimedes::FocusedWindowEvent());
app->unregisterEvent(Archimedes::FocusLostWindowEvent());
app->unregisterEvent(Archimedes::MovedWindowEvent());
if(renderer) {
delete renderer;
}
if(window)
releaseWindow(window);
}
}
void WindowModule::onLoad() {
app->registerEvent(Archimedes::ResizeWindowEvent());
app->registerEvent(Archimedes::CloseWindowEvent());
app->registerEvent(Archimedes::KeyPressedWindowEvent());
app->registerEvent(Archimedes::KeyReleasedWindowEvent());
app->registerEvent(Archimedes::MouseButtonPressedWindowEvent());
app->registerEvent(Archimedes::MouseButtonReleasedWindowEvent());
app->registerEvent(Archimedes::ScrollWindowEvent());
app->registerEvent(Archimedes::MouseMovedWindowEvent());
app->registerEvent(Archimedes::FocusedWindowEvent());
app->registerEvent(Archimedes::FocusLostWindowEvent());
app->registerEvent(Archimedes::MovedWindowEvent());
renderer = new Archimedes::RendererOpenGL();
}
void WindowModule::run() {
if(window) {
window->doFrame();
} else {
app->emitEvent(new Archimedes::DoUnloadModuleEvent(name));
}
}
bool WindowModule::onEvent(const Archimedes::Event& e) {
unsigned int type = app->getEventType(e);
if(type == app->getEventType(Archimedes::ResizeWindowEvent())) {
Archimedes::ResizeWindowEvent& event = (Archimedes::ResizeWindowEvent&) e;
renderer->w = event.width;
renderer->h = event.height;
window->setSize(event.width, event.height);
return true;
} else if(type == app->getEventType(Archimedes::CloseWindowEvent())) {
app->emitEvent(new Archimedes::DoUnloadModuleEvent(name));
return true;
} else if(type == app->getEventType(Archimedes::KeyPressedWindowEvent())) {
return true;
} else if(type == app->getEventType(Archimedes::KeyReleasedWindowEvent())) {
return true;
} else if(type == app->getEventType(Archimedes::MouseButtonPressedWindowEvent())) {
return true;
} else if(type == app->getEventType(Archimedes::MouseButtonReleasedWindowEvent())) {
return true;
} else if(type == app->getEventType(Archimedes::ScrollWindowEvent())) {
return true;
} else if(type == app->getEventType(Archimedes::MouseMovedWindowEvent())) {
return true;
} else if(type == app->getEventType(Archimedes::FocusedWindowEvent())) {
return true;
} else if(type == app->getEventType(Archimedes::FocusLostWindowEvent())) {
return true;
} else if(type == app->getEventType(Archimedes::MovedWindowEvent())) {
return true;
}
return false;
}

View File

@@ -0,0 +1,85 @@
#ifndef WINDOWMODULE_H
#define WINDOWMODULE_H
#include "Archimedes.h"
#include "utils/Renderer/RendererImpl/RendererOpenGL/RendererOpenGL.h"
#include "utils/Window/WindowImpl/WindowGLFW/WindowGLFW.h"
class WindowModule : public Archimedes::Module {
public:
WindowModule(Archimedes::App* a, void* h) : Archimedes::Module(a, h) {
name = "WindowModule";
}
WindowModule() { name = "WindowModule"; }
~WindowModule() override;
void run() override;
void onLoad() override;
bool onEvent(const Archimedes::Event& e) override;
//interface for other modules
Archimedes::Window* aquireWindow() {
if(!window) {
window = new Archimedes::WindowGLFW([this](Archimedes::Event* e) {
for(std::function<void(Archimedes::Event*)> f : eventFuncs)
f(e);
app->emitEvent(e);
});
window->setRenderer(renderer);
if(!renderer->init()) {
std::cout << "Renderer init failed!\n";
std::abort();
}
}
windowRefs++;
#ifdef RENDERER_OPENGL
window->getWindowImpl()->restoreContext();
#endif
return window;
}
void releaseWindow(Archimedes::Window* w) {
if(w == window && window != nullptr) {
if(--windowRefs == 0) {
delete window;
window = nullptr;
}
}
}
auto addEventFn(const std::function<void(Archimedes::Event*)>& fn) { eventFuncs.push_back(fn); return --eventFuncs.end()++; }
void removeEventFn(std::list<std::function<void(Archimedes::Event*)>>::iterator it) { eventFuncs.erase(it); }
Archimedes::Renderer* getRenderer() { return renderer; }
private:
int windowRefs = 0;
std::list<std::function<void(Archimedes::Event*)>> eventFuncs;
Archimedes::WindowGLFW* window = nullptr;
Archimedes::RendererOpenGL* renderer = nullptr;
};
#ifdef WINDOWMODULE_DYNAMIC
typedef WindowModule mtype;
#include "endModule.h"
#endif
#endif