Finalize Cross-Platform Protocol v2.0.3

This commit is contained in:
Michael Howard 2026-04-23 17:36:49 -05:00
parent 86fc77bfd7
commit 446e9ae771
5 changed files with 89 additions and 76 deletions

Binary file not shown.

View File

@ -1 +1 @@
v2.0.0 v2.0.2

Binary file not shown.

View File

@ -1 +1 @@
v2.0.0 v2.0.2

View File

@ -733,7 +733,7 @@ int main(void)
// By default, windows have minimize, maximize, and close buttons on the top bar. // By default, windows have minimize, maximize, and close buttons on the top bar.
SetConfigFlags(FLAG_WINDOW_RESIZABLE | FLAG_VSYNC_HINT); SetConfigFlags(FLAG_WINDOW_RESIZABLE | FLAG_VSYNC_HINT);
InitWindow(screenWidth, screenHeight, "MorriCraft v2.0.2"); InitWindow(screenWidth, screenHeight, "MorriCraft v2.0.3");
LoadConfig(); LoadConfig();
SetExitKey(KEY_NULL); // Prevent ESC from closing the window SetExitKey(KEY_NULL); // Prevent ESC from closing the window
@ -966,57 +966,91 @@ int main(void)
// Handle incoming data // Handle incoming data
auto handleIncoming = [&](Socket sock, bool isServer, int clientIdx = -1) { auto handleIncoming = [&](Socket sock, bool isServer, int clientIdx = -1) {
PacketHeader head; while (true) {
int bytes = recv(sock, (char*)&head, sizeof(head), 0); // Use a quick non-blocking check to see if more data is available
if (bytes > 0) { fd_set readfds;
FD_ZERO(&readfds);
FD_SET(sock, &readfds);
struct timeval tv = {0, 0};
if (select((int)sock + 1, &readfds, NULL, NULL, &tv) <= 0) break;
PacketHeader head;
int bytes = recv(sock, (char*)&head, sizeof(head), 0);
if (bytes <= 0) {
if (isServer && clientIdx != -1) {
std::string leaver = "A player";
for (auto it = remotePlayers.begin(); it != remotePlayers.end(); ++it) {
if (it->sock == sock) {
leaver = it->name;
remotePlayers.erase(it);
break;
}
}
chatLog.push_back({ leaver + " left the game", 5.0f });
PacketHeader nHead = { (uint8_t)PACKET_CHAT, (uint32_t)sizeof(PacketChat) };
PacketChat nChat;
strncpy(nChat.name, "Server", 31);
strncpy(nChat.message, (leaver + " left the game").c_str(), 127);
for (auto& s : clientSockets) {
if (s != sock) {
send(s, (char*)&nHead, sizeof(nHead), 0);
send(s, (char*)&nChat, sizeof(nChat), 0);
}
}
closesocket(sock);
clientSockets.erase(clientSockets.begin() + clientIdx);
}
break;
}
if (head.type == PACKET_HANDSHAKE) { if (head.type == PACKET_HANDSHAKE) {
PacketHandshake hand; PacketHandshake hand;
recv(sock, (char*)&hand, sizeof(hand), 0); recv(sock, (char*)&hand, sizeof(hand), 0);
if (isServer) { if (isServer) {
uint32_t newID = (uint32_t)sock; bool duplicate = false;
RemotePlayer rp; for (auto& rp : remotePlayers) { if (rp.sock == sock) { duplicate = true; break; } }
rp.sock = sock; if (!duplicate) {
rp.id = newID; uint32_t newID = (uint32_t)sock;
rp.name = hand.name; RemotePlayer rp;
rp.position = (Vector3){0,0,0}; rp.sock = sock;
remotePlayers.push_back(rp); rp.id = newID;
rp.name = hand.name;
rp.position = (Vector3){0,0,0};
remotePlayers.push_back(rp);
// Notify others chatLog.push_back({ std::string(hand.name) + " joined the game", 5.0f });
chatLog.push_back({ std::string(hand.name) + " joined the game", 5.0f }); PacketHeader nHead = { (uint8_t)PACKET_CHAT, (uint32_t)sizeof(PacketChat) };
PacketHeader nHead = { (uint8_t)PACKET_CHAT, (uint32_t)sizeof(PacketChat) }; PacketChat nChat;
PacketChat nChat; strncpy(nChat.name, "Server", 31);
strncpy(nChat.name, "Server", 31); strncpy(nChat.message, (std::string(hand.name) + " joined the game").c_str(), 127);
strncpy(nChat.message, (std::string(hand.name) + " joined the game").c_str(), 127); for (auto& s : clientSockets) {
for (auto& s : clientSockets) { send(s, (char*)&nHead, sizeof(nHead), 0);
send(s, (char*)&nHead, sizeof(nHead), 0); send(s, (char*)&nChat, sizeof(nChat), 0);
send(s, (char*)&nChat, sizeof(nChat), 0);
}
// Send seed and time to new client
PacketHeader sHead = { (uint8_t)PACKET_SEED_SYNC, (uint32_t)sizeof(PacketSeedSync) };
PacketSeedSync sData = { (int)globalSeedHash };
send(sock, (char*)&sHead, sizeof(sHead), 0);
send(sock, (char*)&sData, sizeof(sData), 0);
PacketHeader tHead = { (uint8_t)PACKET_TIME_SYNC, (uint32_t)sizeof(PacketTimeSync) };
PacketTimeSync tData = { gameTime };
send(sock, (char*)&tHead, sizeof(tHead), 0);
send(sock, (char*)&tData, sizeof(tData), 0);
// Send existing players to new client
for (auto& rp : remotePlayers) {
if (rp.sock != sock) {
PacketHeader pHead = { (uint8_t)PACKET_PLAYER_UPDATE, (uint32_t)sizeof(PacketPlayerUpdate) };
PacketPlayerUpdate pData = { rp.position.x, rp.position.y, rp.position.z, rp.yaw, rp.id };
send(sock, (char*)&pHead, sizeof(pHead), 0);
send(sock, (char*)&pData, sizeof(pData), 0);
} }
PacketHeader sHead = { (uint8_t)PACKET_SEED_SYNC, (uint32_t)sizeof(PacketSeedSync) };
PacketSeedSync sData = { (int)globalSeedHash };
send(sock, (char*)&sHead, sizeof(sHead), 0);
send(sock, (char*)&sData, sizeof(sData), 0);
PacketHeader tHead = { (uint8_t)PACKET_TIME_SYNC, (uint32_t)sizeof(PacketTimeSync) };
PacketTimeSync tData = { gameTime };
send(sock, (char*)&tHead, sizeof(tHead), 0);
send(sock, (char*)&tData, sizeof(tData), 0);
for (auto& existing : remotePlayers) {
if (existing.sock != sock) {
PacketHeader pHead = { (uint8_t)PACKET_PLAYER_UPDATE, (uint32_t)sizeof(PacketPlayerUpdate) };
PacketPlayerUpdate pData = { existing.position.x, existing.position.y, existing.position.z, existing.yaw, existing.id };
send(sock, (char*)&pHead, sizeof(pHead), 0);
send(sock, (char*)&pData, sizeof(pData), 0);
}
}
PacketHeader hHead = { (uint8_t)PACKET_PLAYER_UPDATE, (uint32_t)sizeof(PacketPlayerUpdate) };
PacketPlayerUpdate hData = { camera3D.position.x, camera3D.position.y - 1.6f, camera3D.position.z, camYaw, 0 };
send(sock, (char*)&hHead, sizeof(hHead), 0);
send(sock, (char*)&hData, sizeof(hData), 0);
} }
// Send HOST to new client (Host ID is always 0)
PacketHeader hHead = { (uint8_t)PACKET_PLAYER_UPDATE, (uint32_t)sizeof(PacketPlayerUpdate) };
PacketPlayerUpdate hData = { camera3D.position.x, camera3D.position.y - 1.6f, camera3D.position.z, camYaw, 0 };
send(sock, (char*)&hHead, sizeof(hHead), 0);
send(sock, (char*)&hData, sizeof(hData), 0);
} }
} else if (head.type == PACKET_PLAYER_UPDATE) { } else if (head.type == PACKET_PLAYER_UPDATE) {
PacketPlayerUpdate pu; PacketPlayerUpdate pu;
@ -1039,7 +1073,7 @@ int main(void)
remotePlayers.push_back(rp); remotePlayers.push_back(rp);
} }
if (isServer) { if (isServer) {
pu.playerID = (uint32_t)sock; // Ensure ID is correct pu.playerID = (uint32_t)sock;
for (auto& other : clientSockets) { for (auto& other : clientSockets) {
if (other != sock) { if (other != sock) {
send(other, (char*)&head, sizeof(head), 0); send(other, (char*)&head, sizeof(head), 0);
@ -1068,7 +1102,6 @@ int main(void)
recv(sock, (char*)&ss, sizeof(ss), 0); recv(sock, (char*)&ss, sizeof(ss), 0);
if (!isServer) { if (!isServer) {
globalSeedHash = ss.seed; globalSeedHash = ss.seed;
// Regerate world if seed changed
for (auto& pair : worldChunks) delete pair.second; for (auto& pair : worldChunks) delete pair.second;
worldChunks.clear(); worldChunks.clear();
} }
@ -1084,31 +1117,11 @@ int main(void)
} }
} }
} }
} } else {
} else if (bytes == 0 || (bytes < 0 && SOCKET_ERROR_VAL != -1)) { if (head.size > 0 && head.size < 2048) {
// Disconnect handling std::vector<char> discard(head.size);
if (isServer && clientIdx != -1) { recv(sock, discard.data(), head.size, 0);
std::string leaver = "A player";
for (auto it = remotePlayers.begin(); it != remotePlayers.end(); ++it) {
if (it->sock == sock) {
leaver = it->name;
remotePlayers.erase(it);
break;
}
} }
chatLog.push_back({ leaver + " left the game", 5.0f });
PacketHeader nHead = { (uint8_t)PACKET_CHAT, (uint32_t)sizeof(PacketChat) };
PacketChat nChat;
strncpy(nChat.name, "Server", 31);
strncpy(nChat.message, (leaver + " left the game").c_str(), 127);
for (auto& s : clientSockets) {
if (s != sock) {
send(s, (char*)&nHead, sizeof(nHead), 0);
send(s, (char*)&nChat, sizeof(nChat), 0);
}
}
closesocket(sock);
clientSockets.erase(clientSockets.begin() + clientIdx);
} }
} }
}; };
@ -1697,8 +1710,8 @@ int main(void)
DrawTexturePro(titleTexture, sourceRec, destRec, origin, 0.0f, WHITE); DrawTexturePro(titleTexture, sourceRec, destRec, origin, 0.0f, WHITE);
EndMode2D(); EndMode2D();
// Show Version Number (v2.0.2) in Red // Show Version Number (v2.0.3) in Red
DrawTextEx(customFont, "v2.0.2", (Vector2){ (float)currentWidth - 140, (float)currentHeight - 40 }, 22, 1.0f, RED); DrawTextEx(customFont, "v2.0.3", (Vector2){ (float)currentWidth - 140, (float)currentHeight - 40 }, 22, 1.0f, RED);
// --- PLAYER NAME POPUP (IF MISSING) --- // --- PLAYER NAME POPUP (IF MISSING) ---
if (playerName == "") { if (playerName == "") {