Fix Multiplayer with more than 2 people

At least on Citra and quite hacky
Join Menu still shows wrong player count, but this affects nothing
This commit is contained in:
Andre Schweiger 2018-02-04 21:02:16 +01:00
parent d2f7796b79
commit 6513c0d1fa
6 changed files with 79 additions and 20 deletions

Binary file not shown.

View file

@ -101,6 +101,7 @@ void ingameMenuTick(PlayerData *pd, int menu) {
case MENU_LOSE: case MENU_LOSE:
if (pd->inputs.k_accept.clicked){ if (pd->inputs.k_accept.clicked){
pd->ingameMenu = MENU_NONE; pd->ingameMenu = MENU_NONE;
pd->entity.level = 1;
playerSpawn(pd); playerSpawn(pd);
//TODO: This canceled to main menu, but what should I do in multiplayer? //TODO: This canceled to main menu, but what should I do in multiplayer?
} }

View file

@ -587,6 +587,7 @@ void tickMenu(int menu){
} }
break; break;
case 2: case 2:
networkScan();
currentMenu = MENU_MULTIPLAYER_JOIN; currentMenu = MENU_MULTIPLAYER_JOIN;
currentSelection = 0; currentSelection = 0;
menuScanTimer = 0; menuScanTimer = 0;

View file

