public virtual void ServerRead(ClientNetObject type, IReadMessage msg, Client c) { if (GameMain.Server == null) { return; } switch (type) { case ClientNetObject.CHARACTER_INPUT: if (c.Character != this) { #if DEBUG DebugConsole.Log("Received a character update message from a client who's not controlling the character"); #endif return; } UInt16 networkUpdateID = msg.ReadUInt16(); byte inputCount = msg.ReadByte(); if (AllowInput) { Enabled = true; } for (int i = 0; i < inputCount; i++) { InputNetFlags newInput = (InputNetFlags)msg.ReadRangedInteger(0, (int)InputNetFlags.MaxVal); UInt16 newAim = 0; UInt16 newInteract = 0; if (newInput != InputNetFlags.None && newInput != InputNetFlags.FacingLeft) { c.KickAFKTimer = 0.0f; } else if (AnimController.Dir < 0.0f != newInput.HasFlag(InputNetFlags.FacingLeft)) { //character changed the direction they're facing c.KickAFKTimer = 0.0f; } newAim = msg.ReadUInt16(); if (newInput.HasFlag(InputNetFlags.Select) || newInput.HasFlag(InputNetFlags.Deselect) || newInput.HasFlag(InputNetFlags.Use) || newInput.HasFlag(InputNetFlags.Health) || newInput.HasFlag(InputNetFlags.Grab)) { newInteract = msg.ReadUInt16(); } if (NetIdUtils.IdMoreRecent((ushort)(networkUpdateID - i), LastNetworkUpdateID) && (i < 60)) { if ((i > 0 && memInput[i - 1].intAim != newAim)) { c.KickAFKTimer = 0.0f; } NetInputMem newMem = new NetInputMem { states = newInput, intAim = newAim, interact = newInteract, networkUpdateID = (ushort)(networkUpdateID - i) }; memInput.Insert(i, newMem); LastInputTime = Timing.TotalTime; } } if (NetIdUtils.IdMoreRecent(networkUpdateID, LastNetworkUpdateID)) { LastNetworkUpdateID = networkUpdateID; } else if (NetIdUtils.Difference(networkUpdateID, LastNetworkUpdateID) > 500) { #if DEBUG || UNSTABLE DebugConsole.AddWarning($"Large disrepancy between a client character's network update ID server-side and client-side (client: {networkUpdateID}, server: {LastNetworkUpdateID}). Resetting the ID."); #endif LastNetworkUpdateID = networkUpdateID; } if (memInput.Count > 60) { //deleting inputs from the queue here means the server is way behind and data needs to be dropped //we'll make the server drop down to 30 inputs for good measure memInput.RemoveRange(30, memInput.Count - 30); } break; case ClientNetObject.ENTITY_STATE: int eventType = msg.ReadRangedInteger(0, 4); switch (eventType) { case 0: Inventory.ServerRead(type, msg, c); break; case 1: bool doingCPR = msg.ReadBoolean(); if (c.Character != this) { #if DEBUG DebugConsole.Log("Received a character update message from a client who's not controlling the character"); #endif return; } AnimController.Anim = doingCPR ? AnimController.Animation.CPR : AnimController.Animation.None; break; case 2: if (c.Character != this) { #if DEBUG DebugConsole.Log("Received a character update message from a client who's not controlling the character"); #endif return; } if (IsIncapacitated) { var causeOfDeath = CharacterHealth.GetCauseOfDeath(); Kill(causeOfDeath.type, causeOfDeath.affliction); } break; case 3: // NetEntityEvent.Type.UpdateTalents if (c.Character != this) { #if DEBUG DebugConsole.Log("Received a character update message from a client who's not controlling the character"); #endif return; } // get the full list of talents from the player, only give the ones // that are not already given (or otherwise not viable) ushort talentCount = msg.ReadUInt16(); List <string> talentSelection = new List <string>(); for (int i = 0; i < talentCount; i++) { UInt32 talentIdentifier = msg.ReadUInt32(); var prefab = TalentPrefab.TalentPrefabs.Find(p => p.UIntIdentifier == talentIdentifier); if (prefab != null) { talentSelection.Add(prefab.Identifier); } } talentSelection = TalentTree.CheckTalentSelection(this, talentSelection); foreach (string talent in talentSelection) { GiveTalent(talent); } break; } break; } msg.ReadPadBits(); }
public virtual void ServerRead(ClientNetObject type, NetBuffer msg, Client c) { if (GameMain.Server == null) { return; } switch (type) { case ClientNetObject.CHARACTER_INPUT: if (c.Character != this) { #if DEBUG DebugConsole.Log("Received a character update message from a client who's not controlling the character"); #endif return; } UInt16 networkUpdateID = msg.ReadUInt16(); byte inputCount = msg.ReadByte(); if (AllowInput) { Enabled = true; } for (int i = 0; i < inputCount; i++) { InputNetFlags newInput = (InputNetFlags)msg.ReadRangedInteger(0, (int)InputNetFlags.MaxVal); UInt16 newAim = 0; UInt16 newInteract = 0; if (newInput != InputNetFlags.None && newInput != InputNetFlags.FacingLeft) { c.KickAFKTimer = 0.0f; } else if (AnimController.Dir < 0.0f != newInput.HasFlag(InputNetFlags.FacingLeft)) { //character changed the direction they're facing c.KickAFKTimer = 0.0f; } newAim = msg.ReadUInt16(); if (newInput.HasFlag(InputNetFlags.Select) || newInput.HasFlag(InputNetFlags.Deselect) || newInput.HasFlag(InputNetFlags.Use) || newInput.HasFlag(InputNetFlags.Health) || newInput.HasFlag(InputNetFlags.Grab)) { newInteract = msg.ReadUInt16(); } if (NetIdUtils.IdMoreRecent((ushort)(networkUpdateID - i), LastNetworkUpdateID) && (i < 60)) { if ((i > 0 && memInput[i - 1].intAim != newAim)) { c.KickAFKTimer = 0.0f; } NetInputMem newMem = new NetInputMem { states = newInput, intAim = newAim, interact = newInteract, networkUpdateID = (ushort)(networkUpdateID - i) }; memInput.Insert(i, newMem); LastInputTime = Timing.TotalTime; } } if (NetIdUtils.IdMoreRecent(networkUpdateID, LastNetworkUpdateID)) { LastNetworkUpdateID = networkUpdateID; } if (memInput.Count > 60) { //deleting inputs from the queue here means the server is way behind and data needs to be dropped //we'll make the server drop down to 30 inputs for good measure memInput.RemoveRange(30, memInput.Count - 30); } break; case ClientNetObject.ENTITY_STATE: int eventType = msg.ReadRangedInteger(0, 3); switch (eventType) { case 0: Inventory.ServerRead(type, msg, c); break; case 1: bool doingCPR = msg.ReadBoolean(); if (c.Character != this) { #if DEBUG DebugConsole.Log("Received a character update message from a client who's not controlling the character"); #endif return; } AnimController.Anim = doingCPR ? AnimController.Animation.CPR : AnimController.Animation.None; break; case 2: if (c.Character != this) { #if DEBUG DebugConsole.Log("Received a character update message from a client who's not controlling the character"); #endif return; } if (IsUnconscious) { var causeOfDeath = CharacterHealth.GetCauseOfDeath(); Kill(causeOfDeath.First, causeOfDeath.Second); } break; } break; } msg.ReadPadBits(); }
partial void UpdateNetInput() { if (GameMain.Client != null) { if (this != Controlled) { if (GameMain.Client.EndCinematic != null) // Freezes the characters during the ending cinematic { AnimController.Frozen = true; memState.Clear(); return; } //freeze AI characters if more than 1 seconds have passed since last update from the server if (lastRecvPositionUpdateTime < Lidgren.Network.NetTime.Now - 1.0f) { AnimController.Frozen = true; memState.Clear(); //hide after 2 seconds if (lastRecvPositionUpdateTime < Lidgren.Network.NetTime.Now - 2.0f) { Enabled = false; return; } } } else { var posInfo = new CharacterStateInfo( SimPosition, AnimController.Collider.Rotation, LastNetworkUpdateID, AnimController.TargetDir, SelectedCharacter, SelectedConstruction, AnimController.Anim); memLocalState.Add(posInfo); InputNetFlags newInput = InputNetFlags.None; if (IsKeyDown(InputType.Left)) { newInput |= InputNetFlags.Left; } if (IsKeyDown(InputType.Right)) { newInput |= InputNetFlags.Right; } if (IsKeyDown(InputType.Up)) { newInput |= InputNetFlags.Up; } if (IsKeyDown(InputType.Down)) { newInput |= InputNetFlags.Down; } if (IsKeyDown(InputType.Run)) { newInput |= InputNetFlags.Run; } if (IsKeyDown(InputType.Crouch)) { newInput |= InputNetFlags.Crouch; } if (IsKeyHit(InputType.Select)) { newInput |= InputNetFlags.Select; //TODO: clean up the way this input is registered } if (IsKeyHit(InputType.Deselect)) { newInput |= InputNetFlags.Deselect; } if (IsKeyHit(InputType.Health)) { newInput |= InputNetFlags.Health; } if (IsKeyHit(InputType.Grab)) { newInput |= InputNetFlags.Grab; } if (IsKeyDown(InputType.Use)) { newInput |= InputNetFlags.Use; } if (IsKeyDown(InputType.Aim)) { newInput |= InputNetFlags.Aim; } if (IsKeyDown(InputType.Shoot)) { newInput |= InputNetFlags.Shoot; } if (IsKeyDown(InputType.Attack)) { newInput |= InputNetFlags.Attack; } if (IsKeyDown(InputType.Ragdoll)) { newInput |= InputNetFlags.Ragdoll; } if (AnimController.TargetDir == Direction.Left) { newInput |= InputNetFlags.FacingLeft; } Vector2 relativeCursorPos = cursorPosition - AimRefPosition; relativeCursorPos.Normalize(); UInt16 intAngle = (UInt16)(65535.0 * Math.Atan2(relativeCursorPos.Y, relativeCursorPos.X) / (2.0 * Math.PI)); NetInputMem newMem = new NetInputMem { states = newInput, intAim = intAngle }; if (focusedItem != null && !CharacterInventory.DraggingItemToWorld && (!newMem.states.HasFlag(InputNetFlags.Grab) && !newMem.states.HasFlag(InputNetFlags.Health))) { newMem.interact = focusedItem.ID; } else if (focusedCharacter != null) { newMem.interact = focusedCharacter.ID; } memInput.Insert(0, newMem); LastNetworkUpdateID++; if (memInput.Count > 60) { memInput.RemoveRange(60, memInput.Count - 60); } } } else //this == Character.Controlled && GameMain.Client == null { AnimController.Frozen = false; } }
public virtual void ServerRead(ClientNetObject type, NetBuffer msg, Client c) { if (GameMain.Server == null) { return; } switch (type) { case ClientNetObject.CHARACTER_INPUT: if (c.Character != this) { #if DEBUG DebugConsole.Log("Received a character update message from a client who's not controlling the character"); #endif return; } UInt16 networkUpdateID = msg.ReadUInt16(); byte inputCount = msg.ReadByte(); try { if (AllowInput) { Enabled = true; } } catch (NullReferenceException e) { DebugConsole.NewMessage("Critical error occured in CHARACTERNETWORKING.SERVERREAD - Failiure to enable character to due error: " + e.Message, Color.Red); DebugConsole.NewMessage("Character: " + Name + " Has been removed to prevent server crash (Hopefully!)", Color.Red); GameMain.Server.ServerLog.WriteLine("Critical error occured in CHARACTERNETWORKING.SERVERREAD - Failiure to enable character to due error: " + e.Message, ServerLog.MessageType.Error); GameMain.Server.ServerLog.WriteLine("Character: " + Name + " Has been removed to prevent server crash (Hopefully!)", ServerLog.MessageType.Error); #if CLIENT if (this == Character.controlled) { Character.controlled = null; } #endif Enabled = false; Entity.Spawner.AddToRemoveQueue(this); } for (int i = 0; i < inputCount; i++) { InputNetFlags newInput = (InputNetFlags)msg.ReadRangedInteger(0, (int)InputNetFlags.MaxVal); UInt16 newAim = 0; UInt16 newInteract = 0; if (newInput.HasFlag(InputNetFlags.Aim)) { newAim = msg.ReadUInt16(); } if (newInput.HasFlag(InputNetFlags.Select) || newInput.HasFlag(InputNetFlags.Use)) { newInteract = msg.ReadUInt16(); } /* * if (GameMain.NilMod.DisconnectedCharacters.Count > 0) * { * DisconnectedCharacter disconnectedcharcheck = GameMain.NilMod.DisconnectedCharacters.Find(dc => dc.character.Name == c.Name && c.Connection.RemoteEndPoint.Address.ToString() == dc.IPAddress); * * if (disconnectedcharcheck != null) * { * if (!disconnectedcharcheck.character.IsDead) * { * SetStun(Math.Min(disconnectedcharcheck.DisconnectStun + GameMain.NilMod.ReconnectAddStun, 60f), true, false, true); * GameMain.NilMod.DisconnectedCharacters.Remove(disconnectedcharcheck); * * var chatMsg = ChatMessage.Create( * "", * ("You have been reconnected to your character - However as a penalty you have taken " + Math.Round(GameMain.NilMod.ReconnectAddStun, 1).ToString() + " seconds stun on top of your original stun.\n"), * (ChatMessageType)ChatMessageType.Server, * null); * * GameMain.Server.SendChatMessage(chatMsg, c); * break; * } * else * { * SetStun(0f, true, true, true); * GameMain.NilMod.DisconnectedCharacters.Remove(disconnectedcharcheck); * * var chatMsg = ChatMessage.Create( * "", * ("You have been reconnected to your character - However while you were gone your character has been killed.\n"), * (ChatMessageType)ChatMessageType.Server, * null); * * GameMain.Server.SendChatMessage(chatMsg, c); * } * } * } */ //if (AllowInput) //{ if (NetIdUtils.IdMoreRecent((ushort)(networkUpdateID - i), LastNetworkUpdateID) && (i < 60)) { NetInputMem newMem = new NetInputMem(); newMem.states = newInput; newMem.intAim = newAim; newMem.interact = newInteract; newMem.networkUpdateID = (ushort)(networkUpdateID - i); memInput.Insert(i, newMem); } else if (LastNetworkUpdateID >= (networkUpdateID + 40)) { while (LastNetworkUpdateID >= (networkUpdateID + 40)) { LastNetworkUpdateID -= 30; } } //} } if (NetIdUtils.IdMoreRecent(networkUpdateID, LastNetworkUpdateID)) { LastNetworkUpdateID = networkUpdateID; } if (memInput.Count > 60) { //deleting inputs from the queue here means the server is way behind and data needs to be dropped //we'll make the server drop down to 30 inputs for good measure memInput.RemoveRange(30, memInput.Count - 30); } break; case ClientNetObject.ENTITY_STATE: int eventType = msg.ReadRangedInteger(0, 3); switch (eventType) { case 0: inventory.ServerRead(type, msg, c); break; case 1: bool doingCPR = msg.ReadBoolean(); if (c.Character != this) { #if DEBUG DebugConsole.Log("Received a character update message from a client who's not controlling the character"); #endif return; } AnimController.Anim = doingCPR ? AnimController.Animation.CPR : AnimController.Animation.None; break; case 2: if (c.Character != this) { #if DEBUG DebugConsole.Log("Received a character update message from a client who's not controlling the character"); #endif return; } if (IsUnconscious) { Kill(lastAttackCauseOfDeath, false, true); } break; case 3: LimbType grabLimb = (LimbType)msg.ReadByte(); if (c.Character != this) { #if DEBUG DebugConsole.Log("Received a character update message from a client who's not controlling the character"); #endif return; } AnimController.GrabLimb = grabLimb; break; } break; } msg.ReadPadBits(); }
private void UpdateNetInput() { if (this != Character.Controlled) { if (GameMain.Client != null) { //freeze AI characters if more than 1 seconds have passed since last update from the server if (lastRecvPositionUpdateTime < NetTime.Now - 1.0f) { AnimController.Frozen = true; memState.Clear(); //hide after 2 seconds if (lastRecvPositionUpdateTime < NetTime.Now - 2.0f) { Enabled = false; return; } } } else if (GameMain.Server != null && (!(this is AICharacter) || IsRemotePlayer)) { if (!AllowInput) { AnimController.Frozen = false; if (memInput.Count > 0) { prevDequeuedInput = dequeuedInput; dequeuedInput = memInput[memInput.Count - 1].states; memInput.RemoveAt(memInput.Count - 1); } } else if (memInput.Count == 0) { AnimController.Frozen = true; } else { AnimController.Frozen = false; prevDequeuedInput = dequeuedInput; LastProcessedID = memInput[memInput.Count - 1].networkUpdateID; dequeuedInput = memInput[memInput.Count - 1].states; double aimAngle = ((double)memInput[memInput.Count - 1].intAim / 65535.0) * 2.0 * Math.PI; cursorPosition = (ViewTarget == null ? AnimController.AimSourcePos : ViewTarget.Position) + new Vector2((float)Math.Cos(aimAngle), (float)Math.Sin(aimAngle)) * 60.0f; //reset focus when attempting to use/select something if (memInput[memInput.Count - 1].states.HasFlag(InputNetFlags.Use) || memInput[memInput.Count - 1].states.HasFlag(InputNetFlags.Select)) { focusedItem = null; focusedCharacter = null; } var closestEntity = FindEntityByID(memInput[memInput.Count - 1].interact); if (closestEntity is Item) { if (CanInteractWith((Item)closestEntity)) { focusedItem = (Item)closestEntity; focusedCharacter = null; } } else if (closestEntity is Character) { if (CanInteractWith((Character)closestEntity)) { focusedCharacter = (Character)closestEntity; focusedItem = null; } } memInput.RemoveAt(memInput.Count - 1); TransformCursorPos(); if ((dequeuedInput == InputNetFlags.None || dequeuedInput == InputNetFlags.FacingLeft) && Math.Abs(AnimController.Collider.LinearVelocity.X) < 0.005f && Math.Abs(AnimController.Collider.LinearVelocity.Y) < 0.2f) { while (memInput.Count > 5 && memInput[memInput.Count - 1].states == dequeuedInput) { //remove inputs where the player is not moving at all //helps the server catch up, shouldn't affect final position LastProcessedID = memInput[memInput.Count - 1].networkUpdateID; memInput.RemoveAt(memInput.Count - 1); } } } } } else if (GameMain.Client != null) { var posInfo = new CharacterStateInfo( SimPosition, AnimController.Collider.Rotation, LastNetworkUpdateID, AnimController.TargetDir, SelectedCharacter == null ? (Entity)selectedConstruction : (Entity)SelectedCharacter, AnimController.Anim); memLocalState.Add(posInfo); InputNetFlags newInput = InputNetFlags.None; if (IsKeyDown(InputType.Left)) { newInput |= InputNetFlags.Left; } if (IsKeyDown(InputType.Right)) { newInput |= InputNetFlags.Right; } if (IsKeyDown(InputType.Up)) { newInput |= InputNetFlags.Up; } if (IsKeyDown(InputType.Down)) { newInput |= InputNetFlags.Down; } if (IsKeyDown(InputType.Run)) { newInput |= InputNetFlags.Run; } if (IsKeyDown(InputType.Crouch)) { newInput |= InputNetFlags.Crouch; } if (IsKeyHit(InputType.Select)) { newInput |= InputNetFlags.Select; //TODO: clean up the way this input is registered } if (IsKeyDown(InputType.Use)) { newInput |= InputNetFlags.Use; } if (IsKeyDown(InputType.Aim)) { newInput |= InputNetFlags.Aim; } if (IsKeyDown(InputType.Attack)) { newInput |= InputNetFlags.Attack; } if (IsKeyDown(InputType.Ragdoll)) { newInput |= InputNetFlags.Ragdoll; } if (AnimController.TargetDir == Direction.Left) { newInput |= InputNetFlags.FacingLeft; } Vector2 relativeCursorPos = cursorPosition - (ViewTarget == null ? AnimController.AimSourcePos : ViewTarget.Position); relativeCursorPos.Normalize(); UInt16 intAngle = (UInt16)(65535.0 * Math.Atan2(relativeCursorPos.Y, relativeCursorPos.X) / (2.0 * Math.PI)); NetInputMem newMem = new NetInputMem(); newMem.states = newInput; newMem.intAim = intAngle; if (focusedItem != null) { newMem.interact = focusedItem.ID; } else if (focusedCharacter != null) { newMem.interact = focusedCharacter.ID; } memInput.Insert(0, newMem); LastNetworkUpdateID++; if (memInput.Count > 60) { memInput.RemoveRange(60, memInput.Count - 60); } } else //this == Character.Controlled && GameMain.Client == null { AnimController.Frozen = false; } if (networkUpdateSent) { foreach (Key key in keys) { key.DequeueHit(); key.DequeueHeld(); } networkUpdateSent = false; } }
public virtual void ServerRead(ClientNetObject type, NetBuffer msg, Client c) { if (GameMain.Server == null) { return; } switch (type) { case ClientNetObject.CHARACTER_INPUT: if (c.Character != this) { #if DEBUG DebugConsole.Log("Received a character update message from a client who's not controlling the character"); #endif return; } UInt16 networkUpdateID = msg.ReadUInt16(); byte inputCount = msg.ReadByte(); if (AllowInput) { Enabled = true; } for (int i = 0; i < inputCount; i++) { InputNetFlags newInput = (InputNetFlags)msg.ReadRangedInteger(0, (int)InputNetFlags.MaxVal); UInt16 newAim = 0; UInt16 newInteract = 0; if (newInput.HasFlag(InputNetFlags.Aim)) { newAim = msg.ReadUInt16(); } if (newInput.HasFlag(InputNetFlags.Select) || newInput.HasFlag(InputNetFlags.Use)) { newInteract = msg.ReadUInt16(); } if (AllowInput) { if (NetIdUtils.IdMoreRecent((ushort)(networkUpdateID - i), LastNetworkUpdateID) && (i < 60)) { NetInputMem newMem = new NetInputMem(); newMem.states = newInput; newMem.intAim = newAim; newMem.interact = newInteract; newMem.networkUpdateID = (ushort)(networkUpdateID - i); memInput.Insert(i, newMem); } } } if (NetIdUtils.IdMoreRecent(networkUpdateID, LastNetworkUpdateID)) { LastNetworkUpdateID = networkUpdateID; } if (memInput.Count > 60) { //deleting inputs from the queue here means the server is way behind and data needs to be dropped //we'll make the server drop down to 30 inputs for good measure memInput.RemoveRange(30, memInput.Count - 30); } break; case ClientNetObject.ENTITY_STATE: int eventType = msg.ReadRangedInteger(0, 2); switch (eventType) { case 0: inventory.ServerRead(type, msg, c); break; case 1: if (c.Character != this) { #if DEBUG DebugConsole.Log("Received a character update message from a client who's not controlling the character"); #endif return; } bool doingCPR = msg.ReadBoolean(); AnimController.Anim = doingCPR ? AnimController.Animation.CPR : AnimController.Animation.None; break; case 2: if (c.Character != this) { #if DEBUG DebugConsole.Log("Received a character update message from a client who's not controlling the character"); #endif return; } if (IsUnconscious) { Kill(lastAttackCauseOfDeath); } break; } msg.ReadPadBits(); break; } }