public MSCPacket(MenuState s) { this.ptype = PacketType.MSC; this.addHeader(ptype); this.addContent(s.getPacketData()); this.finalize(); }
/// <summary> /// Event handler for when the Play Game menu entry is selected. /// </summary> void StartGameMenuEntrySelected(object sender, PlayerInputEventArgs e) { if (e.MenuAccept) // Handle character selection and game starting { if (!characterSelectionsLocked[playerId]) // Unlock a player { characterSelectionsLocked[playerId] = true; if (multiplayer) // Only broadcast in multiplayer mode { if (host) // Broadcast lock changes to all players { HostBroadcastLocks(); } else // Inform the host of a lock change { MenuState lockPacket = new MenuState(MenuState.Type.LockCharacter, playerId, (int)MenuState.LockCharacterDetails.Locked); ((ProjectSkyCrane)ScreenManager.Game).RawClient.sendMSC(lockPacket); } } } else if (host && AllLocked()) { if (multiplayer) // Only broadcast in multiplayer mode { HostBroadcastGameStart(); } LoadingScreen.Load(ScreenManager, false, new GameplayScreen(host, multiplayer, NumConnectedPlayers(), playerId, characterSelections, playerIdToConnectionHash)); } menuSelectSoundEffect.Play(); } else if (!characterSelectionsLocked[playerId] && e.ToggleDirection != 0) // Do some toggling of character selections { characterSelections[playerId] += e.ToggleDirection; if (characterSelections[playerId] < 0) { characterSelections[playerId] = (PlayerCharacter.Type)(characters.Length - 1); } else if ((int)characterSelections[playerId] >= characters.Length) { characterSelections[playerId] = 0; } if (multiplayer) // Only broadcast in multiplayer mode { if (host) // Broadcast sprite changes to all players { HostBroadcastSprites(); } else // Inform the host of a sprite change { MenuState spritePacket = new MenuState(MenuState.Type.SelectCharacter, playerId, (int)characterSelections[playerId]); ((ProjectSkyCrane)ScreenManager.Game).RawClient.sendMSC(spritePacket); } } menuScrollSoundEffect.Play(); } return; }
/// <summary> /// Have the host broadcast which characters are and aren't connected. /// </summary> private void HostBroadcastSprites() { MenuState spriteBroadcast = new MenuState(MenuState.Type.SelectCharacter); for (int i = 0; i < playersConnected.Length; i += 1) // Loop over and broadcast the sprites of all connected players { if (playersConnected[i]) { spriteBroadcast.PlayerId = i; spriteBroadcast.EventDetail = (int)characterSelections[i]; ((ProjectSkyCrane)ScreenManager.Game).RawServer.broadcastMSC(spriteBroadcast); } } return; }
/// <summary> /// Have the host broadcast which characters are and aren't locked. /// </summary> private void HostBroadcastLocks() { MenuState lockedBroadcast = new MenuState(MenuState.Type.LockCharacter); for (int i = 0; i < playersConnected.Length; i += 1) // Loop over and broadcast the locks of all connected players { if (playersConnected[i]) { lockedBroadcast.PlayerId = i; if (characterSelectionsLocked[i]) { lockedBroadcast.EventDetail = (int)MenuState.LockCharacterDetails.Locked; } else { lockedBroadcast.EventDetail = (int)MenuState.LockCharacterDetails.Unlocked; } ((ProjectSkyCrane)ScreenManager.Game).RawServer.broadcastMSC(lockedBroadcast); } } return; }
/// <summary> /// Have the host broadcast that the game has started. /// </summary> private void HostBroadcastGameStart() { MenuState startBroadcast = new MenuState(MenuState.Type.GameStart); for (int i = 0; i < playersConnected.Length; i += 1) // Loop over and inform everyone the game is beginning { if (playersConnected[i]) { ((ProjectSkyCrane)ScreenManager.Game).RawServer.broadcastMSC(startBroadcast); } } return; }
/// <summary> /// Have the host broadcast which players are and aren't connected. /// </summary> private void HostBroadcastConnected() { MenuState connectBroadcast = new MenuState(MenuState.Type.Connect); for (int i = 0; i < playersConnected.Length; i += 1) { connectBroadcast.PlayerId = i; if (playersConnected[i]) // Broadcast 1 to show connected { connectBroadcast.EventDetail = (int)MenuState.ConnectionDetails.Connected; } else // Broadcast -1 to show not connected { connectBroadcast.EventDetail = (int)MenuState.ConnectionDetails.Disconnected; } ((ProjectSkyCrane)ScreenManager.Game).RawServer.broadcastMSC(connectBroadcast); } return; }
/// <summary> /// A player has hit cancel while browsing characters. /// </summary> protected override void OnCancel() { if (!characterSelectionsLocked[playerId]) { if (multiplayer) // Only broadcast in multiplayer mode { playersConnected[playerId] = false; if (host) // Broadcast disconnect of host to all players { HostBroadcastConnected(); } else // Inform the host of a disconnect { MenuState disconnectPacket = new MenuState(MenuState.Type.Connect, playerId, (int)MenuState.ConnectionDetails.Disconnected); ((ProjectSkyCrane)ScreenManager.Game).RawClient.sendMSC(disconnectPacket); } } base.OnCancel(); } else // Unlock a character selection { characterSelectionsLocked[playerId] = false; if (multiplayer) // Only broadcast in multiplayer mode { if (host) // Broadcast lock changes to all players { HostBroadcastLocks(); } else // Inform the host of a lock change { MenuState unlockPacket = new MenuState(MenuState.Type.LockCharacter, playerId, (int)MenuState.LockCharacterDetails.Unlocked); ((ProjectSkyCrane)ScreenManager.Game).RawClient.sendMSC(unlockPacket); } } } return; }
/// <summary> /// Run a regular update loop on the menu. /// </summary> public override void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen) { if (multiplayer) // Don't handle these cases in single player { if (host) // Have the host search for incoming client packets and respond to them { List<Tuple<ConnectionID, MenuState>> serverStates = ((ProjectSkyCrane)ScreenManager.Game).RawServer.getMSC(); for (int i = 0; i < serverStates.Count; i++) { switch (serverStates[i].Item2.MenuType) { case MenuState.Type.Connect: // Deal with connection and disconnections from the server if (serverStates[i].Item2.EventDetail == (int)MenuState.ConnectionDetails.IdReqest) // Someone is requesting an id { int newId; if (connectionToPlayerIdHash.ContainsKey(serverStates[i].Item1.ID)) // We've already seen this player and they haven't disconnected, resend their current id { newId = connectionToPlayerIdHash[serverStates[i].Item1.ID]; } else // Send the player a new id { newId = hostIds.Dequeue(); playersConnected[newId] = true; connectionToPlayerIdHash.Add(serverStates[i].Item1.ID, newId); playerIdToConnectionHash.Add(newId, serverStates[i].Item1); } MenuState connectResponse = new MenuState(MenuState.Type.Connect, newId, (int)MenuState.ConnectionDetails.IdReqest); // Inform connector of their Id ((ProjectSkyCrane)ScreenManager.Game).RawServer.signalMSC(connectResponse, serverStates[i].Item1); HostBroadcastConnected(); HostBroadcastSprites(); HostBroadcastLocks(); } else if (serverStates[i].Item2.EventDetail == (int)MenuState.ConnectionDetails.Disconnected) // Someone is disconnecting { if (connectionToPlayerIdHash.ContainsKey(serverStates[i].Item1.ID)) // This is a known player based on their connection { int requestingId = connectionToPlayerIdHash[serverStates[i].Item1.ID]; if (requestingId == serverStates[i].Item2.PlayerId) // Prevent spoofing and sillyness { playersConnected[requestingId] = false; connectionToPlayerIdHash.Remove(serverStates[i].Item1.ID); // Remove connections from both hashes playerIdToConnectionHash.Remove(requestingId); hostIds.Enqueue(requestingId); // Allow the id to be re-used HostBroadcastConnected(); } } } break; case MenuState.Type.SelectCharacter: if (connectionToPlayerIdHash.ContainsKey(serverStates[i].Item1.ID)) // This is a known player based on their connection { int requestingId = connectionToPlayerIdHash[serverStates[i].Item1.ID]; if (requestingId == serverStates[i].Item2.PlayerId) // Prevent spoofing and sillyness { characterSelections[requestingId] = (PlayerCharacter.Type)serverStates[i].Item2.EventDetail; HostBroadcastSprites(); } } break; case MenuState.Type.LockCharacter: if (connectionToPlayerIdHash.ContainsKey(serverStates[i].Item1.ID)) // Check for a known player based on connection { int requestingId = connectionToPlayerIdHash[serverStates[i].Item1.ID]; if (requestingId == serverStates[i].Item2.PlayerId) // Prevent spoofing and sillyness { if (serverStates[i].Item2.EventDetail == (int)MenuState.LockCharacterDetails.Locked) // Locking a character in { characterSelectionsLocked[requestingId] = true; } else if (serverStates[i].Item2.EventDetail == (int)MenuState.LockCharacterDetails.Unlocked) // Unlocking a character { characterSelectionsLocked[requestingId] = false; } HostBroadcastLocks(); } } break; case MenuState.Type.GameStart: // Don't do anything in this case, it's clearly a silly request break; default: throw new ArgumentException(); } } } else // Handle authoritative updates from the server if we are a client { List<MenuState> clientStates = ((ProjectSkyCrane)ScreenManager.Game).RawClient.rcvMenuState(); for (int i = 0; i < clientStates.Count; i++) { switch (clientStates[i].MenuType) { case MenuState.Type.Connect: // Handle connection events if (clientStates[i].EventDetail == (int)MenuState.ConnectionDetails.IdReqest) // Assign our own player id { playerId = clientStates[i].PlayerId; } else if (clientStates[i].EventDetail == (int)MenuState.ConnectionDetails.Connected) // Assign a connected player { playersConnected[clientStates[i].PlayerId] = true; } else if (clientStates[i].EventDetail == (int)MenuState.ConnectionDetails.Disconnected) // Note down that a player is no longer in the session { playersConnected[clientStates[i].PlayerId] = false; // TODO: Handle the server disconnecting } break; case MenuState.Type.SelectCharacter: // Handle character selection characterSelections[clientStates[i].PlayerId] = (PlayerCharacter.Type)clientStates[i].EventDetail; break; case MenuState.Type.LockCharacter: // Handle character locking if (clientStates[i].EventDetail == (int)MenuState.LockCharacterDetails.Locked) { characterSelectionsLocked[clientStates[i].PlayerId] = true; } else if (clientStates[i].EventDetail == (int)MenuState.LockCharacterDetails.Unlocked) { characterSelectionsLocked[clientStates[i].PlayerId] = false; } break; case MenuState.Type.GameStart: LoadingScreen.Load(ScreenManager, false, new GameplayScreen(host, multiplayer, NumConnectedPlayers(), playerId, characterSelections, null)); break; default: throw new ArgumentException(); } } } } base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen); return; }
/// <summary> /// Loads graphics content for this screen. This uses the shared ContentManager /// provided by the Game class, so the content will remain loaded forever. /// Whenever a subsequent MessageBoxScreen tries to load this same content, /// it will just get back another reference to the already loaded data. /// </summary> public override void LoadContent() { if (!host && playerId < 0) // If we're not the host, ask for an id { MenuState connectPacket = new MenuState(MenuState.Type.Connect, 0, (int)MenuState.ConnectionDetails.IdReqest); ((ProjectSkyCrane)ScreenManager.Game).RawClient.sendMSC(connectPacket); playerId = -1; } ContentManager content = ScreenManager.Game.Content; // Dynamically load character types based on enum Array characterTypes = Enum.GetValues(typeof(PlayerCharacter.Type)); characters = new Texture2D[characterTypes.Length]; for (int i = 0; i < characters.Length; i += 1) { characters[i] = content.Load<Texture2D>("Sprites/" + characterTypes.GetValue(i)); } aButtonTextured2D = content.Load<Texture2D>("XBox Buttons/button_a"); bButtonTextured2D = content.Load<Texture2D>("XBox Buttons/button_b"); dPadLeftTexture2D = content.Load<Texture2D>("XBox Buttons/dpad_left"); dPadRightTexture2D = content.Load<Texture2D>("XBox Buttons/dpad_right"); base.LoadContent(); return; }
public void broadcastMSC(MenuState m) { foreach (KeyValuePair<IPEndPoint, ConnectionID> d in connections) { //Console.WriteLine("Server - Sent MenuState to: " + d.Value.ID); MSCPacket p = new MSCPacket(m); p.Dest = d.Key; this.nw.commitPacket(p); } return; }
private void runThis() { Packet p; while (this.go) { p = nw.getNext(); if (p == null) { foreach (IPEndPoint ep in connections.Keys) { SYNCPacket ps = new SYNCPacket(); ps.Dest = ep; this.nw.commitPacket(ps); } continue; } //Console.WriteLine(p.ptype); switch (p.ptype) { case Packet.PacketType.HANDSHAKE: if (!connections.ContainsKey(p.Dest)) { Console.WriteLine("Server - New connection from: " + p.Dest); connections[p.Dest] = new ConnectionID(p.Dest); Console.WriteLine("Server - Added Connection: " + connections[p.Dest].ID); HandshakePacket hs = new HandshakePacket(); hs.Dest = p.Dest; nw.commitPacket(hs); } break; case Packet.PacketType.STC: //Console.WriteLine("Server - Receivd State Change from client... who do they think they are?"); Environment.Exit(1); break; case Packet.PacketType.SYNC: if (connections.ContainsKey(p.Dest)) { //Console.WriteLine("Server - SYNC Reply from: " + connections[p.Dest].ID); } else { Console.WriteLine("Server - ERROR Unregistered SYNC"); } break; case Packet.PacketType.PING: if (connections.ContainsKey(p.Dest)) { //Console.WriteLine("Server - Ping from connection: " + connections[p.Dest].ID); PingPacket ps = new PingPacket(); ps.Dest = p.Dest; nw.commitPacket(ps); //ACK the ping } else { Console.WriteLine("Server ERROR - Unregistered PING"); } break; case Packet.PacketType.CMD: //Actually handle this //Console.WriteLine("Server - Got CMD from: " + connections[p.Dest].ID); Command cmd = new Command(p.data); lock (commandQ) this.commandQ.Add(cmd); break; case Packet.PacketType.MSC: //Actually handle this //Console.WriteLine("Server - Got MSC from: " + connections[p.Dest].ID); MenuState msc = new MenuState(p.data); if (connections.ContainsKey(p.Dest)) { ConnectionID cid = connections[p.Dest]; Tuple<ConnectionID, MenuState> newMQ = new Tuple<ConnectionID, MenuState>(cid, msc); lock (mscQ) this.mscQ.Enqueue(newMQ); } break; } this.globalStats.rcvdPkts++; } }
public void signalMSC(MenuState m, ConnectionID cid) { MSCPacket p = new MSCPacket(m); p.Dest = cid.endpt; nw.commitPacket(p); }
//Main routine, this does all the processing private void ClientstartFunc() { // Hold here until the server information has been provided ready.WaitOne(); // Event Loop // Pull packets out of the network layer and handle them while (this.go) { Packet newPacket = nw.getNext(); // This is a blocking call! // Handle timeout if (newPacket == null) { Console.WriteLine("Timeout on receive"); switch (curState) { case cState.TRYCONNECT: // Did not receive the expected HANDSHAKE message // Restart the handshake this.handshake(); break; case cState.CONNECTED: // The server may have died, ping the server to find out //this.pingServer(); //TODO Should probably not silently ignore this.... lock (this) { if (this.sw_ping.IsRunning) { //this.curState = cState.DISCONNECTED; this.sw_ping.Stop(); this.lastPing = 501; } } break; case cState.DISCONNECTED: default: // This should not happen, die screaming! Environment.Exit(1); break; } } else { //Console.Write("Received packet of type: "); //Console.WriteLine(newPacket.ptype); // Handle the new packet switch (newPacket.ptype) { case Packet.PacketType.CMD: Console.WriteLine("Should not be getting CMD packets from the server..."); Environment.Exit(1); break; case Packet.PacketType.HANDSHAKE: Console.WriteLine("Handshake received from the server"); switch (curState) { case cState.TRYCONNECT: // The connection has succeeded! this.startPing(); this.curState = cState.CONNECTED; break; case cState.CONNECTED: // Repeat? This can be ignored ( I hope...) break; case cState.DISCONNECTED: default: // This should not happen, die screaming! Environment.Exit(1); break; } break; case Packet.PacketType.STC: //Console.WriteLine("STC received from the server"); switch (curState) { case cState.TRYCONNECT: break; case cState.CONNECTED: // Marshall the state change packet into an object StateChange newSTC = new StateChange(newPacket.data); // Add the state change object to the buffer for the UI lock (this.buffer) { buffer.Enqueue(newSTC); } break; case cState.DISCONNECTED: default: // This should not happen, die screaming! Environment.Exit(1); break; } break; case Packet.PacketType.MSC: //Console.WriteLine("MSC received from the server"); switch (curState) { case cState.TRYCONNECT: break; case cState.CONNECTED: // Marshall the state change packet into an object MenuState newMSC = new MenuState(newPacket.data); // Add the state change object to the buffer for the UI lock (this.menuBuffer) { menuBuffer.Enqueue(newMSC); } break; case cState.DISCONNECTED: default: // This should not happen, die screaming! Environment.Exit(1); break; } break; case Packet.PacketType.SYNC: //Console.WriteLine("SYNC received from the server"); switch (curState) { case cState.TRYCONNECT: break; case cState.CONNECTED: syncServer(); break; case cState.DISCONNECTED: default: // This should not happen, die screaming! Environment.Exit(1); break; } break; case Packet.PacketType.PING: //Console.WriteLine("PING received from the server"); switch (curState) { case cState.TRYCONNECT: break; case cState.CONNECTED: lock (this) { sw_ping.Stop(); this.lastPing = sw_ping.ElapsedMilliseconds; } //Console.WriteLine("Ping"+lastPing); break; case cState.DISCONNECTED: default: // This should not happen, die screaming! Environment.Exit(1); break; } break; default: Console.WriteLine("Unknown packet type from the server..."); Environment.Exit(1); break; } } } }
public void sendMSC(MenuState m) { // Create the MSC Packet MSCPacket newMSC = new MSCPacket(m); newMSC.Dest = server; // Add the MSC packe to the network worker's send queue this.nw.commitPacket(newMSC); }