public void CheckAndProcessMessage(ClientConnection client, dynamic message) { //TODO: why don't these work? //Contract.Requires<ArgumentNullException>(client != null); //Contract.Requires<ArgumentNullException>(message != null); // new connection... only allow login); if (!client.Authenticated && !(message is Login)) { _log.Warn("Non-login message " + message.GetType() + " from " + client.RemoteEndPoint); return; } if (client.Avatar == null && !(message is PossessMobile || message is RequestPossessable || message is Logout || message is Login)) { _log.Warn("ERROR: Non-posses message " + message.GetType() + " from " + client.RemoteEndPoint); return; } try { ProcessMessage(client, message); _log.Trace("Processed message " + message); } catch { _log.Warn("Unable to process message " + message); } }
public static void ProcessUseSkill(ClientConnection client, UseSkill message) { var avatar = client.Avatar as MobileAvatar; if (avatar == null) { client.LogMessage("Requested a skill, but doesn't have an avatar."); return; } Schema.EnumSkillRow esr = Global.ModelSchema.EnumSkill.FindByEnumSkillID(message.SkillId); if (esr == null) { client.LogMessage("Requested an invalid skill " + message.SkillId); return; } // If already performing a skill invocation, just queue the request for later. if (avatar.ActivatingSkill != null) { avatar.SkillQueue.Enqueue(message); return; } if (esr.LeadTime <= 0) { // process it now UseSkillNow(avatar, message); } else { // process it later, after lead-time has elapsed avatar.ActivatingSkill = message; avatar.ActivatingSkillTimestamp = Global.Now; avatar.ActivatingSkillLeadTime = TimeSpan.FromSeconds(esr.LeadTime); } }
public static void ProcessUseSkill(this World world, ClientConnection client, UseSkill message) { var source = client.Avatar as CombatantModel; if (source == null) { client.LogMessage("Requested a skill without an avatar."); return; } Schema.EnumSkillRow esr = Global.Schema.EnumSkill.FindByEnumSkillID((int)message.Skill); if (esr == null) { client.LogMessage("Requested an invalid skill " + message.Skill); return; } EntityModel target; switch ((EnumTargetType)esr.EnumTargetTypeID) { case EnumTargetType.TargetSelf: target = source; break; case EnumTargetType.TargetMobile: if (message.TargetPhysicalObjectIDs.Length == 0) { world.LogMessage(source, "No target specified, this skill may only be used on Mobiles."); return; } target = world.History.Head.Entities.ValueOrDefault(message.TargetPhysicalObjectIDs[0]); if (target == null) { world.LogMessage(source, "Target " + message.TargetPhysicalObjectIDs[0] + " not found."); return; } break; default: world.LogMessage(source, "That skill has an unsupported target type " + esr.EnumTargetTypeID); Log.Error("Unhandled target type " + esr.EnumTargetTypeID + " for skill " + esr.EnumSkillID + " " + esr.EnumSkillName); return; } if (source.ActivatingSkill != EnumSkill.None) // queue the request for later. world.Apply(new EntityUpdateEvent( source.EnqueueSkill(message.Skill, target), "Enqueuing Skill " + message.Skill)); else if (esr.LeadTime <= 0) // process it now world.UseSkillNow(source, esr, target); else // process it later, after lead-time has elapsed world.Apply(new EntityUpdateEvent( source.StartSkill(message.Skill, target, Global.Now, TimeSpan.FromSeconds(esr.LeadTime)), "Activating Skill " + message.Skill)); }
public static void ProcessCancelSkill(this World world, ClientConnection client, CancelSkill message) { var avatar = client.Avatar as CombatantModel; if (avatar == null) { client.LogMessage("Canceled a skill invocation, but don't have an avatar."); return; } // If already performing invocation, just cancel it bool found = false; if (avatar.ActivatingSkill != EnumSkill.None) // TODO: //&& avatar.ActivatingSkill.InvokationId == message.InvokationId) { world.Apply(new EntityUpdateEvent(avatar.StartSkill(EnumSkill.None, null, Global.Now, TimeSpan.FromSeconds(0)), "Started using skill")); found = true; } else { // TODO: search for it in queued skill invocations // just generate a new queue with the invocation missing /* var newQueue = new Queue<UseSkill>(); foreach (UseSkill m in avatar.SkillQueue) { if (m.InvokationId == message.InvokationId) { // don't add it found = true; } else newQueue.Enqueue(m); } avatar.SkillQueue = newQueue; */ avatar.EmptyQueue(); } if (found) client.LogMessage("Successfully canceled invocation " + message.InvokationId); else client.LogMessage("Failed to cancel invocation " + message.InvokationId); }
void ProcessMessage(ClientConnection client, Login loginMessage) { if (World.UserLookup(loginMessage.Username, loginMessage.Password)) { // login succeeded, check there is not an existing connection for this player ClientConnection current; if (World.Users.TryGetValue(loginMessage.Username, out current)) current.Close(); _log.Info("User " + loginMessage.Username + " logged in"); client.AuthenticatedUsername = loginMessage.Username; World.Users.Add(loginMessage.Username, client); } else { _log.Info("Login failed for username '" + loginMessage.Username + "'"); client.Close(); } }
public static void ProcessCancelSkill(ClientConnection client, CancelSkill message) { var avatar = client.Avatar as MobileAvatar; if (avatar == null) { client.LogMessage("Canceled a skill invocation, but don't have an avatar."); return; } // If already performing invocation, just cancel it bool found = false; if (avatar.ActivatingSkill != null && avatar.ActivatingSkill.InvokationId == message.InvokationId) { avatar.ActivatingSkill = null; found = true; } else { // search for it in queued skill invocations // just generate a new queue with the invocation missing var newQueue = new Queue<UseSkill>(); foreach (UseSkill m in avatar.SkillQueue) { if (m.InvokationId == message.InvokationId) { // don't add it found = true; } else newQueue.Enqueue(m); } avatar.SkillQueue = newQueue; } if (found) client.LogMessage("Successfully canceled invocation " + message.InvokationId); else client.LogMessage("Failed to cancel invocation " + message.InvokationId); }
public void SendPartyTalk(ClientConnection client, string party, string message) { // TODO: which name to use? var name = client.Avatar == null ? client.AuthenticatedUsername : client.Avatar.Name; // TODO: can probably simplify this HashSet<string> members; if (Party.TryGetValue(party, out members)) { foreach (var m in members) { ClientConnection cc; if (Users.TryGetValue(m, out cc)) cc.Communication(name, message, Strive.Network.Messages.CommunicationType.PartyTalk); } } }
/// <summary> /// if a new client has entered the world, /// notify them about surrounding physical objects /// this routine will send the client mobile's /// position as one of the 'nearby' mobiles. /// </summary> public void SendInitialWorldView(ClientConnection client) { client.Send(Weather); // TODO: Just subscribe them to the cubes instead? //foreach (EntityModel p in GetNearby(client.Avatar)) //client.Send(p); }
public void SendPartyTalk(ClientConnection client, string message) { string party; if (InParty.TryGetValue(client, out party)) SendPartyTalk(client, party, message); }
void ProcessMessage(ClientConnection client, TransferPartyLeadership message) { var avatar = client.Avatar; ClientConnection target; if (!World.Users.TryGetValue(message.Leader, out target)) { client.LogMessage("Invalid target"); return; } if (client.AuthenticatedUsername == message.Leader) { client.LogMessage("You are already the leader"); return; } HashSet<string> party; if (!World.Party.TryGetValue(client.AuthenticatedUsername, out party)) { client.LogMessage("You are not the leader of a party"); return; } // TODO: use character names instead of username?? if (!party.Contains(message.Leader)) { client.LogMessage(message.Leader + " is not in your party"); return; } World.TransferLeadership(client.AuthenticatedUsername, message.Leader); World.SendPartyTalk(client, "Party leadership has been transferred to " + message.Leader); }
void ProcessMessage(ClientConnection client, MyPosition message) { var avatar = client.Avatar; if (avatar == null) { client.LogMessage("Position message sent, but have no avatar."); return; } if (message.Position != avatar.Position) World.Apply(new EntityUpdateEvent( avatar.Move(message.MobileState, message.Position, message.Rotation, Global.Now), "Player movement")); }
public static void AcceptCallback(IAsyncResult ar) { try { // Get the socket that handles the client request. var listener = (Listener)ar.AsyncState; lock (listener) { if (listener._tcpSocket == null) return; Socket socket; try { socket = listener._tcpSocket.EndAccept(ar); } catch (ArgumentException) { // TODO: hmmm I really wish there was a nicer way // this is the result of a previous binding, we discard it return; } // Create the state object. var client = new ClientConnection(); client.Start(socket); listener.Clients.Add(client); listener._log.Info("New connection from " + client.RemoteEndPoint); // The next connection listener._tcpSocket.BeginAccept( new AsyncCallback(AcceptCallback), listener); } } catch (ObjectDisposedException) { // the underlying socket was closed } }
void ProcessMessage(ClientConnection client, PossessMobile message) { var avatar = World.History.Head.Entities.ValueOrDefault(message.InstanceId); if (avatar != null) { // reconnected, replace existing connection with the new ClientConnection possessedBy; if (World.Possession.TryGetValue(avatar.Id, out possessedBy)) { if (possessedBy == client) { client.LogMessage("You already possess " + avatar); return; } else { _log.Info("Mobile " + avatar + " has been taken over by " + client); possessedBy.LogMessage("You lost control of " + avatar); possessedBy.Avatar = null; } } if (client.Avatar != null && client.Avatar.Id != avatar.Id) { // TODO: omg releasing this sends a combatant which crashes // release control of previous avatar //World.Possession.Remove(client.Avatar.Id); } World.Possession[avatar.Id] = client; client.Avatar = avatar; client.LogMessage("You are now controlling " + avatar); } else { // try to load the character avatar = World.LoadMobile(message.InstanceId); if (avatar == null) { _log.Warn("Character " + message.InstanceId + " not found."); //TODO: rely on world loading //client.Close(); //return; avatar = new CombatantModel( Global.Rand.Next(), client.AuthenticatedUsername, "RTSRobot", new Vector3D(), Quaternion.Identity, 100, 100, Common.EnumMobileState.Standing, 1.7f, 20, 20, 20, 20, 20); } World.Possession[avatar.Id] = client; client.Avatar = avatar; // try to add the character to the world World.Apply(new EntityUpdateEvent(avatar, "Loaded for possession")); } World.SendInitialWorldView(client); }
void ProcessMessage(ClientConnection client, CreateMission c) { // TODO: would like to at least set the id // ObjectInstanceId = Global.Rand.Next(), World.Apply(new MissionUpdateEvent(c.Mission, "Created by " + client.AuthenticatedUsername)); }
void ProcessMessage(ClientConnection client, ReloadWorld message) { _log.Info("ReloadWorld received."); World.Load(); foreach (ClientConnection c in Listener.Clients .Where(c => c.Avatar != null && c.Status == ConnectionStatus.Connected)) { // re-spawn their mobile c.DropAll(); ProcessMessage(c, new PossessMobile(c.Avatar.Id)); } }
void ProcessMessage(ClientConnection client, InviteToParty message) { if (World.Party[client.AuthenticatedUsername] == null) { client.LogMessage("You are not the leader of a party"); return; } var target = World.Users[message.User]; if (target == null) client.LogMessage("Invalid target"); else { World.InvitedToParty[target.AuthenticatedUsername] .Add(client.AuthenticatedUsername, Global.Now); // TODO: probably want a graphical thing or something for invites target.LogMessage("You have been invited to party '" + client.AuthenticatedUsername + "'"); } }
void ProcessMessage(ClientConnection client, RequestSkillList message) { client.SkillList( Global.Schema.EnumSkill .Select(e => Global.Schema.MobileHasSkill.FindByTemplateObjectIDEnumSkillID( client.Avatar.Id, (int)e.EnumSkillID)) .Where(mhs => mhs != null) .Select(mhs => new Tuple<int, double>(mhs.EnumSkillID, mhs.Rating)) .ToArray()); }
void ProcessMessage(ClientConnection client, JoinParty message) { Dictionary<string, DateTime> invitation; if (!World.InvitedToParty.TryGetValue(client.AuthenticatedUsername, out invitation)) { client.LogMessage("You are not currently invited to join a party"); return; } // make sure they are trying to join the party they were invited to if (!invitation.ContainsKey(message.Leader)) { client.LogMessage("You are not currently invited to join " + message.Leader); return; } HashSet<string> party; if (!World.Party.TryGetValue(message.Leader, out party)) { client.LogMessage("That party does not exist anymore"); return; } World.SendPartyTalk(client, message.Leader, client.Avatar.Name + " has joined your "); party.Add(client.AuthenticatedUsername); client.LogMessage("You are now in party '" + message.Leader + "'."); //World.InvitedToParty.Remove(message.Leader); }
void ProcessMessage(ClientConnection client, LeaveParty message) { World.LeaveParty(client, client.AuthenticatedUsername); client.LogMessage("You have left party"); }
void ProcessMessage(ClientConnection client, Pong message) { client.Latency = (DateTime.Now - client.PingedAt).Milliseconds; World.Weather.Latency = client.Latency; client.Send(World.Weather); }
public void LeaveParty(ClientConnection client, string member) { var followers = Party[member]; if (followers != null && followers.Count > 0) TransferLeadership(member, followers.First()); followers.Remove(member); InParty[client] = null; // TODO: which name to use? SendPartyTalk(client, member + " has left your party"); }
void ProcessMessage(ClientConnection client, Logout message) { if (client.Avatar != null) { // remove from world. // TODO: do I want to remove the avatar? // World.Remove((EntityModel)client.Avatar); } _log.Info("Logged out '" + client.AuthenticatedUsername + "'."); client.Close(); }
internal void RemoveClient(ClientConnection client) { HashSet<string> party; if (Party.TryGetValue(client.AuthenticatedUsername, out party)) TransferLeadership(client.AuthenticatedUsername, party.First()); Users.Remove(client.AuthenticatedUsername); }
void ProcessMessage(ClientConnection client, CancelSkill message) { World.ProcessCancelSkill(client, message); }
public void SendInitialWorldView(ClientConnection client) { // if a new client has entered the world, // notify them about surrounding physical objects // NB: this routine will send the client mobile's // position as one of the 'nearby' mobiles. // TODO: figure out how to make client.Avatar the right type var mob = (MobileAvatar)client.Avatar; client.Send(Weather); // TODO: zomg I don't know if this divtruncate is right int squareX = DivTruncate((int)(mob.Position.X - _lowX), Square.SquareSize); int squareZ = DivTruncate((int)(mob.Position.Z - _lowZ), Square.SquareSize); int i, j; var nearbyPhysicalObjects = new List<PhysicalObject>(); // TODO: use xorder, zorder to descide the resolution? for (i = -1; i <= 1; i++) { for (j = -1; j <= 1; j++) { // check that neighbor exists if (squareX + i < 0 || squareX + i >= _squaresInX || squareZ + j < 0 || squareZ + j >= _squaresInZ || _square[squareX + i, squareZ + j] == null) continue; // add all neighboring physical objects // to the clients world view // that are in scope /** TODO: * could only send based upon a radius, but this makes * relocations harder... maybe be better to just use squares // NB: using Manhattan distance not Cartesian float distx = Math.Abs(p.Position.X - mob.Position.X); float distz = Math.Abs(p.Position.Z - mob.Position.Z); if ( distx <= Constants.objectScopeRadius && distz <= Constants.objectScopeRadius ) */ nearbyPhysicalObjects.AddRange( _square[squareX + i, squareZ + j].PhysicalObjects); } } /* ToClient.AddPhysicalObjects message = new ToClient.AddPhysicalObjects( nearbyPhysicalObjects ); client.Send( message ); */ foreach (PhysicalObject p in nearbyPhysicalObjects) client.Send(ToClient.AddPhysicalObject.CreateMessage(p)); for (int k = 0; k < Constants.TerrainZoomOrder; k++) { int tbx = DivTruncate((int)mob.Position.X, Constants.TerrainPieceSize) - Constants.xRadius[k]; int tbz = DivTruncate((int)mob.Position.Z, Constants.TerrainPieceSize) - Constants.zRadius[k]; // Normalize to a 'grid' point tbx = DivTruncate(tbx, Constants.scale[k]) * Constants.scale[k]; tbz = DivTruncate(tbz, Constants.scale[k]) * Constants.scale[k]; for (i = 0; i <= Constants.xRadius[k] * 2; i += Constants.scale[k]) { for (j = 0; j <= Constants.zRadius[k] * 2; j += Constants.scale[k]) { int tx = tbx + i; int tz = tbz + j; int terrainX = tx - (int)_lowX / Constants.TerrainPieceSize; int terrainZ = tz - (int)_lowZ / Constants.TerrainPieceSize; if (terrainX >= 0 && terrainX < _squaresInX * Square.SquareSize / Constants.TerrainPieceSize && terrainZ >= 0 && terrainZ < _squaresInZ * Square.SquareSize / Constants.TerrainPieceSize) { Terrain t = _terrain[terrainX, terrainZ]; if (t != null) { if (// there is no higher zoom order k == (Constants.TerrainZoomOrder - 1) // this is not a higher order point || (tx % Constants.scale[k + 1]) != 0 || (tz % Constants.scale[k + 1]) != 0) client.Send(ToClient.AddPhysicalObject.CreateMessage(t)); } } } } } }
void ProcessMessage(ClientConnection client, Communicate message) { // TODO: chat as character or user? string name = client.Avatar == null ? client.AuthenticatedUsername : client.Avatar.Name; if (message.CommunicationType == CommunicationType.Chat) World.SendToUsers(new Network.Messages.ToClient.Communication( name, message.Message, message.CommunicationType)); else if (message.CommunicationType == CommunicationType.PartyTalk) World.SendPartyTalk(client, message.Message); else _log.Error("Unexpected CommunicationType " + message.CommunicationType); }
void ProcessMessage(ClientConnection client, ProduceEntity p) { var factory = World.History.Head.Entities.ValueOrDefault(p.FactoryId); if (factory == null) { client.LogMessage("Could not find factory " + p.FactoryId); return; } World.Apply(new ProductionStartedEvent( factory.Id, p.Id, client.AuthenticatedUsername + " producing " + p.Name + " from " + factory)); }
void ProcessMessage(ClientConnection client, RequestWhoList message) { client.WhoList( Listener.Clients .Select(c => c.Avatar) .Except(null) .Select(a => new Tuple<int, string>(a.Id, a.Name)) .ToArray()); }
void ProcessMessage(ClientConnection client, UseSkill message) { World.ProcessUseSkill(client, message); }
void ProcessMessage(ClientConnection client, RequestPossessable message) { //Strive.Data.MultiverseFactory.refreshMultiverseForPlayer(Global.modelSchema, client.PlayerID); client.CanPossess(GetPossessable(client.AuthenticatedUsername)); }