public static void LoadPets(XElement petsElement) { foreach (XElement subElement in petsElement.Elements()) { string speciesName = subElement.GetAttributeString("speciesname", ""); string seed = subElement.GetAttributeString("seed", "123"); ushort ownerID = (ushort)subElement.GetAttributeInt("ownerid", 0); Vector2 spawnPos = Vector2.Zero; Character owner = Entity.FindEntityByID(ownerID) as Character; if (owner != null) { spawnPos = owner.WorldPosition; } else { var spawnPoint = WayPoint.WayPointList.Where(wp => wp.SpawnType == SpawnType.Human && wp.Submarine?.Info.Type == SubmarineType.Player).GetRandom(); spawnPos = spawnPoint?.WorldPosition ?? Submarine.MainSub.WorldPosition; } var pet = Character.Create(speciesName, spawnPos, seed); var petBehavior = (pet.AIController as EnemyAIController)?.PetBehavior; if (petBehavior != null) { petBehavior.Owner = owner; var petBehaviorElement = subElement.Attribute("petbehavior"); if (petBehaviorElement != null) { petBehavior.Hunger = petBehaviorElement.GetAttributeFloat(50.0f); petBehavior.Happiness = petBehaviorElement.GetAttributeFloat(50.0f); } } } }
public void SellItems(List <SoldItem> itemsToSell) { // Check all the prices before starting the transaction // to make sure the modifiers stay the same for the whole transaction Dictionary <ItemPrefab, int> sellValues = GetSellValuesAtCurrentLocation(itemsToSell.Select(i => i.ItemPrefab)); var canAddToRemoveQueue = (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer) && Entity.Spawner != null; foreach (SoldItem item in itemsToSell) { var itemValue = sellValues[item.ItemPrefab]; // check if the store can afford the item and if the item hasn't been removed already if (Location.StoreCurrentBalance < itemValue || item.Removed) { continue; } if (!item.Removed && canAddToRemoveQueue && Entity.FindEntityByID(item.ID) is Item entity) { item.Removed = true; Entity.Spawner.AddToRemoveQueue(entity); } SoldItems.Add(item); Location.StoreCurrentBalance -= itemValue; campaign.Money += itemValue; } OnSoldItemsChanged?.Invoke(); }
private void ApplyReceivedState() { if (receivedItemIDs == null) { return; } for (int i = 0; i < capacity; i++) { if (receivedItemIDs[i] == 0) { if (Items[i] != null) { Items[i].Drop(); } } else { var item = Entity.FindEntityByID(receivedItemIDs[i]) as Item; if (item == null) { continue; } TryPutItem(item, i, true, false); } } receivedItemIDs = null; }
public override void ClientReadInitial(IReadMessage msg) { base.ClientReadInitial(msg); existingTargets.Clear(); spawnedTargets.Clear(); allTargets.Clear(); ushort existingTargetsCount = msg.ReadUInt16(); for (int i = 0; i < existingTargetsCount; i++) { ushort targetId = msg.ReadUInt16(); if (targetId == Entity.NullEntityID) { continue; } Entity target = Entity.FindEntityByID(targetId); if (target == null) { continue; } existingTargets.Add(target); allTargets.Add(target); } ushort spawnedTargetsCount = msg.ReadUInt16(); for (int i = 0; i < spawnedTargetsCount; i++) { var enemy = Character.ReadSpawnData(msg); existingTargets.Add(enemy); allTargets.Add(enemy); } }
private void ApplyReceivedState() { for (int i = 0; i < capacity; i++) { if (receivedItemIDs[i] == 0 || (Entity.FindEntityByID(receivedItemIDs[i]) as Item != Items[i])) { if (Items[i] != null) { Items[i].Drop(); } System.Diagnostics.Debug.Assert(Items[i] == null); } } for (int i = 0; i < capacity; i++) { if (receivedItemIDs[i] > 0) { var item = Entity.FindEntityByID(receivedItemIDs[i]) as Item; if (item == null || item == Items[i]) { continue; } TryPutItem(item, i, true, true, null, false); } } receivedItemIDs = null; }
public void SellItems(List <SoldItem> itemsToSell) { var canAddToRemoveQueue = (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer) && Entity.Spawner != null; foreach (SoldItem item in itemsToSell) { var itemValue = GetSellValueAtCurrentLocation(item.ItemPrefab); // check if the store can afford the item and if the item hasn't been removed already if (location.StoreCurrentBalance < itemValue || item.Removed) { continue; } if (!item.Removed && canAddToRemoveQueue && Entity.FindEntityByID(item.ID) is Item entity) { item.Removed = true; Entity.Spawner.AddToRemoveQueue(entity); } SoldItems.Add(item); location.StoreCurrentBalance -= itemValue; campaign.Money += itemValue; } OnSoldItemsChanged?.Invoke(); }
private void ClientReadScanTargetStatus(IReadMessage msg) { scanTargets.Clear(); byte targetsToScan = msg.ReadByte(); for (int i = 0; i < targetsToScan; i++) { ushort id = msg.ReadUInt16(); bool scanned = msg.ReadBoolean(); Entity entity = Entity.FindEntityByID(id); scanTargets.Add(entity as WayPoint, scanned); } }
public TraitorMissionResult(IReadMessage inc) { MissionIdentifier = inc.ReadString(); EndMessage = inc.ReadString(); Success = inc.ReadBoolean(); byte characterCount = inc.ReadByte(); for (int i = 0; i < characterCount; i++) { UInt16 characterID = inc.ReadUInt16(); var character = Entity.FindEntityByID(characterID) as Character; if (character != null) { Characters.Add(character); } } }
private void ApplyReceivedState() { if (receivedItemIDs == null) { return; } for (int i = 0; i < capacity; i++) { if (receivedItemIDs[i] == 0 || (Entity.FindEntityByID(receivedItemIDs[i]) as Item != Items[i])) { if (Items[i] != null) { Items[i].Drop(null); } System.Diagnostics.Debug.Assert(Items[i] == null); } } for (int i = 0; i < capacity; i++) { if (receivedItemIDs[i] > 0) { if (!(Entity.FindEntityByID(receivedItemIDs[i]) is Item item) || Items[i] == item) { continue; } TryPutItem(item, i, true, true, null, false); for (int j = 0; j < capacity; j++) { if (Items[j] == item && receivedItemIDs[j] != item.ID) { Items[j] = null; } } } } receivedItemIDs = null; }
public override void Update(float deltaTime) { base.Update(deltaTime); if (startWatchmanID > 0 && startWatchman == null) { startWatchman = Entity.FindEntityByID(startWatchmanID) as Character; if (startWatchman != null) { InitializeWatchman(startWatchman); } } if (endWatchmanID > 0 && endWatchman == null) { endWatchman = Entity.FindEntityByID(endWatchmanID) as Character; if (endWatchman != null) { InitializeWatchman(endWatchman); } } }
public void StartRound() { listBox.ClearChildren(); characters.Clear(); WayPoint[] waypoints = WayPoint.SelectCrewSpawnPoints(characterInfos, Submarine.MainSub); for (int i = 0; i < waypoints.Length; i++) { Character character; if (characterInfos[i].HullID != null) { var hull = Entity.FindEntityByID((ushort)characterInfos[i].HullID) as Hull; if (hull == null) { continue; } character = Character.Create(characterInfos[i], hull.WorldPosition); } else { character = Character.Create(characterInfos[i], waypoints[i].WorldPosition); Character.Controlled = character; if (character.Info != null && !character.Info.StartItemsGiven) { character.GiveJobItems(waypoints[i]); character.Info.StartItemsGiven = true; } } AddCharacter(character); } if (characters.Any()) { listBox.Select(0); // SelectCharacter(null, characters[0]); } }
public override void ClientReadInitial(IReadMessage msg) { base.ClientReadInitial(msg); bool usedExistingItem = msg.ReadBoolean(); if (usedExistingItem) { ushort id = msg.ReadUInt16(); item = Entity.FindEntityByID(id) as Item; if (item == null) { throw new System.Exception("Error in SalvageMission.ClientReadInitial: failed to find item " + id + " (mission: " + Prefab.Identifier + ")"); } } else { item = Item.ReadSpawnData(msg); if (item == null) { throw new System.Exception("Error in SalvageMission.ClientReadInitial: spawned item was null (mission: " + Prefab.Identifier + ")"); } } int executedEffectCount = msg.ReadByte(); for (int i = 0; i < executedEffectCount; i++) { int index1 = msg.ReadByte(); int index2 = msg.ReadByte(); var selectedEffect = statusEffects[index1][index2]; item.ApplyStatusEffect(selectedEffect, selectedEffect.type, deltaTime: 1.0f, worldPosition: item.Position); } if (item.body != null) { item.body.FarseerBody.BodyType = BodyType.Kinematic; } }
//static because we may need to instantiate the campaign if it hasn't been done yet public static void ClientRead(IReadMessage msg) { bool isFirstRound = msg.ReadBoolean(); byte campaignID = msg.ReadByte(); UInt16 updateID = msg.ReadUInt16(); UInt16 saveID = msg.ReadUInt16(); string mapSeed = msg.ReadString(); UInt16 currentLocIndex = msg.ReadUInt16(); UInt16 selectedLocIndex = msg.ReadUInt16(); byte selectedMissionCount = msg.ReadByte(); List <int> selectedMissionIndices = new List <int>(); for (int i = 0; i < selectedMissionCount; i++) { selectedMissionIndices.Add(msg.ReadByte()); } bool allowDebugTeleport = msg.ReadBoolean(); float?reputation = null; if (msg.ReadBoolean()) { reputation = msg.ReadSingle(); } Dictionary <string, float> factionReps = new Dictionary <string, float>(); byte factionsCount = msg.ReadByte(); for (int i = 0; i < factionsCount; i++) { factionReps.Add(msg.ReadString(), msg.ReadSingle()); } bool forceMapUI = msg.ReadBoolean(); int money = msg.ReadInt32(); bool purchasedHullRepairs = msg.ReadBoolean(); bool purchasedItemRepairs = msg.ReadBoolean(); bool purchasedLostShuttles = msg.ReadBoolean(); byte missionCount = msg.ReadByte(); List <Pair <string, byte> > availableMissions = new List <Pair <string, byte> >(); for (int i = 0; i < missionCount; i++) { string missionIdentifier = msg.ReadString(); byte connectionIndex = msg.ReadByte(); availableMissions.Add(new Pair <string, byte>(missionIdentifier, connectionIndex)); } UInt16?storeBalance = null; if (msg.ReadBoolean()) { storeBalance = msg.ReadUInt16(); } UInt16 buyCrateItemCount = msg.ReadUInt16(); List <PurchasedItem> buyCrateItems = new List <PurchasedItem>(); for (int i = 0; i < buyCrateItemCount; i++) { string itemPrefabIdentifier = msg.ReadString(); int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity); buyCrateItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity)); } UInt16 purchasedItemCount = msg.ReadUInt16(); List <PurchasedItem> purchasedItems = new List <PurchasedItem>(); for (int i = 0; i < purchasedItemCount; i++) { string itemPrefabIdentifier = msg.ReadString(); int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity); purchasedItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity)); } UInt16 soldItemCount = msg.ReadUInt16(); List <SoldItem> soldItems = new List <SoldItem>(); for (int i = 0; i < soldItemCount; i++) { string itemPrefabIdentifier = msg.ReadString(); UInt16 id = msg.ReadUInt16(); bool removed = msg.ReadBoolean(); byte sellerId = msg.ReadByte(); soldItems.Add(new SoldItem(ItemPrefab.Prefabs[itemPrefabIdentifier], id, removed, sellerId)); } ushort pendingUpgradeCount = msg.ReadUInt16(); List <PurchasedUpgrade> pendingUpgrades = new List <PurchasedUpgrade>(); for (int i = 0; i < pendingUpgradeCount; i++) { string upgradeIdentifier = msg.ReadString(); UpgradePrefab prefab = UpgradePrefab.Find(upgradeIdentifier); string categoryIdentifier = msg.ReadString(); UpgradeCategory category = UpgradeCategory.Find(categoryIdentifier); int upgradeLevel = msg.ReadByte(); if (prefab == null || category == null) { continue; } pendingUpgrades.Add(new PurchasedUpgrade(prefab, category, upgradeLevel)); } ushort purchasedItemSwapCount = msg.ReadUInt16(); List <PurchasedItemSwap> purchasedItemSwaps = new List <PurchasedItemSwap>(); for (int i = 0; i < purchasedItemSwapCount; i++) { UInt16 itemToRemoveID = msg.ReadUInt16(); Item itemToRemove = Entity.FindEntityByID(itemToRemoveID) as Item; string itemToInstallIdentifier = msg.ReadString(); ItemPrefab itemToInstall = string.IsNullOrEmpty(itemToInstallIdentifier) ? null : ItemPrefab.Find(string.Empty, itemToInstallIdentifier); if (itemToRemove == null) { continue; } purchasedItemSwaps.Add(new PurchasedItemSwap(itemToRemove, itemToInstall)); } bool hasCharacterData = msg.ReadBoolean(); CharacterInfo myCharacterInfo = null; if (hasCharacterData) { myCharacterInfo = CharacterInfo.ClientRead(CharacterPrefab.HumanSpeciesName, msg); } if (!(GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign) || campaignID != campaign.CampaignID) { string savePath = SaveUtil.CreateSavePath(SaveUtil.SaveType.Multiplayer); GameMain.GameSession = new GameSession(null, savePath, GameModePreset.MultiPlayerCampaign, CampaignSettings.Unsure, mapSeed); campaign = (MultiPlayerCampaign)GameMain.GameSession.GameMode; campaign.CampaignID = campaignID; GameMain.NetLobbyScreen.ToggleCampaignMode(true); } //server has a newer save file if (NetIdUtils.IdMoreRecent(saveID, campaign.PendingSaveID)) { campaign.PendingSaveID = saveID; } if (NetIdUtils.IdMoreRecent(updateID, campaign.lastUpdateID)) { campaign.SuppressStateSending = true; campaign.IsFirstRound = isFirstRound; //we need to have the latest save file to display location/mission/store if (campaign.LastSaveID == saveID) { campaign.ForceMapUI = forceMapUI; UpgradeStore.WaitForServerUpdate = false; campaign.Map.SetLocation(currentLocIndex == UInt16.MaxValue ? -1 : currentLocIndex); campaign.Map.SelectLocation(selectedLocIndex == UInt16.MaxValue ? -1 : selectedLocIndex); campaign.Map.SelectMission(selectedMissionIndices); campaign.Map.AllowDebugTeleport = allowDebugTeleport; campaign.CargoManager.SetItemsInBuyCrate(buyCrateItems); campaign.CargoManager.SetPurchasedItems(purchasedItems); campaign.CargoManager.SetSoldItems(soldItems); if (storeBalance.HasValue) { campaign.Map.CurrentLocation.StoreCurrentBalance = storeBalance.Value; } campaign.UpgradeManager.SetPendingUpgrades(pendingUpgrades); campaign.UpgradeManager.PurchasedUpgrades.Clear(); campaign.UpgradeManager.PurchasedUpgrades.Clear(); foreach (var purchasedItemSwap in purchasedItemSwaps) { if (purchasedItemSwap.ItemToInstall == null) { campaign.UpgradeManager.CancelItemSwap(purchasedItemSwap.ItemToRemove, force: true); } else { campaign.UpgradeManager.PurchaseItemSwap(purchasedItemSwap.ItemToRemove, purchasedItemSwap.ItemToInstall, force: true); } } foreach (Item item in Item.ItemList) { if (item.PendingItemSwap != null && !purchasedItemSwaps.Any(it => it.ItemToRemove == item)) { item.PendingItemSwap = null; } } foreach (var(identifier, rep) in factionReps) { Faction faction = campaign.Factions.FirstOrDefault(f => f.Prefab.Identifier.Equals(identifier, StringComparison.OrdinalIgnoreCase)); if (faction?.Reputation != null) { faction.Reputation.Value = rep; } else { DebugConsole.ThrowError($"Received an update for a faction that doesn't exist \"{identifier}\"."); } } if (reputation.HasValue) { campaign.Map.CurrentLocation.Reputation.Value = reputation.Value; campaign?.CampaignUI?.UpgradeStore?.RefreshAll(); } foreach (var availableMission in availableMissions) { MissionPrefab missionPrefab = MissionPrefab.List.Find(mp => mp.Identifier == availableMission.First); if (missionPrefab == null) { DebugConsole.ThrowError($"Error when receiving campaign data from the server: mission prefab \"{availableMission.First}\" not found."); continue; } if (availableMission.Second == 255) { campaign.Map.CurrentLocation.UnlockMission(missionPrefab); } else { if (availableMission.Second < 0 || availableMission.Second >= campaign.Map.CurrentLocation.Connections.Count) { DebugConsole.ThrowError($"Error when receiving campaign data from the server: connection index for mission \"{availableMission.First}\" out of range (index: {availableMission.Second}, current location: {campaign.Map.CurrentLocation.Name}, connections: {campaign.Map.CurrentLocation.Connections.Count})."); continue; } LocationConnection connection = campaign.Map.CurrentLocation.Connections[availableMission.Second]; campaign.Map.CurrentLocation.UnlockMission(missionPrefab, connection); } } GameMain.NetLobbyScreen.ToggleCampaignMode(true); } bool shouldRefresh = campaign.Money != money || campaign.PurchasedHullRepairs != purchasedHullRepairs || campaign.PurchasedItemRepairs != purchasedItemRepairs || campaign.PurchasedLostShuttles != purchasedLostShuttles; campaign.Money = money; campaign.PurchasedHullRepairs = purchasedHullRepairs; campaign.PurchasedItemRepairs = purchasedItemRepairs; campaign.PurchasedLostShuttles = purchasedLostShuttles; if (shouldRefresh) { campaign?.CampaignUI?.UpgradeStore?.RefreshAll(); } if (myCharacterInfo != null) { GameMain.Client.CharacterInfo = myCharacterInfo; GameMain.NetLobbyScreen.SetCampaignCharacterInfo(myCharacterInfo); } else { GameMain.NetLobbyScreen.SetCampaignCharacterInfo(null); } campaign.lastUpdateID = updateID; campaign.SuppressStateSending = false; } }
private static void InitProjectSpecific() { commands.Add(new Command("restart|reset", "restart/reset: Close and restart the server.", (string[] args) => { NewMessage("*****************", Color.Lime); NewMessage("RESTARTING SERVER", Color.Lime); NewMessage("*****************", Color.Lime); GameMain.Instance.CloseServer(); GameMain.Instance.StartServer(); })); commands.Add(new Command("exit|quit|close", "exit/quit/close: Exit the application.", (string[] args) => { GameMain.ShouldRun = false; })); commands.Add(new Command("say", "say [message]: Send a chat message that displays \"HOST\" as the sender.", (string[] args) => { string text = string.Join(" ", args); text = "HOST: " + text; GameMain.Server.SendChatMessage(text, ChatMessageType.Server); })); commands.Add(new Command("msg", "msg [message]: Send a chat message with no sender specified.", (string[] args) => { string text = string.Join(" ", args); GameMain.Server.SendChatMessage(text, ChatMessageType.Server); })); commands.Add(new Command("servername", "servername [name]: Change the name of the server.", (string[] args) => { GameMain.Server.Name = string.Join(" ", args); GameMain.NetLobbyScreen.ChangeServerName(string.Join(" ", args)); })); commands.Add(new Command("servermsg", "servermsg [message]: Change the message displayed in the server lobby.", (string[] args) => { GameMain.NetLobbyScreen.ChangeServerMessage(string.Join(" ", args)); })); commands.Add(new Command("seed|levelseed", "seed/levelseed: Changes the level seed for the next round.", (string[] args) => { GameMain.NetLobbyScreen.LevelSeed = string.Join(" ", args); })); commands.Add(new Command("randomizeseed", "randomizeseed: Toggles level seed randomization on/off.", (string[] args) => { GameMain.Server.RandomizeSeed = !GameMain.Server.RandomizeSeed; NewMessage((GameMain.Server.RandomizeSeed ? "Enabled" : "Disabled") + " level seed randomization.", Color.Cyan); })); commands.Add(new Command("gamemode", "gamemode [name]/[index]: Select the game mode for the next round. The parameter can either be the name or the index number of the game mode (0 = sandbox, 1 = mission, etc).", (string[] args) => { int index = -1; if (int.TryParse(string.Join(" ", args), out index)) { if (index > 0 && index < GameMain.NetLobbyScreen.GameModes.Length && GameMain.NetLobbyScreen.GameModes[index].Name == "Campaign") { MultiPlayerCampaign.StartCampaignSetup(); } else { GameMain.NetLobbyScreen.SelectedModeIndex = index; } } else { string modeName = string.Join(" ", args); if (modeName.ToLowerInvariant() == "campaign") { MultiPlayerCampaign.StartCampaignSetup(); } else { GameMain.NetLobbyScreen.SelectedModeName = modeName; } } NewMessage("Set gamemode to " + GameMain.NetLobbyScreen.SelectedModeName, Color.Cyan); }, () => { return(new string[][] { GameModePreset.list.Select(gm => gm.Name).ToArray() }); })); commands.Add(new Command("mission", "mission [name]/[index]: Select the mission type for the next round. The parameter can either be the name or the index number of the mission type (0 = first mission type, 1 = second mission type, etc).", (string[] args) => { int index = -1; if (int.TryParse(string.Join(" ", args), out index)) { GameMain.NetLobbyScreen.MissionTypeIndex = index; } else { GameMain.NetLobbyScreen.MissionTypeName = string.Join(" ", args); } NewMessage("Set mission to " + GameMain.NetLobbyScreen.MissionTypeName, Color.Cyan); }, () => { return(new string[][] { MissionPrefab.MissionTypes.ToArray() }); })); commands.Add(new Command("sub|submarine", "submarine [name]: Select the submarine for the next round.", (string[] args) => { Submarine sub = GameMain.NetLobbyScreen.GetSubList().Find(s => s.Name.ToLower() == string.Join(" ", args).ToLower()); if (sub != null) { GameMain.NetLobbyScreen.SelectedSub = sub; } sub = GameMain.NetLobbyScreen.SelectedSub; NewMessage("Selected sub: " + sub.Name + (sub.HasTag(SubmarineTag.Shuttle) ? " (shuttle)" : ""), Color.Cyan); }, () => { return(new string[][] { Submarine.Loaded.Select(s => s.Name).ToArray() }); })); commands.Add(new Command("shuttle", "shuttle [name]: Select the specified submarine as the respawn shuttle for the next round.", (string[] args) => { Submarine shuttle = GameMain.NetLobbyScreen.GetSubList().Find(s => s.Name.ToLower() == string.Join(" ", args).ToLower()); if (shuttle != null) { GameMain.NetLobbyScreen.SelectedShuttle = shuttle; } shuttle = GameMain.NetLobbyScreen.SelectedShuttle; NewMessage("Selected shuttle: " + shuttle.Name + (shuttle.HasTag(SubmarineTag.Shuttle) ? "" : " (not shuttle)"), Color.Cyan); }, () => { return(new string[][] { Submarine.Loaded.Select(s => s.Name).ToArray() }); })); commands.Add(new Command("startgame|startround|start", "start/startgame/startround: Start a new round.", (string[] args) => { if (Screen.Selected == GameMain.GameScreen) { return; } if (!GameMain.Server.StartGame()) { NewMessage("Failed to start a new round", Color.Yellow); } })); commands.Add(new Command("endgame|endround|end", "end/endgame/endround: End the current round.", (string[] args) => { if (Screen.Selected == GameMain.NetLobbyScreen) { return; } GameMain.Server.EndGame(); })); commands.Add(new Command("entitydata", "", (string[] args) => { if (args.Length == 0) { return; } Entity ent = Entity.FindEntityByID(Convert.ToUInt16(args[0])); if (ent != null) { NewMessage(ent.ToString(), Color.Lime); } })); //"dummy commands" that only exist so that the server can give clients permissions to use them commands.Add(new Command("control|controlcharacter", "control [character name]: Start controlling the specified character (client-only).", null)); commands.Add(new Command("los", "Toggle the line of sight effect on/off (client-only).", null)); commands.Add(new Command("lighting|lights", "Toggle lighting on/off (client-only).", null)); commands.Add(new Command("debugdraw", "Toggle the debug drawing mode on/off (client-only).", null)); commands.Add(new Command("togglehud|hud", "Toggle the character HUD (inventories, icons, buttons, etc) on/off (client-only).", null)); commands.Add(new Command("followsub", "Toggle whether the camera should follow the nearest submarine (client-only).", null)); commands.Add(new Command("toggleaitargets|aitargets", "Toggle the visibility of AI targets (= targets that enemies can detect and attack/escape from) (client-only).", null)); #if DEBUG commands.Add(new Command("eventdata", "", (string[] args) => { if (args.Length == 0) { return; } ServerEntityEvent ev = GameMain.Server.EntityEventManager.Events[Convert.ToUInt16(args[0])]; if (ev != null) { NewMessage(ev.StackTrace, Color.Lime); } })); commands.Add(new Command("spamchatmessages", "", (string[] args) => { int msgCount = 1000; if (args.Length > 0) { int.TryParse(args[0], out msgCount); } int msgLength = 50; if (args.Length > 1) { int.TryParse(args[1], out msgLength); } for (int i = 0; i < msgCount; i++) { GameMain.Server.SendChatMessage(ToolBox.RandomSeed(msgLength), ChatMessageType.Default); } })); #endif }
public void ServerRead(IReadMessage msg, Client sender) { UInt16 currentLocIndex = msg.ReadUInt16(); UInt16 selectedLocIndex = msg.ReadUInt16(); byte selectedMissionCount = msg.ReadByte(); List <int> selectedMissionIndices = new List <int>(); for (int i = 0; i < selectedMissionCount; i++) { selectedMissionIndices.Add(msg.ReadByte()); } bool purchasedHullRepairs = msg.ReadBoolean(); bool purchasedItemRepairs = msg.ReadBoolean(); bool purchasedLostShuttles = msg.ReadBoolean(); UInt16 buyCrateItemCount = msg.ReadUInt16(); List <PurchasedItem> buyCrateItems = new List <PurchasedItem>(); for (int i = 0; i < buyCrateItemCount; i++) { string itemPrefabIdentifier = msg.ReadString(); int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity); buyCrateItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity)); } UInt16 purchasedItemCount = msg.ReadUInt16(); List <PurchasedItem> purchasedItems = new List <PurchasedItem>(); for (int i = 0; i < purchasedItemCount; i++) { string itemPrefabIdentifier = msg.ReadString(); int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity); purchasedItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity)); } UInt16 soldItemCount = msg.ReadUInt16(); List <SoldItem> soldItems = new List <SoldItem>(); for (int i = 0; i < soldItemCount; i++) { string itemPrefabIdentifier = msg.ReadString(); UInt16 id = msg.ReadUInt16(); bool removed = msg.ReadBoolean(); byte sellerId = msg.ReadByte(); soldItems.Add(new SoldItem(ItemPrefab.Prefabs[itemPrefabIdentifier], id, removed, sellerId)); } ushort purchasedUpgradeCount = msg.ReadUInt16(); List <PurchasedUpgrade> purchasedUpgrades = new List <PurchasedUpgrade>(); for (int i = 0; i < purchasedUpgradeCount; i++) { string upgradeIdentifier = msg.ReadString(); UpgradePrefab prefab = UpgradePrefab.Find(upgradeIdentifier); string categoryIdentifier = msg.ReadString(); UpgradeCategory category = UpgradeCategory.Find(categoryIdentifier); int upgradeLevel = msg.ReadByte(); if (category == null || prefab == null) { continue; } purchasedUpgrades.Add(new PurchasedUpgrade(prefab, category, upgradeLevel)); } ushort purchasedItemSwapCount = msg.ReadUInt16(); List <PurchasedItemSwap> purchasedItemSwaps = new List <PurchasedItemSwap>(); for (int i = 0; i < purchasedItemSwapCount; i++) { UInt16 itemToRemoveID = msg.ReadUInt16(); Item itemToRemove = Entity.FindEntityByID(itemToRemoveID) as Item; string itemToInstallIdentifier = msg.ReadString(); ItemPrefab itemToInstall = string.IsNullOrEmpty(itemToInstallIdentifier) ? null : ItemPrefab.Find(string.Empty, itemToInstallIdentifier); if (itemToRemove == null) { continue; } purchasedItemSwaps.Add(new PurchasedItemSwap(itemToRemove, itemToInstall)); } if (!AllowedToManageCampaign(sender)) { DebugConsole.ThrowError("Client \"" + sender.Name + "\" does not have a permission to manage the campaign"); return; } Location location = Map.CurrentLocation; int hullRepairCost = location?.GetAdjustedMechanicalCost(HullRepairCost) ?? HullRepairCost; int itemRepairCost = location?.GetAdjustedMechanicalCost(ItemRepairCost) ?? ItemRepairCost; int shuttleRetrieveCost = location?.GetAdjustedMechanicalCost(ShuttleReplaceCost) ?? ShuttleReplaceCost; if (purchasedHullRepairs != this.PurchasedHullRepairs) { if (purchasedHullRepairs && Money >= hullRepairCost) { this.PurchasedHullRepairs = true; Money -= hullRepairCost; } else if (!purchasedHullRepairs) { this.PurchasedHullRepairs = false; Money += hullRepairCost; } } if (purchasedItemRepairs != this.PurchasedItemRepairs) { if (purchasedItemRepairs && Money >= itemRepairCost) { this.PurchasedItemRepairs = true; Money -= itemRepairCost; } else if (!purchasedItemRepairs) { this.PurchasedItemRepairs = false; Money += itemRepairCost; } } if (purchasedLostShuttles != this.PurchasedLostShuttles) { if (GameMain.GameSession?.SubmarineInfo != null && GameMain.GameSession.SubmarineInfo.LeftBehindSubDockingPortOccupied) { GameMain.Server.SendDirectChatMessage(TextManager.FormatServerMessage("ReplaceShuttleDockingPortOccupied"), sender, ChatMessageType.MessageBox); } else if (purchasedLostShuttles && Money >= shuttleRetrieveCost) { this.PurchasedLostShuttles = true; Money -= shuttleRetrieveCost; } else if (!purchasedItemRepairs) { this.PurchasedLostShuttles = false; Money += shuttleRetrieveCost; } } if (currentLocIndex < Map.Locations.Count && Map.AllowDebugTeleport) { Map.SetLocation(currentLocIndex); } Map.SelectLocation(selectedLocIndex == UInt16.MaxValue ? -1 : selectedLocIndex); if (Map.SelectedLocation == null) { Map.SelectRandomLocation(preferUndiscovered: true); } if (Map.SelectedConnection != null) { Map.SelectMission(selectedMissionIndices); } CheckTooManyMissions(Map.CurrentLocation, sender); List <PurchasedItem> currentBuyCrateItems = new List <PurchasedItem>(CargoManager.ItemsInBuyCrate); currentBuyCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInBuyCrate(i.ItemPrefab, -i.Quantity)); buyCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInBuyCrate(i.ItemPrefab, i.Quantity)); CargoManager.SellBackPurchasedItems(new List <PurchasedItem>(CargoManager.PurchasedItems)); CargoManager.PurchaseItems(purchasedItems, false); // for some reason CargoManager.SoldItem is never cleared by the server, I've added a check to SellItems that ignores all // sold items that are removed so they should be discarded on the next message CargoManager.BuyBackSoldItems(new List <SoldItem>(CargoManager.SoldItems)); CargoManager.SellItems(soldItems); foreach (var(prefab, category, _) in purchasedUpgrades) { UpgradeManager.PurchaseUpgrade(prefab, category); // unstable logging int price = prefab.Price.GetBuyprice(UpgradeManager.GetUpgradeLevel(prefab, category), Map?.CurrentLocation); int level = UpgradeManager.GetUpgradeLevel(prefab, category); GameServer.Log($"SERVER: Purchased level {level} {category.Identifier}.{prefab.Identifier} for {price}", ServerLog.MessageType.ServerMessage); } foreach (var purchasedItemSwap in purchasedItemSwaps) { if (purchasedItemSwap.ItemToInstall == null) { UpgradeManager.CancelItemSwap(purchasedItemSwap.ItemToRemove); } else { UpgradeManager.PurchaseItemSwap(purchasedItemSwap.ItemToRemove, purchasedItemSwap.ItemToInstall); } } foreach (Item item in Item.ItemList) { if (item.PendingItemSwap != null && !purchasedItemSwaps.Any(it => it.ItemToRemove == item)) { UpgradeManager.CancelItemSwap(item); item.PendingItemSwap = null; } } }
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c) { List <Item> prevItems = new List <Item>(Items); byte itemCount = msg.ReadByte(); ushort[] newItemIDs = new ushort[itemCount]; for (int i = 0; i < itemCount; i++) { newItemIDs[i] = msg.ReadUInt16(); } if (c == null || c.Character == null) { return; } bool accessible = c.Character.CanAccessInventory(this); if (this is CharacterInventory && accessible) { if (Owner == null || !(Owner is Character)) { accessible = false; } else if (!((CharacterInventory)this).AccessibleWhenAlive && !((Character)Owner).IsDead) { accessible = false; } } if (!accessible) { //create a network event to correct the client's inventory state //otherwise they may have an item in their inventory they shouldn't have been able to pick up, //and receiving an event for that inventory later will cause the item to be dropped CreateNetworkEvent(); for (int i = 0; i < capacity; i++) { if (!(Entity.FindEntityByID(newItemIDs[i]) is Item item)) { continue; } item.PositionUpdateInterval = 0.0f; if (item.ParentInventory != null && item.ParentInventory != this) { item.ParentInventory.CreateNetworkEvent(); } } return; } List <Inventory> prevItemInventories = new List <Inventory>(Items.Select(i => i?.ParentInventory)); for (int i = 0; i < capacity; i++) { Item newItem = newItemIDs[i] == 0 ? null : Entity.FindEntityByID(newItemIDs[i]) as Item; prevItemInventories.Add(newItem?.ParentInventory); if (newItemIDs[i] == 0 || (newItem != Items[i])) { if (Items[i] != null) { Item droppedItem = Items[i]; Entity prevOwner = Owner; droppedItem.Drop(null); var previousInventory = prevOwner switch { Item itemInventory => (itemInventory.FindParentInventory(inventory => inventory is CharacterInventory) as CharacterInventory), Character character => character.Inventory, _ => null }; if (previousInventory != null && previousInventory != c.Character?.Inventory) { GameMain.Server?.KarmaManager.OnItemTakenFromPlayer(previousInventory, c, droppedItem); } if (droppedItem.body != null && prevOwner != null) { droppedItem.body.SetTransform(prevOwner.SimPosition, 0.0f); } } System.Diagnostics.Debug.Assert(Items[i] == null); } } for (int i = 0; i < capacity; i++) { if (newItemIDs[i] > 0) { if (!(Entity.FindEntityByID(newItemIDs[i]) is Item item) || item == Items[i]) { continue; } if (GameMain.Server != null) { var holdable = item.GetComponent <Holdable>(); if (holdable != null && !holdable.CanBeDeattached()) { continue; } if (!prevItems.Contains(item) && !item.CanClientAccess(c)) { #if DEBUG || UNSTABLE DebugConsole.NewMessage($"Client {c.Name} failed to pick up item \"{item}\" (parent inventory: {(item.ParentInventory?.Owner.ToString() ?? "null")}). No access.", Color.Yellow); #endif if (item.body != null && !c.PendingPositionUpdates.Contains(item)) { c.PendingPositionUpdates.Enqueue(item); } item.PositionUpdateInterval = 0.0f; continue; } } TryPutItem(item, i, true, true, c.Character, false); for (int j = 0; j < capacity; j++) { if (Items[j] == item && newItemIDs[j] != item.ID) { Items[j] = null; } } } } CreateNetworkEvent(); foreach (Inventory prevInventory in prevItemInventories.Distinct()) { if (prevInventory != this) { prevInventory?.CreateNetworkEvent(); } } foreach (Item item in Items.Distinct()) { if (item == null) { continue; } if (!prevItems.Contains(item)) { if (Owner == c.Character) { GameServer.Log(GameServer.CharacterLogName(c.Character) + " picked up " + item.Name, ServerLog.MessageType.Inventory); } else { GameServer.Log(GameServer.CharacterLogName(c.Character) + " placed " + item.Name + " in " + Owner, ServerLog.MessageType.Inventory); } } } foreach (Item item in prevItems.Distinct()) { if (item == null) { continue; } if (!Items.Contains(item)) { if (Owner == c.Character) { GameServer.Log(GameServer.CharacterLogName(c.Character) + " dropped " + item.Name, ServerLog.MessageType.Inventory); } else { GameServer.Log(GameServer.CharacterLogName(c.Character) + " removed " + item.Name + " from " + Owner, ServerLog.MessageType.Inventory); } } } }
public override void ClientReadInitial(IReadMessage msg) { base.ClientReadInitial(msg); byte caveCount = msg.ReadByte(); for (int i = 0; i < caveCount; i++) { byte selectedCave = msg.ReadByte(); if (selectedCave < 255 && Level.Loaded != null) { if (selectedCave < Level.Loaded.Caves.Count) { Level.Loaded.Caves[selectedCave].DisplayOnSonar = true; } else { DebugConsole.ThrowError($"Cave index out of bounds when reading nest mission data. Index: {selectedCave}, number of caves: {Level.Loaded.Caves.Count}"); } } } for (int i = 0; i < resourceClusters.Count; i++) { var amount = msg.ReadByte(); var rotation = msg.ReadSingle(); for (int j = 0; j < amount; j++) { var item = Item.ReadSpawnData(msg); if (item.GetComponent <Holdable>() is Holdable h) { h.AttachToWall(); item.Rotation = rotation; } if (spawnedResources.TryGetValue(item.Prefab.Identifier, out var resources)) { resources.Add(item); } else { spawnedResources.Add(item.Prefab.Identifier, new List <Item>() { item }); } } } CalculateMissionClusterPositions(); for (int i = 0; i < resourceClusters.Count; i++) { var identifier = msg.ReadString(); var count = msg.ReadByte(); var resources = new Item[count]; for (int j = 0; j < count; j++) { var id = msg.ReadUInt16(); var entity = Entity.FindEntityByID(id); if (!(entity is Item item)) { continue; } resources[j] = item; } relevantLevelResources.Add(identifier, resources); } }
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; } 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.Collider.Position : ViewTarget.Position) + new Vector2((float)Math.Cos(aimAngle), (float)Math.Sin(aimAngle)) * 60.0f; var closestEntity = Entity.FindEntityByID(memInput[memInput.Count - 1].interact); if (closestEntity is Item) { closestItem = (Item)closestEntity; closestCharacter = null; } else if (closestEntity is Character) { closestCharacter = (Character)closestEntity; closestItem = 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, 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 (AnimController.TargetDir == Direction.Left) { newInput |= InputNetFlags.FacingLeft; } Vector2 relativeCursorPos = cursorPosition - (ViewTarget == null ? AnimController.Collider.Position : 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 (closestItem != null) { newMem.interact = closestItem.ID; } else if (closestCharacter != null) { newMem.interact = closestCharacter.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 void ServerRead(ClientNetObject type, NetBuffer msg, Barotrauma.Networking.Client c) { List <Item> prevItems = new List <Item>(Items); ushort[] newItemIDs = new ushort[capacity]; for (int i = 0; i < capacity; i++) { newItemIDs[i] = msg.ReadUInt16(); } if (c == null || c.Character == null) { return; } if (!c.Character.CanAccessInventory(this)) { //create a network event to correct the client's inventory state //otherwise they may have an item in their inventory they shouldn't have been able to pick up, //and receiving an event for that inventory later will cause the item to be dropped CreateNetworkEvent(); for (int i = 0; i < capacity; i++) { var item = Entity.FindEntityByID(newItemIDs[i]) as Item; if (item == null) { continue; } if (item.ParentInventory != null && item.ParentInventory != this) { item.ParentInventory.CreateNetworkEvent(); } } return; } List <Inventory> prevItemInventories = new List <Inventory>(Items.Select(i => i?.ParentInventory)); for (int i = 0; i < capacity; i++) { Item newItem = newItemIDs[i] == 0 ? null : Entity.FindEntityByID(newItemIDs[i]) as Item; prevItemInventories.Add(newItem?.ParentInventory); if (newItemIDs[i] == 0 || (newItem != Items[i])) { if (Items[i] != null) { Items[i].Drop(); } System.Diagnostics.Debug.Assert(Items[i] == null); } } for (int i = 0; i < capacity; i++) { if (newItemIDs[i] > 0) { var item = Entity.FindEntityByID(newItemIDs[i]) as Item; if (item == null || item == Items[i]) { continue; } if (GameMain.Server != null) { var holdable = item.GetComponent <Holdable>(); if (holdable != null && !holdable.CanBeDeattached()) { continue; } if (!item.CanClientAccess(c)) { continue; } } TryPutItem(item, i, true, true, c.Character, false); } } CreateNetworkEvent(); foreach (Inventory prevInventory in prevItemInventories.Distinct()) { if (prevInventory != this) { prevInventory?.CreateNetworkEvent(); } } foreach (Item item in Items.Distinct()) { if (item == null) { continue; } if (!prevItems.Contains(item)) { if (Owner == c.Character) { GameServer.Log(c.Character.LogName + " picked up " + item.Name, ServerLog.MessageType.Inventory); } else { GameServer.Log(c.Character.LogName + " placed " + item.Name + " in " + Owner, ServerLog.MessageType.Inventory); } } } foreach (Item item in prevItems.Distinct()) { if (item == null) { continue; } if (!Items.Contains(item)) { if (Owner == c.Character) { GameServer.Log(c.Character.LogName + " dropped " + item.Name, ServerLog.MessageType.Inventory); } else { GameServer.Log(c.Character.LogName + " removed " + item.Name + " from " + Owner, ServerLog.MessageType.Inventory); } } } }
/// <summary> /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input, and playing audio. /// </summary> public override void Update(double deltaTime) { if (tutorial != null) { tutorial.Update((float)deltaTime); } hullVolumeFrame.Visible = MapEntity.SelectedList.Any(s => s is Hull); cam.MoveCamera((float)deltaTime, true, GUIComponent.MouseOn == null); if (characterMode || wiringMode) { if (dummyCharacter == null || Entity.FindEntityByID(dummyCharacter.ID) != dummyCharacter) { ToggleCharacterMode(null, null); } else { foreach (MapEntity me in MapEntity.mapEntityList) { me.IsHighlighted = false; } if (wiringMode && dummyCharacter.SelectedConstruction == null) { List <Wire> wires = new List <Wire>(); foreach (Item item in Item.ItemList) { var wire = item.GetComponent <Wire>(); if (wire != null) { wires.Add(wire); } } Wire.UpdateEditing(wires); } if (dummyCharacter.SelectedConstruction == null) { Vector2 mouseSimPos = FarseerPhysics.ConvertUnits.ToSimUnits(dummyCharacter.CursorPosition); foreach (Limb limb in dummyCharacter.AnimController.Limbs) { limb.body.SetTransform(mouseSimPos, 0.0f); } dummyCharacter.AnimController.Collider.SetTransform(mouseSimPos, 0.0f); } dummyCharacter.ControlLocalPlayer((float)deltaTime, cam, false); dummyCharacter.Control((float)deltaTime, cam); dummyCharacter.Submarine = Submarine.MainSub; cam.TargetPos = Vector2.Zero; } } else { MapEntity.UpdateSelecting(cam); } //GUIComponent.ForceMouseOn(null); if (!characterMode && !wiringMode) { if (MapEntityPrefab.Selected != null) { MapEntityPrefab.Selected.UpdatePlacing(cam); } MapEntity.UpdateEditor(cam); } leftPanel.Update((float)deltaTime); topPanel.Update((float)deltaTime); if (wiringMode) { if (!dummyCharacter.SelectedItems.Any(it => it != null && it.HasTag("Wire"))) { wiringToolPanel.GetChild <GUIListBox>().Deselect(); } wiringToolPanel.Update((float)deltaTime); } if (loadFrame != null) { loadFrame.Update((float)deltaTime); if (PlayerInput.RightButtonClicked()) { loadFrame = null; } } else if (saveFrame != null) { saveFrame.Update((float)deltaTime); } else if (selectedTab > -1) { GUItabs[selectedTab].Update((float)deltaTime); if (PlayerInput.RightButtonClicked()) { selectedTab = -1; } } if ((characterMode || wiringMode) && dummyCharacter != null) { dummyCharacter.AnimController.FindHull(dummyCharacter.CursorWorldPosition, false); foreach (Item item in dummyCharacter.SelectedItems) { if (item == null) { continue; } item.SetTransform(dummyCharacter.SimPosition, 0.0f); item.Update((float)deltaTime, cam); item.SetTransform(item.body.SimPosition, 0.0f); } if (dummyCharacter.SelectedConstruction != null) { if (dummyCharacter.SelectedConstruction != null) { dummyCharacter.SelectedConstruction.UpdateHUD(cam, dummyCharacter); } if (PlayerInput.KeyHit(InputType.Select) && dummyCharacter.FocusedItem != dummyCharacter.SelectedConstruction) { dummyCharacter.SelectedConstruction = null; } } CharacterHUD.Update((float)deltaTime, dummyCharacter); } GUI.Update((float)deltaTime); }
public virtual void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime) { switch (type) { case ServerNetObject.ENTITY_POSITION: bool facingRight = AnimController.Dir > 0.0f; lastRecvPositionUpdateTime = (float)Lidgren.Network.NetTime.Now; AnimController.Frozen = false; Enabled = true; UInt16 networkUpdateID = 0; if (msg.ReadBoolean()) { networkUpdateID = msg.ReadUInt16(); } else { bool aimInput = msg.ReadBoolean(); keys[(int)InputType.Aim].Held = aimInput; keys[(int)InputType.Aim].SetState(false, aimInput); bool shootInput = msg.ReadBoolean(); keys[(int)InputType.Shoot].Held = shootInput; keys[(int)InputType.Shoot].SetState(false, shootInput); bool useInput = msg.ReadBoolean(); keys[(int)InputType.Use].Held = useInput; keys[(int)InputType.Use].SetState(false, useInput); if (AnimController is HumanoidAnimController) { bool crouching = msg.ReadBoolean(); keys[(int)InputType.Crouch].Held = crouching; keys[(int)InputType.Crouch].SetState(false, crouching); } bool attackInput = msg.ReadBoolean(); keys[(int)InputType.Attack].Held = attackInput; keys[(int)InputType.Attack].SetState(false, attackInput); double aimAngle = msg.ReadUInt16() / 65535.0 * 2.0 * Math.PI; cursorPosition = AimRefPosition + new Vector2((float)Math.Cos(aimAngle), (float)Math.Sin(aimAngle)) * 500.0f; TransformCursorPos(); bool ragdollInput = msg.ReadBoolean(); keys[(int)InputType.Ragdoll].Held = ragdollInput; keys[(int)InputType.Ragdoll].SetState(false, ragdollInput); facingRight = msg.ReadBoolean(); } bool entitySelected = msg.ReadBoolean(); Character selectedCharacter = null; Item selectedItem = null; AnimController.Animation animation = AnimController.Animation.None; if (entitySelected) { ushort characterID = msg.ReadUInt16(); ushort itemID = msg.ReadUInt16(); selectedCharacter = FindEntityByID(characterID) as Character; selectedItem = FindEntityByID(itemID) as Item; if (characterID != NullEntityID) { bool doingCpr = msg.ReadBoolean(); if (doingCpr && SelectedCharacter != null) { animation = AnimController.Animation.CPR; } } } Vector2 pos = new Vector2( msg.ReadSingle(), msg.ReadSingle()); float MaxVel = NetConfig.MaxPhysicsBodyVelocity; Vector2 linearVelocity = new Vector2( msg.ReadRangedSingle(-MaxVel, MaxVel, 12), msg.ReadRangedSingle(-MaxVel, MaxVel, 12)); linearVelocity = NetConfig.Quantize(linearVelocity, -MaxVel, MaxVel, 12); bool fixedRotation = msg.ReadBoolean(); float?rotation = null; float?angularVelocity = null; if (!fixedRotation) { rotation = msg.ReadSingle(); float MaxAngularVel = NetConfig.MaxPhysicsBodyAngularVelocity; angularVelocity = msg.ReadRangedSingle(-MaxAngularVel, MaxAngularVel, 8); angularVelocity = NetConfig.Quantize(angularVelocity.Value, -MaxAngularVel, MaxAngularVel, 8); } bool readStatus = msg.ReadBoolean(); if (readStatus) { ReadStatus(msg); (AIController as EnemyAIController)?.PetBehavior?.ClientRead(msg); } msg.ReadPadBits(); int index = 0; if (GameMain.Client.Character == this && CanMove) { var posInfo = new CharacterStateInfo( pos, rotation, networkUpdateID, facingRight ? Direction.Right : Direction.Left, selectedCharacter, selectedItem, animation); while (index < memState.Count && NetIdUtils.IdMoreRecent(posInfo.ID, memState[index].ID)) { index++; } memState.Insert(index, posInfo); } else { var posInfo = new CharacterStateInfo( pos, rotation, linearVelocity, angularVelocity, sendingTime, facingRight ? Direction.Right : Direction.Left, selectedCharacter, selectedItem, animation); while (index < memState.Count && posInfo.Timestamp > memState[index].Timestamp) { index++; } memState.Insert(index, posInfo); } break; case ServerNetObject.ENTITY_EVENT: int eventType = msg.ReadRangedInteger(0, 9); switch (eventType) { case 0: //NetEntityEvent.Type.InventoryState if (Inventory == null) { string errorMsg = "Received an inventory update message for an entity with no inventory (" + Name + ", removed: " + Removed + ")"; DebugConsole.ThrowError(errorMsg); GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ClientRead:NoInventory" + ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); //read anyway to prevent messing up reading the rest of the message _ = msg.ReadUInt16(); byte inventoryItemCount = msg.ReadByte(); for (int i = 0; i < inventoryItemCount; i++) { msg.ReadUInt16(); } } else { Inventory.ClientRead(type, msg, sendingTime); } break; case 1: //NetEntityEvent.Type.Control byte ownerID = msg.ReadByte(); ResetNetState(); if (ownerID == GameMain.Client.ID) { if (controlled != null) { LastNetworkUpdateID = controlled.LastNetworkUpdateID; } if (!IsDead) { Controlled = this; } IsRemotePlayer = false; GameMain.Client.HasSpawned = true; GameMain.Client.Character = this; GameMain.LightManager.LosEnabled = true; GameMain.LightManager.LosAlpha = 1f; GameMain.Client.WaitForNextRoundRespawn = null; } else { if (controlled == this) { Controlled = null; IsRemotePlayer = ownerID > 0; } } break; case 2: //NetEntityEvent.Type.Status ReadStatus(msg); break; case 3: //NetEntityEvent.Type.UpdateSkills int skillCount = msg.ReadByte(); for (int i = 0; i < skillCount; i++) { string skillIdentifier = msg.ReadString(); float skillLevel = msg.ReadSingle(); info?.SetSkillLevel(skillIdentifier, skillLevel, Position + Vector2.UnitY * 150.0f); } break; case 4: // NetEntityEvent.Type.SetAttackTarget case 5: //NetEntityEvent.Type.ExecuteAttack int attackLimbIndex = msg.ReadByte(); UInt16 targetEntityID = msg.ReadUInt16(); int targetLimbIndex = msg.ReadByte(); Vector2 targetSimPos = new Vector2(msg.ReadSingle(), msg.ReadSingle()); //255 = entity already removed, no need to do anything if (attackLimbIndex == 255 || Removed) { break; } if (attackLimbIndex >= AnimController.Limbs.Length) { DebugConsole.ThrowError($"Received invalid SetAttack/ExecuteAttack message. Limb index out of bounds (character: {Name}, limb index: {attackLimbIndex}, limb count: {AnimController.Limbs.Length})"); break; } Limb attackLimb = AnimController.Limbs[attackLimbIndex]; Limb targetLimb = null; if (!(FindEntityByID(targetEntityID) is IDamageable targetEntity)) { DebugConsole.ThrowError($"Received invalid SetAttack/ExecuteAttack message. Target entity not found (ID {targetEntityID})"); break; } if (targetEntity is Character targetCharacter) { if (targetLimbIndex >= targetCharacter.AnimController.Limbs.Length) { DebugConsole.ThrowError($"Received invalid SetAttack/ExecuteAttack message. Target limb index out of bounds (target character: {targetCharacter.Name}, limb index: {targetLimbIndex}, limb count: {targetCharacter.AnimController.Limbs.Length})"); break; } targetLimb = targetCharacter.AnimController.Limbs[targetLimbIndex]; } if (attackLimb?.attack != null) { if (eventType == 4) { SetAttackTarget(attackLimb, targetEntity, targetSimPos); } else { attackLimb.ExecuteAttack(targetEntity, targetLimb, out _); } } break; case 6: //NetEntityEvent.Type.AssignCampaignInteraction byte campaignInteractionType = msg.ReadByte(); bool requireConsciousness = msg.ReadBoolean(); (GameMain.GameSession?.GameMode as CampaignMode)?.AssignNPCMenuInteraction(this, (CampaignMode.InteractionType)campaignInteractionType); RequireConsciousnessForCustomInteract = requireConsciousness; break; case 7: //NetEntityEvent.Type.ObjectiveManagerState // 1 = order, 2 = objective int msgType = msg.ReadRangedInteger(0, 2); if (msgType == 0) { break; } bool validData = msg.ReadBoolean(); if (!validData) { break; } if (msgType == 1) { int orderIndex = msg.ReadRangedInteger(0, Order.PrefabList.Count); var orderPrefab = Order.PrefabList[orderIndex]; string option = null; if (orderPrefab.HasOptions) { int optionIndex = msg.ReadRangedInteger(-1, orderPrefab.AllOptions.Length); if (optionIndex > -1) { option = orderPrefab.AllOptions[optionIndex]; } } GameMain.GameSession?.CrewManager?.SetOrderHighlight(this, orderPrefab.Identifier, option); } else if (msgType == 2) { string identifier = msg.ReadString(); string option = msg.ReadString(); ushort objectiveTargetEntityId = msg.ReadUInt16(); var objectiveTargetEntity = FindEntityByID(objectiveTargetEntityId); GameMain.GameSession?.CrewManager?.CreateObjectiveIcon(this, identifier, option, objectiveTargetEntity); } break; case 8: //NetEntityEvent.Type.TeamChange byte newTeamId = msg.ReadByte(); ChangeTeam((CharacterTeamType)newTeamId); break; case 9: //NetEntityEvent.Type.AddToCrew GameMain.GameSession.CrewManager.AddCharacter(this); CharacterTeamType teamID = (CharacterTeamType)msg.ReadByte(); ushort itemCount = msg.ReadUInt16(); for (int i = 0; i < itemCount; i++) { ushort itemID = msg.ReadUInt16(); if (!(Entity.FindEntityByID(itemID) is Item item)) { continue; } item.AllowStealing = true; var wifiComponent = item.GetComponent <Items.Components.WifiComponent>(); if (wifiComponent != null) { wifiComponent.TeamID = teamID; } } break; } msg.ReadPadBits(); break; } }
public void ServerRead(ClientNetObject type, NetBuffer msg, Client c) { List <Item> prevItems = new List <Item>(Items); ushort[] newItemIDs = new ushort[capacity]; for (int i = 0; i < capacity; i++) { newItemIDs[i] = msg.ReadUInt16(); } if (c == null || c.Character == null) { return; } bool accessible = c.Character.CanAccessInventory(this); if (this is CharacterInventory && accessible) { if (Owner == null || !(Owner is Character)) { accessible = false; } else if (!((CharacterInventory)this).AccessibleWhenAlive && !((Character)Owner).IsDead) { accessible = false; } } if (!accessible) { //create a network event to correct the client's inventory state //otherwise they may have an item in their inventory they shouldn't have been able to pick up, //and receiving an event for that inventory later will cause the item to be dropped CreateNetworkEvent(); for (int i = 0; i < capacity; i++) { if (!(Entity.FindEntityByID(newItemIDs[i]) is Item item)) { continue; } item.PositionUpdateInterval = 0.0f; if (item.ParentInventory != null && item.ParentInventory != this) { item.ParentInventory.CreateNetworkEvent(); } } return; } List <Inventory> prevItemInventories = new List <Inventory>(Items.Select(i => i?.ParentInventory)); for (int i = 0; i < capacity; i++) { Item newItem = newItemIDs[i] == 0 ? null : Entity.FindEntityByID(newItemIDs[i]) as Item; prevItemInventories.Add(newItem?.ParentInventory); if (newItemIDs[i] == 0 || (newItem != Items[i])) { if (Items[i] != null) { Item droppedItem = Items[i]; Entity prevOwner = Owner; droppedItem.Drop(null); if (droppedItem.body != null && prevOwner != null) { droppedItem.body.SetTransform(prevOwner.SimPosition, 0.0f); } } System.Diagnostics.Debug.Assert(Items[i] == null); } } for (int i = 0; i < capacity; i++) { if (newItemIDs[i] > 0) { if (!(Entity.FindEntityByID(newItemIDs[i]) is Item item) || item == Items[i]) { continue; } if (GameMain.Server != null) { var holdable = item.GetComponent <Holdable>(); if (holdable != null && !holdable.CanBeDeattached()) { continue; } if (!prevItems.Contains(item) && !item.CanClientAccess(c)) { item.PositionUpdateInterval = 0.0f; continue; } } TryPutItem(item, i, true, true, c.Character, false); for (int j = 0; j < capacity; j++) { if (Items[j] == item && newItemIDs[j] != item.ID) { Items[j] = null; } } } } CreateNetworkEvent(); foreach (Inventory prevInventory in prevItemInventories.Distinct()) { if (prevInventory != this) { prevInventory?.CreateNetworkEvent(); } } foreach (Item item in Items.Distinct()) { if (item == null) { continue; } if (!prevItems.Contains(item)) { if (Owner == c.Character) { GameServer.Log(c.Character.LogName + " picked up " + item.Name, ServerLog.MessageType.Inventory); } else { GameServer.Log(c.Character.LogName + " placed " + item.Name + " in " + Owner, ServerLog.MessageType.Inventory); } } } foreach (Item item in prevItems.Distinct()) { if (item == null) { continue; } if (!Items.Contains(item)) { if (Owner == c.Character) { GameServer.Log(c.Character.LogName + " dropped " + item.Name, ServerLog.MessageType.Inventory); } else { GameServer.Log(c.Character.LogName + " removed " + item.Name + " from " + Owner, ServerLog.MessageType.Inventory); } } } }
private static void InitProjectSpecific() { commands.Add(new Command("restart|reset", "restart/reset: Close and restart the server.", (string[] args) => { NewMessage("*****************", Color.Lime); NewMessage("RESTARTING SERVER", Color.Lime); NewMessage("*****************", Color.Lime); GameMain.Instance.CloseServer(); GameMain.Instance.StartServer(); })); commands.Add(new Command("exit|quit|close", "exit/quit/close: Exit the application.", (string[] args) => { GameMain.ShouldRun = false; })); commands.Add(new Command("say", "say [message]: Send a chat message that displays \"HOST\" as the sender.", (string[] args) => { string text = string.Join(" ", args); text = "HOST: " + text; GameMain.Server.SendChatMessage(text, ChatMessageType.Server); })); commands.Add(new Command("msg", "msg [message]: Send a chat message with no sender specified.", (string[] args) => { string text = string.Join(" ", args); GameMain.Server.SendChatMessage(text, ChatMessageType.Server); })); commands.Add(new Command("servername", "servername [name]: Change the name of the server.", (string[] args) => { GameMain.Server.Name = string.Join(" ", args); GameMain.NetLobbyScreen.ChangeServerName(string.Join(" ", args)); })); commands.Add(new Command("servermsg", "servermsg [message]: Change the message displayed in the server lobby.", (string[] args) => { GameMain.NetLobbyScreen.ChangeServerMessage(string.Join(" ", args)); })); commands.Add(new Command("seed|levelseed", "seed/levelseed: Changes the level seed for the next round.", (string[] args) => { GameMain.NetLobbyScreen.LevelSeed = string.Join(" ", args); })); commands.Add(new Command("gamemode", "gamemode [name]/[index]: Select the game mode for the next round. The parameter can either be the name or the index number of the game mode (0 = sandbox, 1 = mission, etc).", (string[] args) => { int index = -1; if (int.TryParse(string.Join(" ", args), out index)) { GameMain.NetLobbyScreen.SelectedModeIndex = index; } else { GameMain.NetLobbyScreen.SelectedModeName = string.Join(" ", args); } NewMessage("Set gamemode to " + GameMain.NetLobbyScreen.SelectedModeName, Color.Cyan); })); commands.Add(new Command("mission", "mission [name]/[index]: Select the mission type for the next round. The parameter can either be the name or the index number of the mission type (0 = first mission type, 1 = second mission type, etc).", (string[] args) => { int index = -1; if (int.TryParse(string.Join(" ", args), out index)) { GameMain.NetLobbyScreen.MissionTypeIndex = index; } else { GameMain.NetLobbyScreen.MissionTypeName = string.Join(" ", args); } NewMessage("Set mission to " + GameMain.NetLobbyScreen.MissionTypeName, Color.Cyan); })); commands.Add(new Command("sub|submarine", "submarine [name]: Select the submarine for the next round.", (string[] args) => { Submarine sub = GameMain.NetLobbyScreen.GetSubList().Find(s => s.Name.ToLower() == string.Join(" ", args).ToLower()); if (sub != null) { GameMain.NetLobbyScreen.SelectedSub = sub; } sub = GameMain.NetLobbyScreen.SelectedSub; NewMessage("Selected sub: " + sub.Name + (sub.HasTag(SubmarineTag.Shuttle) ? " (shuttle)" : ""), Color.Cyan); })); commands.Add(new Command("shuttle", "shuttle [name]: Select the specified submarine as the respawn shuttle for the next round.", (string[] args) => { Submarine shuttle = GameMain.NetLobbyScreen.GetSubList().Find(s => s.Name.ToLower() == string.Join(" ", args).ToLower()); if (shuttle != null) { GameMain.NetLobbyScreen.SelectedShuttle = shuttle; } shuttle = GameMain.NetLobbyScreen.SelectedShuttle; NewMessage("Selected shuttle: " + shuttle.Name + (shuttle.HasTag(SubmarineTag.Shuttle) ? "" : " (not shuttle)"), Color.Cyan); })); commands.Add(new Command("startgame|startround|start", "start/startgame/startround: Start a new round.", (string[] args) => { if (Screen.Selected == GameMain.GameScreen) { return; } if (!GameMain.Server.StartGame()) { NewMessage("Failed to start a new round", Color.Yellow); } })); commands.Add(new Command("endgame|endround|end", "end/endgame/endround: End the current round.", (string[] args) => { if (Screen.Selected == GameMain.NetLobbyScreen) { return; } GameMain.Server.EndGame(); })); commands.Add(new Command("entitydata", "", (string[] args) => { if (args.Length == 0) { return; } Entity ent = Entity.FindEntityByID(Convert.ToUInt16(args[0])); if (ent != null) { NewMessage(ent.ToString(), Color.Lime); } })); #if DEBUG commands.Add(new Command("eventdata", "", (string[] args) => { if (args.Length == 0) { return; } ServerEntityEvent ev = GameMain.Server.EntityEventManager.Events[Convert.ToUInt16(args[0])]; if (ev != null) { NewMessage(ev.StackTrace, Color.Lime); } })); commands.Add(new Command("spamchatmessages", "", (string[] args) => { int msgCount = 1000; if (args.Length > 0) { int.TryParse(args[0], out msgCount); } int msgLength = 50; if (args.Length > 1) { int.TryParse(args[1], out msgLength); } for (int i = 0; i < msgCount; i++) { GameMain.Server.SendChatMessage(ToolBox.RandomSeed(msgLength), ChatMessageType.Default); } })); #endif }
public void ServerRead(ClientNetObject type, NetBuffer msg, Barotrauma.Networking.Client c) { List <Item> prevItems = new List <Item>(Items); ushort[] newItemIDs = new ushort[capacity]; for (int i = 0; i < capacity; i++) { newItemIDs[i] = msg.ReadUInt16(); } if (c == null || c.Character == null || !c.Character.CanAccessInventory(this)) { return; } for (int i = 0; i < capacity; i++) { if (newItemIDs[i] == 0) { if (Items[i] != null) { Items[i].Drop(c.Character); } System.Diagnostics.Debug.Assert(Items[i] == null); } else { var item = Entity.FindEntityByID(newItemIDs[i]) as Item; if (item == null || item == Items[i]) { continue; } if (GameMain.Server != null) { if (!item.CanClientAccess(c)) { continue; } } TryPutItem(item, i, true, false); } } GameMain.Server.CreateEntityEvent(Owner as IServerSerializable, new object[] { NetEntityEvent.Type.InventoryState }); foreach (Item item in Items.Distinct()) { if (item == null) { continue; } if (!prevItems.Contains(item)) { if (Owner == c.Character) { GameServer.Log(c.Character + " picked up " + item.Name, ServerLog.MessageType.Inventory); } else { GameServer.Log(c.Character + " placed " + item.Name + " in " + Owner, ServerLog.MessageType.Inventory); } } } foreach (Item item in prevItems.Distinct()) { if (item == null) { continue; } if (!Items.Contains(item)) { if (Owner == c.Character) { GameServer.Log(c.Character + " dropped " + item.Name, ServerLog.MessageType.Inventory); } else { GameServer.Log(c.Character + " removed " + item.Name + " from " + Owner, ServerLog.MessageType.Inventory); } } } }