/// <summary> /// Process all information coming from clients, and other servers. /// </summary> /// <remarks> /// Connection Approval is enabled, so when a client connects to this server it must /// provide the correct data. That is a username and id. /// The login server gets a special case, in that its username is "lgn", and its id is Guid.Empty. /// If the master server hasn't been notified by the login server that a user is logging in, it won't /// know about this information and will reject the client. /// </remarks> public void Process() { NetIncomingMessage msg; //Read what incoming messages we have from clients while ((msg = LidgrenServer.ReadMessage()) != null) { switch (msg.MessageType) { //If it is a debug message, warning message, or status changed print the relevant information to the console case NetIncomingMessageType.DebugMessage: Console.WriteLine("Debug message: " + msg.ReadString()); break; case NetIncomingMessageType.WarningMessage: Console.WriteLine("Warning message: " + msg.ReadString()); break; case NetIncomingMessageType.StatusChanged: Console.WriteLine("Status changed for " + msg.SenderEndpoint + " to " + msg.SenderConnection.Status); break; //Check the connection approval for an accepted username and userid case NetIncomingMessageType.ConnectionApproval: //Read the username an userid from the message string username = msg.ReadString(); Guid userid = new Guid(msg.ReadBytes(msg.LengthBytes - msg.PositionInBytes)); //If the username is "lgn" and the userid is Guid.Empty, this is the login server's client. Let it connect regardless. //We should probably validate this harder in the future if (username == "lgn" && userid == Guid.Empty) { Console.WriteLine("Login accept"); msg.SenderConnection.Approve(); } //If the user with the userid and username has already been accepted by the login server //and their information has been sent here, let them be accepted. else if (Users.ContainsKey(userid) && Users[userid].Username == username) { Console.WriteLine("User: "******" accept."); Users[userid].Connection = msg.SenderConnection; msg.SenderConnection.Approve(); } //Otherwise, don't let them in here. else { Console.WriteLine("User: "******" with userid " + userid + " reject."); msg.SenderConnection.Deny(); } break; case NetIncomingMessageType.Data: //We are decrypting data. All data sent to a master server is encrypted with key "DERPHERP". msg.Decrypt(new NetXtea("DERPHERP")); //Figure out where this data came from. CallSources source = (CallSources)msg.ReadByte(); Console.WriteLine("Got data from " + source); //If we got the data from a login server if (source == CallSources.LoginServer) { //Figure out what kind of login server request it is. LoginServerRequests request = (LoginServerRequests)msg.ReadByte(); //If a user logged in, deal with it. if (request == LoginServerRequests.Login) { //Deserialize our login message from the login server LoginMessage loginmessage = new LoginMessage(); loginmessage = Serializer.Deserialize<LoginMessage>(new MemoryStream(msg.ReadBytes(msg.LengthBytes - msg.PositionInBytes))); //Create a new user with the relevant information. User u = new User(); u.Connection = msg.SenderConnection; u.Id = loginmessage.LoginUser.Id; u.Username = loginmessage.LoginUser.Username; //Add the user to our master server Users.Add(loginmessage.LoginUser.Id, u); Console.WriteLine(u.Username + " logged in."); } //If a user logged out, double deal with it. else if (request == LoginServerRequests.Logout) { //Deserialize the logout message LogoutMessage logoutmessage = new LogoutMessage(); logoutmessage = Serializer.Deserialize<LogoutMessage>(new MemoryStream(msg.ReadBytes(msg.LengthBytes - msg.PositionInBytes))); Console.WriteLine(Users[logoutmessage.UserId].Username + " logged out."); //If this user had an active character (that would be on a region server) send a message to the //region server to remove the character. if(Users[logoutmessage.UserId].ActiveCharacter != null) SendRemoveCharacterMessage(Users[logoutmessage.UserId].ActiveCharacter.RegionId, logoutmessage.UserId); //Remove the user from the master server. Users.Remove(logoutmessage.UserId); } } //If we got a message from the client else if (source == CallSources.Client) { //It is a remote procedure call, so figure out what kind it is RemoteProcedureCallCodes callcode = (RemoteProcedureCallCodes)msg.ReadByte(); //The user created a character. if (callcode == RemoteProcedureCallCodes.CreateCharacter) { //Deserialize that message CreateCharacterRequest createcharactersrequest = new CreateCharacterRequest(); createcharactersrequest = Serializer.Deserialize<CreateCharacterRequest>(new MemoryStream(msg.ReadBytes(msg.LengthBytes - msg.PositionInBytes))); //See if a character with the name requested already exists. if (!CharacterExists(createcharactersrequest.Name)) { //Create a new character with a new guid. Guid newguid = Guid.NewGuid(); //With arbitrary information about the character for now. Default regionid 0, default pos and rot, default race, height and weight. Character character = new Character(createcharactersrequest.Name, RaceCode.human, 5, 170, newguid, new Vector3(0.0f, 10.0f, 0.0f), new Vector3(0.0f, 0.0f, 0.0f), 0, new Dictionary<ulong,int>()); //Add the character to be associated with this user id. UserIdToCharacters[createcharactersrequest.UserId].Add(character); //Send a resposne to the client saying the creation was successful SendCreateCharacterResponse(msg.SenderConnection, true); Console.WriteLine("User " + Users[createcharactersrequest.UserId].Username + " created a character named " + createcharactersrequest.Name); } else { //Otherwise send a response to the client saying the creation was unsuccessful SendCreateCharacterResponse(msg.SenderConnection, false); Console.WriteLine("User " + Users[createcharactersrequest.UserId].Username + " couldn't create a character named " + createcharactersrequest.Name); } } //The user needs to get characters, so they can see which one to select else if (callcode == RemoteProcedureCallCodes.GetCharacters) { //Deserialize the get characters request GetCharactersRequest getcharactersrequest = new GetCharactersRequest(); getcharactersrequest = Serializer.Deserialize<GetCharactersRequest>(new MemoryStream(msg.ReadBytes(msg.LengthBytes - msg.PositionInBytes))); //Make sure this user has a character list started if (UserIdToCharacters.ContainsKey(getcharactersrequest.UserId)) { //If so, send the get characters response SendGetCharactersResponse(msg.SenderConnection, getcharactersrequest.UserId); } else { //Else make a new list, and send the get characters response UserIdToCharacters.Add(getcharactersrequest.UserId, new List<Character>()); SendGetCharactersResponse(msg.SenderConnection, getcharactersrequest.UserId); } Console.WriteLine("Getting Characters for " + Users[getcharactersrequest.UserId].Username); } //The user selected a character and is entering the world. else if (callcode == RemoteProcedureCallCodes.EnterWorld) { //Deserialize the enterworld request EnterWorldRequest enterworldrequest = new EnterWorldRequest(); enterworldrequest = Serializer.Deserialize<EnterWorldRequest>(new MemoryStream(msg.ReadBytes(msg.LengthBytes - msg.PositionInBytes))); //Set this users active character to the one selected. Users[enterworldrequest.UserId].ActiveCharacter = UserIdToCharacters[enterworldrequest.UserId].Find(delegate(Character c) { return c.Id == enterworldrequest.CharacterId; }); //Send an Add Character Message to the appropriate region server AddCharacterMessage(UserIdToCharacters[enterworldrequest.UserId].Find(delegate(Character c) { return c.Id == enterworldrequest.CharacterId; }), Users[enterworldrequest.UserId].ActiveCharacter.Position, null, enterworldrequest.UserId); Console.WriteLine("User " + Users[enterworldrequest.UserId].Username + " made their character " + Users[enterworldrequest.UserId].ActiveCharacter.Name + " enter the world into region " + Users[enterworldrequest.UserId].ActiveCharacter.RegionId); } else if (callcode == RemoteProcedureCallCodes.Teleport) { TeleportRequest request = Serializer.Deserialize<TeleportRequest>(new MemoryStream(msg.ReadBytes(msg.LengthBytes - msg.PositionInBytes))); TeleportMessage(Users[request.UserId].ActiveCharacter.RegionId, request.UserId, request.TeleportId); Console.WriteLine("Teleport request."); } //The client sent a character snapshot (position, rotation, velocity) else if (callcode == RemoteProcedureCallCodes.CharacterSnapshot) { CharacterSnapshot snapshot = new CharacterSnapshot(); snapshot = Serializer.Deserialize<CharacterSnapshot>(new MemoryStream(msg.ReadBytes(msg.LengthBytes - msg.PositionInBytes))); SendCharacterSnapshotMessage(Users[snapshot.UserId].ActiveCharacter.RegionId, snapshot); //Console.WriteLine("Snapshot for " + Users[snapshot.UserId].ActiveCharacter.Name); } else if (callcode == RemoteProcedureCallCodes.DropItem) { DropItemRequest request = Serializer.Deserialize<DropItemRequest>(new MemoryStream(msg.ReadBytes(msg.LengthBytes - msg.PositionInBytes))); DropItemMessage(Users[request.UserId].ActiveCharacter.RegionId, request.ItemId, request.UserId); Console.WriteLine("Drop Item request for " + Users[request.UserId].ActiveCharacter.Name); } else if (callcode == RemoteProcedureCallCodes.PickupItem) { PickupItemRequest request = Serializer.Deserialize<PickupItemRequest>(new MemoryStream(msg.ReadBytes(msg.LengthBytes - msg.PositionInBytes))); //TODO PickupItemMessage(Users[request.UserId].ActiveCharacter.RegionId, request.UserId, request.ItemSpawnId); } } break; } LidgrenServer.Recycle(msg); } //Or we recieved a message from one of the many region servers foreach (NetClient regionclient in RegionServers.Values) { NetIncomingMessage regionmessage; //Read a message from the queue while ((regionmessage = regionclient.ReadMessage()) != null) { switch (regionmessage.MessageType) { //If it is debug, warning, or status changed output to screen case NetIncomingMessageType.DebugMessage: Console.WriteLine("Region Debug: " + regionmessage.ReadString()); break; case NetIncomingMessageType.WarningMessage: Console.WriteLine("Region Warning: " + regionmessage.ReadString()); break; case NetIncomingMessageType.StatusChanged: Console.WriteLine("Region status changed: " + regionmessage.SenderConnection.Status); break; //Or we got some actual data case NetIncomingMessageType.Data: //Figure out what kind of message it is RegionMessages messagetype = (RegionMessages)regionmessage.ReadByte(); //A character was added to this region if (messagetype == RegionMessages.AddCharacterBroadcast) { Console.WriteLine("Got an Add Character broadcast from a region."); //Deserialize the broadcast AddCharacterBroadcast addbroadcast = Serializer.Deserialize<AddCharacterBroadcast>(new MemoryStream(regionmessage.ReadBytes(regionmessage.LengthBytes - regionmessage.PositionInBytes))); //Send an event to all the relevant users using their userid foreach (Guid userid in addbroadcast.RecivingUserIds) { SendEnterRegionEvent(Users[userid].Connection, addbroadcast.EnteringCharacter, addbroadcast.UserId); } } //A user asked what characters were in this region, so we relay it back via enter region response else if (messagetype == RegionMessages.AddCharacterResponse) { Console.WriteLine("Relaying characters in region as well as position."); AddCharacterResponseMessage message = Serializer.Deserialize<AddCharacterResponseMessage>(new MemoryStream(regionmessage.ReadBytes(regionmessage.LengthBytes - regionmessage.PositionInBytes))); Console.WriteLine(message.Location.X + " " + message.Location.Y + " " + message.Location.Z); SendEnterRegionResponse(Users[message.MeantForUserId].Connection, message.Characters, message.ItemSpawns, message.Location, message.RegionId); } //A character was removed from this region else if (messagetype == RegionMessages.RemoveCharacterBroadcast) { Console.WriteLine("Got a Remove Character broadcast from a region."); //Deserialize the broadcast RemoveCharacterBroadcast exitregionbroadcast = Serializer.Deserialize<RemoveCharacterBroadcast>(new MemoryStream(regionmessage.ReadBytes(regionmessage.LengthBytes - regionmessage.PositionInBytes))); //Send it to all relevant user ids foreach (Guid userid in exitregionbroadcast.RecivingUserIds) { SendExitRegionEvent(Users[userid].Connection, exitregionbroadcast.UserId); } } //A character sent a snapshot of their information to the region else if (messagetype == RegionMessages.CharacterSnapshotBroadcast) { Console.WriteLine("Got a character snapshot broadcast from a region."); CharacterSnapshotBroadcast charsnapbroadcast = Serializer.Deserialize<CharacterSnapshotBroadcast>(new MemoryStream(regionmessage.ReadBytes(regionmessage.LengthBytes - regionmessage.PositionInBytes))); //Send the event to all relevant users foreach (Guid userid in charsnapbroadcast.ReceivingUserIds) SendCharacterSnapshotEvent(Users[userid].Connection, charsnapbroadcast.Snapshot); } else if (messagetype == RegionMessages.TeleportCharacterResponse) { TeleportResponseMessage message = Serializer.Deserialize<TeleportResponseMessage>(new MemoryStream(regionmessage.ReadBytes(regionmessage.LengthBytes - regionmessage.PositionInBytes))); Users[message.UserId].ActiveCharacter.RegionId = message.ExitRegionId; Console.WriteLine("Got teleport character response, and adding character."); AddCharacterMessage(Users[message.UserId].ActiveCharacter, null, message.TeleportExitId, message.UserId); } else if (messagetype == RegionMessages.DropItemResponse) { DropItemResponseMessage message = Serializer.Deserialize<DropItemResponseMessage>(new MemoryStream(regionmessage.ReadBytes(regionmessage.LengthBytes - regionmessage.PositionInBytes))); SendDropItemResponse(Users[message.UserId].Connection, message.Success, message.ItemId); } else if(messagetype == RegionMessages.DropItemBroadcast) { DropItemBroadcast broadcast = Serializer.Deserialize<DropItemBroadcast>(new MemoryStream(regionmessage.ReadBytes(regionmessage.LengthBytes - regionmessage.PositionInBytes))); foreach (Guid userid in broadcast.ReceivingUserIds) { SendCreateItemSpawnEvent(Users[userid].Connection, broadcast.NewItemSpawn); } } else if(messagetype == RegionMessages.PickupItemResponse) { PickupItemResponseMessage message = Serializer.Deserialize<PickupItemResponseMessage>(new MemoryStream(regionmessage.ReadBytes(regionmessage.LengthBytes - regionmessage.PositionInBytes))); SendTakeItemResponse(Users[message.UserId].Connection, message.Success, message.ItemId); } else if(messagetype == RegionMessages.PickupItemBroadcast) { PickupItemBroadcast broadcast = Serializer.Deserialize<PickupItemBroadcast>(new MemoryStream(regionmessage.ReadBytes(regionmessage.LengthBytes - regionmessage.PositionInBytes))); foreach(Guid userid in broadcast.Recipients) { SendTakeItemEvent(Users[userid].Connection, broadcast.ItemSpawnId); } } else if (messagetype == RegionMessages.SpawnItemBroadcast) { SpawnItemBroadcast broadcast = Serializer.Deserialize<SpawnItemBroadcast>(new MemoryStream(regionmessage.ReadBytes(regionmessage.LengthBytes - regionmessage.PositionInBytes))); foreach(Guid userid in broadcast.Recipients) { SendSpawnItemEvent(Users[userid].Connection, broadcast.SpawnId, broadcast.ItemId); } } break; } LidgrenServer.Recycle(regionmessage); } } }
/// <summary> /// Sends a logout to the master server connected to th userid. /// </summary> /// <param name="guid">User id of the user that is logging out.</param> private void SendLogoutToMasterServer(Guid guid) { LogoutMessage logoutmessage = new LogoutMessage(guid); NetOutgoingMessage messagetomaster = MasterServerConnections[(int)idtomasterserver[guid]].CreateMessage(); messagetomaster.Write((byte)CallSources.LoginServer); messagetomaster.Write((byte)LoginServerRequests.Logout); messagetomaster.Write(Serialize(logoutmessage)); messagetomaster.Encrypt(new NetXtea("DERPHERP")); MasterServerConnections[(int)idtomasterserver[guid]].SendMessage(messagetomaster, NetDeliveryMethod.ReliableOrdered); }