@ -21,6 +21,8 @@ udsBindContext networkBindCtx;
udsConnectionStatus networkStatus; udsConnectionStatus networkStatus;
u16 networkConnectedMask;
//new code //new code
//structure in buffer is u16(seqID),u16(size),size(data), ... //structure in buffer is u16(seqID),u16(size),size(data), ...
void *networkSendBuffer; void *networkSendBuffer;
@ -57,8 +59,16 @@ void networkThreadMain(void *arg) {
} }
void networkUpdateStatus() { void networkUpdateStatus() {
/*for(int i=0; i<10; i++) {
Result ret = udsGetConnectionStatus(&networkStatus);
if(!R_FAILED(ret)) {
return;
}
}*/
if(udsWaitConnectionStatusEvent(false, false)) {
udsGetConnectionStatus(&networkStatus); udsGetConnectionStatus(&networkStatus);
} }
}
void networkHandleRecieve() { void networkHandleRecieve() {
bool recieved = false; bool recieved = false;
@ -101,8 +111,12 @@ void networkHandleRecieve() {
networkSeqRecvLast[sourceNetworkNodeID] = seqID; networkSeqRecvLast[sourceNetworkNodeID] = seqID;
ackToSend = seqID; ackToSend = seqID;
//handle data //handle data - TODO: WARNING: Do not send sizeof(u16) packets or else they will get confused with this one
if(size==sizeof(u16)) {
networkConnectedMask = *((u16*) readPointer);
} else {
processPacket(readPointer, size); processPacket(readPointer, size);
}
} else if(seqID<=nextID-1) { } else if(seqID<=nextID-1) {
ackToSend = nextID-1; ackToSend = nextID-1;
} }
@ -143,6 +157,8 @@ void networkHandleSend() {
//send frame //send frame
if(currentSize>0) { if(currentSize>0) {
//TODO: Once we have our own custom mask, no longer broadcast, but send directly because bcast doesn't always reach everyone?
if(networkConnectedMask==0) {
//send frame //send frame
Result ret = udsSendTo(UDS_BROADCAST_NETWORKNODEID, NETWORK_CHANNEL, UDS_SENDFLAG_Default, networkSendBuffer+networkSendBufferStartPos, currentSize); Result ret = udsSendTo(UDS_BROADCAST_NETWORKNODEID, NETWORK_CHANNEL, UDS_SENDFLAG_Default, networkSendBuffer+networkSendBufferStartPos, currentSize);
if(UDS_CHECK_SENDTO_FATALERROR(ret)) { if(UDS_CHECK_SENDTO_FATALERROR(ret)) {
@ -150,6 +166,19 @@ void networkHandleSend() {
} else if(R_FAILED(ret)) { } else if(R_FAILED(ret)) {
//TODO: what do? //TODO: what do?
} }
} else {
for(int i=1; i<=UDS_MAXNODES; i++) {
if(i!=networkGetLocalNodeID()/* && networkIsNodeConnected(i)*/ && networkConnectedMask & (1 << (i-1))) {
//send frame
Result ret = udsSendTo(i, NETWORK_CHANNEL, UDS_SENDFLAG_Default, networkSendBuffer+networkSendBufferStartPos, currentSize);
if(UDS_CHECK_SENDTO_FATALERROR(ret)) {
//TODO: what do?
} else if(R_FAILED(ret)) {
//TODO: what do?
}
}
}
}
} }
LightLock_Unlock(&sendBufferLock); LightLock_Unlock(&sendBufferLock);
@ -160,7 +189,7 @@ void clearSendAckedBuffer() {
//find last ack recieved from all com partners //find last ack recieved from all com partners
u16 ackID = 0; u16 ackID = 0;
for(int i=1; i<=UDS_MAXNODES; i++) { for(int i=1; i<=UDS_MAXNODES; i++) {
if(i!=networkGetLocalNodeID() && networkIsNodeConnected(i)) { if(i!=networkGetLocalNodeID()/* && networkIsNodeConnected(i)*/ && networkConnectedMask & (1 << (i-1))) {
if(networkSeqSendConf[i]==0) { if(networkSeqSendConf[i]==0) {
ackID = 0; ackID = 0;
return; return;
@ -235,6 +264,7 @@ void networkInit() {
scannedNetworks = NULL; scannedNetworks = NULL;
isConnected = false; isConnected = false;
isServer = false; isServer = false;
networkConnectedMask = 0;
networkWriteBuffer = malloc(NETWORK_MAXDATASIZE); networkWriteBuffer = malloc(NETWORK_MAXDATASIZE);
if(networkWriteBuffer==NULL) { if(networkWriteBuffer==NULL) {
@ -331,9 +361,11 @@ bool networkHost() {
return false; return false;
} else { } else {
if(udsWaitConnectionStatusEvent(false, false)) {} if(udsWaitConnectionStatusEvent(false, false)) {}
udsGetConnectionStatus(&networkStatus);
udsSetNewConnectionsBlocked(false, true, false); udsSetNewConnectionsBlocked(false, true, false);
isConnected = true; isConnected = true;
isServer = true; isServer = true;
networkConnectedMask = 0;
return true; return true;
} }
} }
@ -392,8 +424,10 @@ bool networkConnect(int pos) {
return false; return false;
} else { } else {
if(udsWaitConnectionStatusEvent(false, false)) {} if(udsWaitConnectionStatusEvent(false, false)) {}
udsGetConnectionStatus(&networkStatus);
isConnected = true; isConnected = true;
isServer = false; isServer = false;
networkConnectedMask = 0;
return true; return true;
} }
} }
@ -403,18 +437,9 @@ bool networkConnect(int pos) {
void networkDisconnect() { void networkDisconnect() {
//For clients this just means disconnect, for the server it means destroy the network //For clients this just means disconnect, for the server it means destroy the network
if(udsRunning && isConnected) { if(udsRunning && isConnected) {
//TODO
if(isServer) {
//TODO: Clients need to cleanup too, how can I tell they got disconnected
udsDestroyNetwork();
} else {
udsDisconnectNetwork();
}
udsUnbind(&networkBindCtx);
isConnected = false; isConnected = false;
isServer = false;
LightLock_Lock(&sendBufferLock);
//reset send buffer //reset send buffer
networkSendBufferStartPos = 0; networkSendBufferStartPos = 0;
networkSendBufferEndPos = 0; networkSendBufferEndPos = 0;
@ -426,10 +451,38 @@ void networkDisconnect() {
networkSeqSendConf[i] = 0; networkSeqSendConf[i] = 0;
networkSeqRecvLast[i] = 0; networkSeqRecvLast[i] = 0;
} }
LightLock_Unlock(&sendBufferLock);
//With new changes citra now crashes HOST with "cannot be a router if we are not a host" when exiting game with more than 2 people
svcSleepThread(220000 * 1000); //HACK: prevent citra crash (>20*networkthreadsleep) (wait unti no more stuff gets send)
//TODO
if(isServer) {
//TODO: Clients need to cleanup too, how can I tell they got disconnected
udsDestroyNetwork();
} else {
udsDisconnectNetwork();
}
udsUnbind(&networkBindCtx);
isServer = false;
} }
} }
void networkStart() {
//TODO: This sends the node_bitmask from server to everyone else, because it is uncorrect on some clients?
if(udsRunning && isConnected && isServer) {
void *buffer = networkWriteBuffer;
*((u16*) buffer) = networkStatus.node_bitmask;
networkConnectedMask = networkStatus.node_bitmask;
networkSend(networkWriteBuffer, sizeof(u16));
networkSendWaitFlush();
}
}
bool networkConnected() { bool networkConnected() {
return isConnected; return isConnected;

View file

@ -30,6 +30,8 @@ bool networkGetScanName(char *name, int pos);
bool networkConnect(int pos); bool networkConnect(int pos);
void networkDisconnect(); void networkDisconnect();
void networkStart();
void networkUpdateStatus(); void networkUpdateStatus();
bool networkConnected(); bool networkConnected();

View file

@ -38,6 +38,8 @@ void setupGameServer() {
networkHostStopConnections(); networkHostStopConnections();
networkStart();
//send start info (seed) //send start info (seed)
size = writeStartPacket(networkWriteBuffer, rand()); size = writeStartPacket(networkWriteBuffer, rand());
networkSend(networkWriteBuffer, size); networkSend(networkWriteBuffer, size);