public OrderMessageInfo(int orderIndex, Order orderPrefab, string orderOption, int?orderOptionIndex, Character targetCharacter, Order.OrderTargetType targetType, Entity targetEntity, OrderTarget targetPosition, int?wallSectionIndex, int orderPriority) { OrderIndex = orderIndex; OrderPrefab = orderPrefab; OrderOption = orderOption; OrderOptionIndex = orderOptionIndex; TargetCharacter = targetCharacter; TargetType = targetType; TargetEntity = targetEntity; TargetPosition = targetPosition; WallSectionIndex = wallSectionIndex; Priority = orderPriority; }
public static void ServerRead(IReadMessage msg, Client c) { c.KickAFKTimer = 0.0f; UInt16 ID = msg.ReadUInt16(); ChatMessageType type = (ChatMessageType)msg.ReadByte(); string txt; Character orderTargetCharacter = null; Entity orderTargetEntity = null; OrderChatMessage orderMsg = null; OrderTarget orderTargetPosition = null; Order.OrderTargetType orderTargetType = Order.OrderTargetType.Entity; int?wallSectionIndex = null; if (type == ChatMessageType.Order) { var orderMessageInfo = OrderChatMessage.ReadOrder(msg); if (orderMessageInfo.OrderIndex < 0 || orderMessageInfo.OrderIndex >= Order.PrefabList.Count) { DebugConsole.ThrowError($"Invalid order message from client \"{c.Name}\" - order index out of bounds ({orderMessageInfo.OrderIndex})."); if (NetIdUtils.IdMoreRecent(ID, c.LastSentChatMsgID)) { c.LastSentChatMsgID = ID; } return; } orderTargetCharacter = orderMessageInfo.TargetCharacter; orderTargetEntity = orderMessageInfo.TargetEntity; orderTargetPosition = orderMessageInfo.TargetPosition; orderTargetType = orderMessageInfo.TargetType; wallSectionIndex = orderMessageInfo.WallSectionIndex; var orderPrefab = orderMessageInfo.OrderPrefab ?? Order.PrefabList[orderMessageInfo.OrderIndex]; string orderOption = orderMessageInfo.OrderOption ?? (orderMessageInfo.OrderOptionIndex == null || orderMessageInfo.OrderOptionIndex < 0 || orderMessageInfo.OrderOptionIndex >= orderPrefab.Options.Length ? "" : orderPrefab.Options[orderMessageInfo.OrderOptionIndex.Value]); orderMsg = new OrderChatMessage(orderPrefab, orderOption, orderMessageInfo.Priority, orderTargetPosition ?? orderTargetEntity as ISpatialEntity, orderTargetCharacter, c.Character) { WallSectionIndex = wallSectionIndex }; txt = orderMsg.Text; } else { txt = msg.ReadString() ?? ""; } if (!NetIdUtils.IdMoreRecent(ID, c.LastSentChatMsgID)) { return; } c.LastSentChatMsgID = ID; if (txt.Length > MaxLength) { txt = txt.Substring(0, MaxLength); } c.LastSentChatMessages.Add(txt); if (c.LastSentChatMessages.Count > 10) { c.LastSentChatMessages.RemoveRange(0, c.LastSentChatMessages.Count - 10); } float similarity = 0.0f; for (int i = 0; i < c.LastSentChatMessages.Count; i++) { float closeFactor = 1.0f / (c.LastSentChatMessages.Count - i); if (string.IsNullOrEmpty(txt)) { similarity += closeFactor; } else { int levenshteinDist = ToolBox.LevenshteinDistance(txt, c.LastSentChatMessages[i]); similarity += Math.Max((txt.Length - levenshteinDist) / (float)txt.Length * closeFactor, 0.0f); } } //order/report messages can be sent a little faster than normal messages without triggering the spam filter if (orderMsg != null) { similarity *= 0.25f; } bool isOwner = GameMain.Server.OwnerConnection != null && c.Connection == GameMain.Server.OwnerConnection; if (similarity + c.ChatSpamSpeed > 5.0f && !isOwner) { GameMain.Server.KarmaManager.OnSpamFilterTriggered(c); c.ChatSpamCount++; if (c.ChatSpamCount > 3) { //kick for spamming too much GameMain.Server.KickClient(c, TextManager.Get("SpamFilterKicked")); } else { ChatMessage denyMsg = Create("", TextManager.Get("SpamFilterBlocked"), ChatMessageType.Server, null); c.ChatSpamTimer = 10.0f; GameMain.Server.SendDirectChatMessage(denyMsg, c); } return; } c.ChatSpamSpeed += similarity + 0.5f; if (c.ChatSpamTimer > 0.0f && !isOwner) { ChatMessage denyMsg = Create("", TextManager.Get("SpamFilterBlocked"), ChatMessageType.Server, null); c.ChatSpamTimer = 10.0f; GameMain.Server.SendDirectChatMessage(denyMsg, c); return; } var should = GameMain.Lua.hook.Call("chatMessage", new DynValue[] { DynValue.NewString(txt), UserData.Create(c) }); if (should != null) { if (should.CastToBool()) { return; } else { } } if (type == ChatMessageType.Order) { if (c.Character == null || c.Character.SpeechImpediment >= 100.0f || c.Character.IsDead) { return; } if (orderMsg.Order.IsReport) { HumanAIController.ReportProblem(orderMsg.Sender, orderMsg.Order); } Order order = orderTargetType switch { Order.OrderTargetType.Entity => new Order(orderMsg.Order, orderTargetEntity, orderMsg.Order?.GetTargetItemComponent(orderTargetEntity as Item), orderGiver: orderMsg.Sender), Order.OrderTargetType.Position => new Order(orderMsg.Order, orderTargetPosition, orderGiver: orderMsg.Sender), Order.OrderTargetType.WallSection when orderTargetEntity is Structure s && wallSectionIndex.HasValue => new Order(orderMsg.Order, s, wallSectionIndex, orderGiver: orderMsg.Sender), _ => throw new NotImplementedException() }; if (order != null) { if (order.TargetAllCharacters) { if (order.IsIgnoreOrder) { switch (orderTargetType) { case Order.OrderTargetType.Entity: if (!(orderTargetEntity is IIgnorable ignorableEntity)) { break; } ignorableEntity.OrderedToBeIgnored = order.Identifier == "ignorethis"; break; case Order.OrderTargetType.Position: throw new NotImplementedException(); case Order.OrderTargetType.WallSection: if (!wallSectionIndex.HasValue) { break; } if (!(orderTargetEntity is Structure s)) { break; } if (!(s.GetSection(wallSectionIndex.Value) is IIgnorable ignorableWall)) { break; } ignorableWall.OrderedToBeIgnored = order.Identifier == "ignorethis"; break; } } GameMain.GameSession?.CrewManager?.AddOrder(order, order.IsIgnoreOrder ? (float?)null : order.FadeOutTime); } else if (orderTargetCharacter != null) { orderTargetCharacter.SetOrder(order, orderMsg.OrderOption, orderMsg.OrderPriority, orderMsg.Sender); } } GameMain.Server.SendOrderChatMessage(orderMsg); } else { GameMain.Server.SendChatMessage(txt, null, c); } }
public static void ClientRead(IReadMessage msg) { UInt16 id = msg.ReadUInt16(); ChatMessageType type = (ChatMessageType)msg.ReadByte(); PlayerConnectionChangeType changeType = PlayerConnectionChangeType.None; string txt = ""; string styleSetting = string.Empty; if (type != ChatMessageType.Order) { changeType = (PlayerConnectionChangeType)msg.ReadByte(); txt = msg.ReadString(); } string senderName = msg.ReadString(); Character senderCharacter = null; Client senderClient = null; bool hasSenderClient = msg.ReadBoolean(); if (hasSenderClient) { UInt64 clientId = msg.ReadUInt64(); senderClient = GameMain.Client.ConnectedClients.Find(c => c.SteamID == clientId || c.ID == clientId); if (senderClient != null) { senderName = senderClient.Name; } } bool hasSenderCharacter = msg.ReadBoolean(); if (hasSenderCharacter) { senderCharacter = Entity.FindEntityByID(msg.ReadUInt16()) as Character; if (senderCharacter != null) { senderName = senderCharacter.Name; } } msg.ReadPadBits(); switch (type) { case ChatMessageType.Default: break; case ChatMessageType.Order: int orderIndex = msg.ReadByte(); UInt16 targetCharacterID = msg.ReadUInt16(); Character targetCharacter = Entity.FindEntityByID(targetCharacterID) as Character; Entity targetEntity = Entity.FindEntityByID(msg.ReadUInt16()); Order orderPrefab = null; int? optionIndex = null; string orderOption = null; // The option of a Dismiss order is written differently so we know what order we target // now that the game supports multiple current orders simultaneously if (orderIndex >= 0 && orderIndex < Order.PrefabList.Count) { orderPrefab = Order.PrefabList[orderIndex]; if (orderPrefab.Identifier != "dismissed") { optionIndex = msg.ReadByte(); } // Does the dismiss order have a specified target? else if (msg.ReadBoolean()) { int identifierCount = msg.ReadByte(); if (identifierCount > 0) { int dismissedOrderIndex = msg.ReadByte(); Order dismissedOrderPrefab = null; if (dismissedOrderIndex >= 0 && dismissedOrderIndex < Order.PrefabList.Count) { dismissedOrderPrefab = Order.PrefabList[dismissedOrderIndex]; orderOption = dismissedOrderPrefab.Identifier; } if (identifierCount > 1) { int dismissedOrderOptionIndex = msg.ReadByte(); if (dismissedOrderPrefab != null) { var options = dismissedOrderPrefab.Options; if (options != null && dismissedOrderOptionIndex >= 0 && dismissedOrderOptionIndex < options.Length) { orderOption += $".{options[dismissedOrderOptionIndex]}"; } } } } } } else { optionIndex = msg.ReadByte(); } int orderPriority = msg.ReadByte(); OrderTarget orderTargetPosition = null; Order.OrderTargetType orderTargetType = (Order.OrderTargetType)msg.ReadByte(); int wallSectionIndex = 0; if (msg.ReadBoolean()) { var x = msg.ReadSingle(); var y = msg.ReadSingle(); var hull = Entity.FindEntityByID(msg.ReadUInt16()) as Hull; orderTargetPosition = new OrderTarget(new Vector2(x, y), hull, creatingFromExistingData: true); } else if (orderTargetType == Order.OrderTargetType.WallSection) { wallSectionIndex = msg.ReadByte(); } if (orderIndex < 0 || orderIndex >= Order.PrefabList.Count) { DebugConsole.ThrowError("Invalid order message - order index out of bounds."); if (NetIdUtils.IdMoreRecent(id, LastID)) { LastID = id; } return; } else { orderPrefab ??= Order.PrefabList[orderIndex]; } orderOption ??= optionIndex.HasValue && optionIndex >= 0 && optionIndex < orderPrefab.Options.Length ? orderPrefab.Options[optionIndex.Value] : ""; txt = orderPrefab.GetChatMessage(targetCharacter?.Name, senderCharacter?.CurrentHull?.DisplayName, givingOrderToSelf: targetCharacter == senderCharacter, orderOption: orderOption); if (GameMain.Client.GameStarted && Screen.Selected == GameMain.GameScreen) { Order order = null; switch (orderTargetType) { case Order.OrderTargetType.Entity: order = new Order(orderPrefab, targetEntity, orderPrefab.GetTargetItemComponent(targetEntity as Item), orderGiver: senderCharacter); break; case Order.OrderTargetType.Position: order = new Order(orderPrefab, orderTargetPosition, orderGiver: senderCharacter); break; case Order.OrderTargetType.WallSection: order = new Order(orderPrefab, targetEntity as Structure, wallSectionIndex, orderGiver: senderCharacter); break; } if (order != null) { if (order.TargetAllCharacters) { var fadeOutTime = !orderPrefab.IsIgnoreOrder ? (float?)orderPrefab.FadeOutTime : null; GameMain.GameSession?.CrewManager?.AddOrder(order, fadeOutTime); } else if (targetCharacter != null) { targetCharacter.SetOrder(order, orderOption, orderPriority, senderCharacter); } } } if (NetIdUtils.IdMoreRecent(id, LastID)) { GameMain.Client.AddChatMessage( new OrderChatMessage(orderPrefab, orderOption, orderPriority, txt, orderTargetPosition ?? targetEntity as ISpatialEntity, targetCharacter, senderCharacter)); LastID = id; } return; case ChatMessageType.ServerMessageBox: txt = TextManager.GetServerMessage(txt); break; case ChatMessageType.ServerMessageBoxInGame: styleSetting = msg.ReadString(); txt = TextManager.GetServerMessage(txt); break; } if (NetIdUtils.IdMoreRecent(id, LastID)) { switch (type) { case ChatMessageType.MessageBox: case ChatMessageType.ServerMessageBox: //only show the message box if the text differs from the text in the currently visible box if ((GUIMessageBox.VisibleBox as GUIMessageBox)?.Text?.Text != txt) { new GUIMessageBox("", txt); } break; case ChatMessageType.ServerMessageBoxInGame: new GUIMessageBox("", txt, new string[0], type: GUIMessageBox.Type.InGame, iconStyle: styleSetting); break; case ChatMessageType.Console: DebugConsole.NewMessage(txt, MessageColor[(int)ChatMessageType.Console]); break; case ChatMessageType.ServerLog: if (!Enum.TryParse(senderName, out ServerLog.MessageType messageType)) { return; } GameMain.Client.ServerSettings.ServerLog?.WriteLine(txt, messageType); break; default: GameMain.Client.AddChatMessage(txt, type, senderName, senderClient, senderCharacter, changeType); break; } LastID = id; } }
public static void ServerRead(IReadMessage msg, Client c) { c.KickAFKTimer = 0.0f; UInt16 ID = msg.ReadUInt16(); ChatMessageType type = (ChatMessageType)msg.ReadByte(); string txt; Character orderTargetCharacter = null; Entity orderTargetEntity = null; OrderChatMessage orderMsg = null; OrderTarget orderTargetPosition = null; Order.OrderTargetType orderTargetType = Order.OrderTargetType.Entity; int?wallSectionIndex = null; if (type == ChatMessageType.Order) { int orderIndex = msg.ReadByte(); orderTargetCharacter = Entity.FindEntityByID(msg.ReadUInt16()) as Character; orderTargetEntity = Entity.FindEntityByID(msg.ReadUInt16()) as Entity; Order orderPrefab = null; int? orderOptionIndex = null; string orderOption = null; // The option of a Dismiss order is written differently so we know what order we target // now that the game supports multiple current orders simultaneously if (orderIndex >= 0 && orderIndex < Order.PrefabList.Count) { orderPrefab = Order.PrefabList[orderIndex]; if (orderPrefab.Identifier != "dismissed") { orderOptionIndex = msg.ReadByte(); } // Does the dismiss order have a specified target? else if (msg.ReadBoolean()) { int identifierCount = msg.ReadByte(); if (identifierCount > 0) { int dismissedOrderIndex = msg.ReadByte(); Order dismissedOrderPrefab = null; if (dismissedOrderIndex >= 0 && dismissedOrderIndex < Order.PrefabList.Count) { dismissedOrderPrefab = Order.PrefabList[dismissedOrderIndex]; orderOption = dismissedOrderPrefab.Identifier; } if (identifierCount > 1) { int dismissedOrderOptionIndex = msg.ReadByte(); if (dismissedOrderPrefab != null) { var options = dismissedOrderPrefab.Options; if (options != null && dismissedOrderOptionIndex >= 0 && dismissedOrderOptionIndex < options.Length) { orderOption += $".{options[dismissedOrderOptionIndex]}"; } } } } } } else { orderOptionIndex = msg.ReadByte(); } int orderPriority = msg.ReadByte(); orderTargetType = (Order.OrderTargetType)msg.ReadByte(); if (msg.ReadBoolean()) { var x = msg.ReadSingle(); var y = msg.ReadSingle(); var hull = Entity.FindEntityByID(msg.ReadUInt16()) as Hull; orderTargetPosition = new OrderTarget(new Vector2(x, y), hull, true); } else if (orderTargetType == Order.OrderTargetType.WallSection) { wallSectionIndex = msg.ReadByte(); } if (orderIndex < 0 || orderIndex >= Order.PrefabList.Count) { DebugConsole.ThrowError($"Invalid order message from client \"{c.Name}\" - order index out of bounds ({orderIndex})."); if (NetIdUtils.IdMoreRecent(ID, c.LastSentChatMsgID)) { c.LastSentChatMsgID = ID; } return; } orderPrefab ??= Order.PrefabList[orderIndex]; orderOption ??= orderOptionIndex == null || orderOptionIndex < 0 || orderOptionIndex >= orderPrefab.Options.Length ? "" : orderPrefab.Options[orderOptionIndex.Value]; orderMsg = new OrderChatMessage(orderPrefab, orderOption, orderPriority, orderTargetPosition ?? orderTargetEntity as ISpatialEntity, orderTargetCharacter, c.Character) { WallSectionIndex = wallSectionIndex }; txt = orderMsg.Text; } else { txt = msg.ReadString() ?? ""; } if (!NetIdUtils.IdMoreRecent(ID, c.LastSentChatMsgID)) { return; } c.LastSentChatMsgID = ID; if (txt.Length > MaxLength) { txt = txt.Substring(0, MaxLength); } c.LastSentChatMessages.Add(txt); if (c.LastSentChatMessages.Count > 10) { c.LastSentChatMessages.RemoveRange(0, c.LastSentChatMessages.Count - 10); } float similarity = 0.0f; for (int i = 0; i < c.LastSentChatMessages.Count; i++) { float closeFactor = 1.0f / (c.LastSentChatMessages.Count - i); if (string.IsNullOrEmpty(txt)) { similarity += closeFactor; } else { int levenshteinDist = ToolBox.LevenshteinDistance(txt, c.LastSentChatMessages[i]); similarity += Math.Max((txt.Length - levenshteinDist) / (float)txt.Length * closeFactor, 0.0f); } } //order/report messages can be sent a little faster than normal messages without triggering the spam filter if (orderMsg != null) { similarity *= 0.25f; } bool isOwner = GameMain.Server.OwnerConnection != null && c.Connection == GameMain.Server.OwnerConnection; if (similarity + c.ChatSpamSpeed > 5.0f && !isOwner) { GameMain.Server.KarmaManager.OnSpamFilterTriggered(c); c.ChatSpamCount++; if (c.ChatSpamCount > 3) { //kick for spamming too much GameMain.Server.KickClient(c, TextManager.Get("SpamFilterKicked")); } else { ChatMessage denyMsg = Create("", TextManager.Get("SpamFilterBlocked"), ChatMessageType.Server, null); c.ChatSpamTimer = 10.0f; GameMain.Server.SendDirectChatMessage(denyMsg, c); } return; } c.ChatSpamSpeed += similarity + 0.5f; if (c.ChatSpamTimer > 0.0f && !isOwner) { ChatMessage denyMsg = Create("", TextManager.Get("SpamFilterBlocked"), ChatMessageType.Server, null); c.ChatSpamTimer = 10.0f; GameMain.Server.SendDirectChatMessage(denyMsg, c); return; } if (type == ChatMessageType.Order) { if (c.Character == null || c.Character.SpeechImpediment >= 100.0f || c.Character.IsDead) { return; } Order order = null; if (orderMsg.Order.IsReport) { HumanAIController.ReportProblem(orderMsg.Sender, orderMsg.Order); } else if (orderTargetCharacter != null && !orderMsg.Order.TargetAllCharacters) { switch (orderTargetType) { case Order.OrderTargetType.Entity: order = new Order(orderMsg.Order.Prefab, orderTargetEntity, orderMsg.Order.Prefab?.GetTargetItemComponent(orderTargetEntity as Item), orderGiver: orderMsg.Sender); break; case Order.OrderTargetType.Position: order = new Order(orderMsg.Order.Prefab, orderTargetPosition, orderGiver: orderMsg.Sender); break; } if (order != null) { orderTargetCharacter.SetOrder(order, orderMsg.OrderOption, orderMsg.OrderPriority, orderMsg.Sender); } } else if (orderMsg.Order.IsIgnoreOrder) { switch (orderTargetType) { case Order.OrderTargetType.Entity: if (orderTargetEntity is IIgnorable ignorableEntity) { ignorableEntity.OrderedToBeIgnored = orderMsg.Order.Identifier == "ignorethis"; } break; case Order.OrderTargetType.WallSection: if (!wallSectionIndex.HasValue) { break; } if (orderTargetEntity is Structure s && s.GetSection(wallSectionIndex.Value) is IIgnorable ignorableWall) { ignorableWall.OrderedToBeIgnored = orderMsg.Order.Identifier == "ignorethis"; } break; } } GameMain.Server.SendOrderChatMessage(orderMsg); } else { GameMain.Server.SendChatMessage(txt, null, c); } }
public static void ClientRead(IReadMessage msg) { UInt16 ID = msg.ReadUInt16(); ChatMessageType type = (ChatMessageType)msg.ReadByte(); PlayerConnectionChangeType changeType = PlayerConnectionChangeType.None; string txt = ""; string styleSetting = string.Empty; if (type != ChatMessageType.Order) { changeType = (PlayerConnectionChangeType)msg.ReadByte(); txt = msg.ReadString(); } string senderName = msg.ReadString(); Character senderCharacter = null; bool hasSenderCharacter = msg.ReadBoolean(); if (hasSenderCharacter) { senderCharacter = Entity.FindEntityByID(msg.ReadUInt16()) as Character; if (senderCharacter != null) { senderName = senderCharacter.Name; } } switch (type) { case ChatMessageType.Default: break; case ChatMessageType.Order: int orderIndex = msg.ReadByte(); UInt16 targetCharacterID = msg.ReadUInt16(); Character targetCharacter = Entity.FindEntityByID(targetCharacterID) as Character; Entity targetEntity = Entity.FindEntityByID(msg.ReadUInt16()); int optionIndex = msg.ReadByte(); OrderTarget orderTargetPosition = null; Order.OrderTargetType orderTargetType = (Order.OrderTargetType)msg.ReadByte(); int wallSectionIndex = 0; if (msg.ReadBoolean()) { var x = msg.ReadSingle(); var y = msg.ReadSingle(); var hull = Entity.FindEntityByID(msg.ReadUInt16()) as Hull; orderTargetPosition = new OrderTarget(new Vector2(x, y), hull, creatingFromExistingData: true); } else if (orderTargetType == Order.OrderTargetType.WallSection) { wallSectionIndex = msg.ReadByte(); } Order orderPrefab; if (orderIndex < 0 || orderIndex >= Order.PrefabList.Count) { DebugConsole.ThrowError("Invalid order message - order index out of bounds."); if (NetIdUtils.IdMoreRecent(ID, LastID)) { LastID = ID; } return; } else { orderPrefab = Order.PrefabList[orderIndex]; } string orderOption = ""; if (optionIndex >= 0 && optionIndex < orderPrefab.Options.Length) { orderOption = orderPrefab.Options[optionIndex]; } txt = orderPrefab.GetChatMessage(targetCharacter?.Name, senderCharacter?.CurrentHull?.DisplayName, givingOrderToSelf: targetCharacter == senderCharacter, orderOption: orderOption); if (GameMain.Client.GameStarted && Screen.Selected == GameMain.GameScreen) { Order order = null; switch (orderTargetType) { case Order.OrderTargetType.Entity: order = new Order(orderPrefab, targetEntity, orderPrefab.GetTargetItemComponent(targetEntity as Item), orderGiver: senderCharacter); break; case Order.OrderTargetType.Position: order = new Order(orderPrefab, orderTargetPosition, orderGiver: senderCharacter); break; case Order.OrderTargetType.WallSection: order = new Order(orderPrefab, targetEntity as Structure, wallSectionIndex, orderGiver: senderCharacter); break; } if (order != null) { if (order.TargetAllCharacters) { var fadeOutTime = !orderPrefab.IsIgnoreOrder ? (float?)orderPrefab.FadeOutTime : null; GameMain.GameSession?.CrewManager?.AddOrder(order, fadeOutTime); } else if (targetCharacter != null) { targetCharacter.SetOrder(order, orderOption, senderCharacter); } } } if (NetIdUtils.IdMoreRecent(ID, LastID)) { GameMain.Client.AddChatMessage( new OrderChatMessage(orderPrefab, orderOption, txt, orderTargetPosition ?? targetEntity as ISpatialEntity, targetCharacter, senderCharacter)); LastID = ID; } return; case ChatMessageType.ServerMessageBox: txt = TextManager.GetServerMessage(txt); break; case ChatMessageType.ServerMessageBoxInGame: styleSetting = msg.ReadString(); txt = TextManager.GetServerMessage(txt); break; } if (NetIdUtils.IdMoreRecent(ID, LastID)) { switch (type) { case ChatMessageType.MessageBox: case ChatMessageType.ServerMessageBox: //only show the message box if the text differs from the text in the currently visible box if ((GUIMessageBox.VisibleBox as GUIMessageBox)?.Text?.Text != txt) { new GUIMessageBox("", txt); } break; case ChatMessageType.ServerMessageBoxInGame: new GUIMessageBox("", txt, new string[0], type: GUIMessageBox.Type.InGame, iconStyle: styleSetting); break; case ChatMessageType.Console: DebugConsole.NewMessage(txt, MessageColor[(int)ChatMessageType.Console]); break; case ChatMessageType.ServerLog: if (!Enum.TryParse(senderName, out ServerLog.MessageType messageType)) { return; } GameMain.Client.ServerSettings.ServerLog?.WriteLine(txt, messageType); break; default: GameMain.Client.AddChatMessage(txt, type, senderName, senderCharacter, changeType); break; } LastID = ID; } }
public static OrderMessageInfo ReadOrder(IReadMessage msg) { int orderIndex = msg.ReadByte(); ushort targetCharacterId = msg.ReadUInt16(); Character targetCharacter = targetCharacterId != Entity.NullEntityID ? Entity.FindEntityByID(targetCharacterId) as Character : null; ushort targetEntityId = msg.ReadUInt16(); Entity targetEntity = targetEntityId != Entity.NullEntityID ? Entity.FindEntityByID(targetEntityId) : null; Order orderPrefab = null; int? optionIndex = null; string orderOption = null; // The option of a Dismiss order is written differently so we know what order we target // now that the game supports multiple current orders simultaneously if (orderIndex >= 0 && orderIndex < Order.PrefabList.Count) { orderPrefab = Order.PrefabList[orderIndex]; if (orderPrefab.Identifier != "dismissed") { optionIndex = msg.ReadByte(); } // Does the dismiss order have a specified target? else if (msg.ReadBoolean()) { int identifierCount = msg.ReadByte(); if (identifierCount > 0) { int dismissedOrderIndex = msg.ReadByte(); Order dismissedOrderPrefab = null; if (dismissedOrderIndex >= 0 && dismissedOrderIndex < Order.PrefabList.Count) { dismissedOrderPrefab = Order.PrefabList[dismissedOrderIndex]; orderOption = dismissedOrderPrefab.Identifier; } if (identifierCount > 1) { int dismissedOrderOptionIndex = msg.ReadByte(); if (dismissedOrderPrefab != null) { var options = dismissedOrderPrefab.Options; if (options != null && dismissedOrderOptionIndex >= 0 && dismissedOrderOptionIndex < options.Length) { orderOption += $".{options[dismissedOrderOptionIndex]}"; } } } } } } else { optionIndex = msg.ReadByte(); } int orderPriority = msg.ReadByte(); OrderTarget orderTargetPosition = null; Order.OrderTargetType orderTargetType = (Order.OrderTargetType)msg.ReadByte(); int wallSectionIndex = 0; if (msg.ReadBoolean()) { float x = msg.ReadSingle(); float y = msg.ReadSingle(); ushort hullId = msg.ReadUInt16(); var hull = hullId != Entity.NullEntityID ? Entity.FindEntityByID(hullId) as Hull : null; orderTargetPosition = new OrderTarget(new Vector2(x, y), hull, creatingFromExistingData: true); } else if (orderTargetType == Order.OrderTargetType.WallSection) { wallSectionIndex = msg.ReadByte(); } return(new OrderMessageInfo(orderIndex, orderPrefab, orderOption, optionIndex, targetCharacter, orderTargetType, targetEntity, orderTargetPosition, wallSectionIndex, orderPriority)); }
public static void ServerRead(IReadMessage msg, Client c) { c.KickAFKTimer = 0.0f; UInt16 ID = msg.ReadUInt16(); ChatMessageType type = (ChatMessageType)msg.ReadByte(); string txt; Character orderTargetCharacter = null; Entity orderTargetEntity = null; OrderChatMessage orderMsg = null; OrderTarget orderTargetPosition = null; if (type == ChatMessageType.Order) { int orderIndex = msg.ReadByte(); orderTargetCharacter = Entity.FindEntityByID(msg.ReadUInt16()) as Character; orderTargetEntity = Entity.FindEntityByID(msg.ReadUInt16()) as Entity; int orderOptionIndex = msg.ReadByte(); if (msg.ReadBoolean()) { var x = msg.ReadSingle(); var y = msg.ReadSingle(); var hull = Entity.FindEntityByID(msg.ReadUInt16()) as Hull; orderTargetPosition = new OrderTarget(new Vector2(x, y), hull, true); } if (orderIndex < 0 || orderIndex >= Order.PrefabList.Count) { DebugConsole.ThrowError($"Invalid order message from client \"{c.Name}\" - order index out of bounds ({orderIndex}, {orderOptionIndex})."); if (NetIdUtils.IdMoreRecent(ID, c.LastSentChatMsgID)) { c.LastSentChatMsgID = ID; } return; } Order order = Order.PrefabList[orderIndex]; string orderOption = orderOptionIndex < 0 || orderOptionIndex >= order.Options.Length ? "" : order.Options[orderOptionIndex]; orderMsg = new OrderChatMessage(order, orderOption, orderTargetPosition ?? orderTargetEntity as ISpatialEntity, orderTargetCharacter, c.Character); txt = orderMsg.Text; } else { txt = msg.ReadString() ?? ""; } if (!NetIdUtils.IdMoreRecent(ID, c.LastSentChatMsgID)) { return; } c.LastSentChatMsgID = ID; if (txt.Length > MaxLength) { txt = txt.Substring(0, MaxLength); } c.LastSentChatMessages.Add(txt); if (c.LastSentChatMessages.Count > 10) { c.LastSentChatMessages.RemoveRange(0, c.LastSentChatMessages.Count - 10); } float similarity = 0.0f; for (int i = 0; i < c.LastSentChatMessages.Count; i++) { float closeFactor = 1.0f / (c.LastSentChatMessages.Count - i); if (string.IsNullOrEmpty(txt)) { similarity += closeFactor; } else { int levenshteinDist = ToolBox.LevenshteinDistance(txt, c.LastSentChatMessages[i]); similarity += Math.Max((txt.Length - levenshteinDist) / (float)txt.Length * closeFactor, 0.0f); } } //order/report messages can be sent a little faster than normal messages without triggering the spam filter if (orderMsg != null) { similarity *= 0.25f; } bool isOwner = GameMain.Server.OwnerConnection != null && c.Connection == GameMain.Server.OwnerConnection; if (similarity + c.ChatSpamSpeed > 5.0f && !isOwner) { GameMain.Server.KarmaManager.OnSpamFilterTriggered(c); c.ChatSpamCount++; if (c.ChatSpamCount > 3) { //kick for spamming too much GameMain.Server.KickClient(c, TextManager.Get("SpamFilterKicked")); } else { ChatMessage denyMsg = Create("", TextManager.Get("SpamFilterBlocked"), ChatMessageType.Server, null); c.ChatSpamTimer = 10.0f; GameMain.Server.SendDirectChatMessage(denyMsg, c); } return; } c.ChatSpamSpeed += similarity + 0.5f; if (c.ChatSpamTimer > 0.0f && !isOwner) { ChatMessage denyMsg = Create("", TextManager.Get("SpamFilterBlocked"), ChatMessageType.Server, null); c.ChatSpamTimer = 10.0f; GameMain.Server.SendDirectChatMessage(denyMsg, c); return; } if (type == ChatMessageType.Order) { if (c.Character == null || c.Character.SpeechImpediment >= 100.0f || c.Character.IsDead) { return; } if (orderMsg.Order.TargetAllCharacters) { HumanAIController.ReportProblem(orderMsg.Sender, orderMsg.Order); } else if (orderTargetCharacter != null) { var order = orderTargetPosition == null ? new Order(orderMsg.Order.Prefab, orderTargetEntity, orderMsg.Order.Prefab?.GetTargetItemComponent(orderTargetEntity as Item), orderMsg.Sender) : new Order(orderMsg.Order.Prefab, orderTargetPosition, orderMsg.Sender); orderTargetCharacter.SetOrder(order, orderMsg.OrderOption, orderMsg.Sender); } GameMain.Server.SendOrderChatMessage(orderMsg); } else { GameMain.Server.SendChatMessage(txt, null, c); } }