diff --git a/Subsurface/Content/Map/testroom.png b/Subsurface/Content/Map/testroom.png index 3672e0776..2c6332335 100644 Binary files a/Subsurface/Content/Map/testroom.png and b/Subsurface/Content/Map/testroom.png differ diff --git a/Subsurface/Content/Sounds/Music/Phantom From Space.ogg b/Subsurface/Content/Sounds/Music/Phantom From Space.ogg new file mode 100644 index 000000000..8707b3e6a Binary files /dev/null and b/Subsurface/Content/Sounds/Music/Phantom From Space.ogg differ diff --git a/Subsurface/Content/Sounds/sounds.xml b/Subsurface/Content/Sounds/sounds.xml index 43114cba9..22f05a258 100644 --- a/Subsurface/Content/Sounds/sounds.xml +++ b/Subsurface/Content/Sounds/sounds.xml @@ -43,6 +43,7 @@ + diff --git a/Subsurface/Data/ContentPackages/Vanilla 0.3.xml b/Subsurface/Data/ContentPackages/Vanilla 0.3.xml index 2e2d2444c..1d35a45ca 100644 --- a/Subsurface/Data/ContentPackages/Vanilla 0.3.xml +++ b/Subsurface/Data/ContentPackages/Vanilla 0.3.xml @@ -42,6 +42,8 @@ + + diff --git a/Subsurface/Source/Characters/BackgroundSprite/BackgroundCreatureManager.cs b/Subsurface/Source/Characters/BackgroundSprite/BackgroundCreatureManager.cs index 1153c3b6b..4a3de9511 100644 --- a/Subsurface/Source/Characters/BackgroundSprite/BackgroundCreatureManager.cs +++ b/Subsurface/Source/Characters/BackgroundSprite/BackgroundCreatureManager.cs @@ -16,23 +16,37 @@ namespace Barotrauma float checkActiveTimer; - private List prefabs; - private List activeSprites; + private List prefabs = new List(); + private List activeSprites = new List(); public BackgroundCreatureManager(string configPath) { - activeSprites = new List(); - prefabs = new List(); - - XDocument doc = ToolBox.TryLoadXml(configPath); - if (doc == null || doc.Root == null) return; - - foreach (XElement element in doc.Root.Elements()) + LoadConfig(configPath); + } + public BackgroundCreatureManager(List files) + { + foreach(var file in files) { - prefabs.Add(new BackgroundCreaturePrefab(element)); + LoadConfig(file); } } + private void LoadConfig(string configPath) + { + try + { + XDocument doc = ToolBox.TryLoadXml(configPath); + if (doc == null || doc.Root == null) return; + foreach (XElement element in doc.Root.Elements()) + { + prefabs.Add(new BackgroundCreaturePrefab(element)); + }; + } + catch (Exception e) + { + DebugConsole.ThrowError(String.Format("Failed to load BackgroundCreatures from {0}", configPath), e); + } + } public void SpawnSprites(int count, Vector2? position = null) { activeSprites.Clear(); diff --git a/Subsurface/Source/Characters/BackgroundSprite/BackgroundSpriteManager.cs b/Subsurface/Source/Characters/BackgroundSprite/BackgroundSpriteManager.cs index a69c83229..67521f327 100644 --- a/Subsurface/Source/Characters/BackgroundSprite/BackgroundSpriteManager.cs +++ b/Subsurface/Source/Characters/BackgroundSprite/BackgroundSpriteManager.cs @@ -34,25 +34,39 @@ namespace Barotrauma { const int GridSize = 1000; - private List prefabs; - //private List sprites; + private List prefabs = new List(); + private List[,] sprites; public BackgroundSpriteManager(string configPath) { - //sprites = new List[2,2](); - prefabs = new List(); - - XDocument doc = ToolBox.TryLoadXml(configPath); - if (doc == null || doc.Root == null) return; - - foreach (XElement element in doc.Root.Elements()) + LoadConfig(configPath); + } + public BackgroundSpriteManager(List files) + { + foreach (var file in files) { - prefabs.Add(new BackgroundSpritePrefab(element)); + LoadConfig(file); } } + private void LoadConfig(string configPath) + { + try + { + XDocument doc = ToolBox.TryLoadXml(configPath); + if (doc == null || doc.Root == null) return; + foreach (XElement element in doc.Root.Elements()) + { + prefabs.Add(new BackgroundSpritePrefab(element)); + } + } + catch (Exception e) + { + DebugConsole.ThrowError(String.Format("Failed to load BackgroundSprites from {0}", configPath), e); + } + } public void PlaceSprites(Level level, int amount) { sprites = new List[ diff --git a/Subsurface/Source/ContentPackage.cs b/Subsurface/Source/ContentPackage.cs index caa18b81c..52a3397de 100644 --- a/Subsurface/Source/ContentPackage.cs +++ b/Subsurface/Source/ContentPackage.cs @@ -10,7 +10,7 @@ namespace Barotrauma { public enum ContentType { - None, Jobs, Item, Character, Structure, Executable, LocationTypes, RandomEvents, Missions + None, Jobs, Item, Character, Structure, Executable, LocationTypes, RandomEvents, Missions, BackgroundCreaturePrefabs, BackgroundSpritePrefabs } public class ContentPackage diff --git a/Subsurface/Source/DebugConsole.cs b/Subsurface/Source/DebugConsole.cs index 3a7dce55b..d8aaab928 100644 --- a/Subsurface/Source/DebugConsole.cs +++ b/Subsurface/Source/DebugConsole.cs @@ -181,6 +181,7 @@ namespace Barotrauma NewMessage(" ", Color.Cyan); NewMessage("spawn [creaturename] [near/inside/outside]: spawn a creature at a random spawnpoint (use the second parameter to only select spawnpoints near/inside/outside the submarine)", Color.Cyan); + NewMessage("spawnitem [itemname] [cursor/inventory]: spawn an item at the position of the cursor, in the inventory of the controlled character or at a random spawnpoint if the last parameter is omitted", Color.Cyan); NewMessage(" ", Color.Cyan); @@ -200,7 +201,7 @@ namespace Barotrauma NewMessage("revive: bring the controlled character back from the dead", Color.Cyan); NewMessage(" ", Color.Cyan); - + NewMessage("fixwalls: fixes all the walls", Color.Cyan); NewMessage("fixitems: fixes every item/device in the sub", Color.Cyan); NewMessage("oxygen: replenishes the oxygen in every room to 100%", Color.Cyan); @@ -219,6 +220,7 @@ namespace Barotrauma UpdaterUtil.SaveFileList("filelist.xml"); break; case "spawn": + case "spawncharacter": if (commands.Length == 1) return; Character spawnedCharacter = null; @@ -231,7 +233,7 @@ namespace Barotrauma switch (commands[2].ToLowerInvariant()) { case "inside": - spawnPoint = WayPoint.GetRandom(SpawnType.Human); + spawnPoint = WayPoint.GetRandom(SpawnType.Human, null, Submarine.MainSub); break; case "outside": spawnPoint = WayPoint.GetRandom(SpawnType.Enemy); @@ -293,6 +295,54 @@ namespace Barotrauma spawnedCharacter.SpawnedMidRound = true; } + break; + case "spawnitem": + if (commands.Length < 2) return; + + Vector2? spawnPos = null; + Inventory spawnInventory = null; + + int extraParams = 0; + switch (commands.Last()) + { + case "cursor": + extraParams = 1; + spawnPos = GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition); + break; + case "inventory": + extraParams = 1; + spawnInventory = Character.Controlled == null ? null : Character.Controlled.Inventory; + break; + default: + extraParams = 0; + break; + } + + string itemName = string.Join(" ", commands.Skip(1).Take(commands.Length - extraParams - 1)).ToLowerInvariant(); + + var itemPrefab = MapEntityPrefab.list.Find(ip => ip.Name.ToLowerInvariant() == itemName) as ItemPrefab; + if (itemPrefab == null) + { + ThrowError("Item \""+itemName+"\" not found!"); + return; + } + + if (spawnPos == null && spawnInventory == null) + { + var wp = WayPoint.GetRandom(SpawnType.Human, null, Submarine.MainSub); + spawnPos = wp == null ? Vector2.Zero : wp.WorldPosition; + } + + if (spawnPos != null) + { + Item.Spawner.QueueItem(itemPrefab, (Vector2)spawnPos, false); + + } + else if (spawnInventory != null) + { + Item.Spawner.QueueItem(itemPrefab, (Inventory)spawnInventory, false); + } + break; case "disablecrewai": HumanAIController.DisableCrewAI = !HumanAIController.DisableCrewAI; diff --git a/Subsurface/Source/GameSession/GameSession.cs b/Subsurface/Source/GameSession/GameSession.cs index beb6e15eb..31be54638 100644 --- a/Subsurface/Source/GameSession/GameSession.cs +++ b/Subsurface/Source/GameSession/GameSession.cs @@ -244,7 +244,7 @@ namespace Barotrauma missionButton.UserData = InfoFrameTab.Mission; missionButton.OnClicked = SelectInfoFrameTab; - if (GameMain.Server != null) + if (GameMain.Server != null) { var manageButton = new GUIButton(new Rectangle(200, -30, 130, 20), "Manage players", GUI.Style, infoFrame); manageButton.UserData = InfoFrameTab.ManagePlayers; @@ -269,7 +269,7 @@ namespace Barotrauma break; case InfoFrameTab.Mission: CreateMissionInfo(infoFrame); - break; + break; case InfoFrameTab.ManagePlayers: GameMain.Server.ManagePlayersFrame(infoFrame); break; diff --git a/Subsurface/Source/Items/ItemSpawner.cs b/Subsurface/Source/Items/ItemSpawner.cs index 93e32bed1..4d03c1ced 100644 --- a/Subsurface/Source/Items/ItemSpawner.cs +++ b/Subsurface/Source/Items/ItemSpawner.cs @@ -17,20 +17,20 @@ namespace Barotrauma spawnQueue = new Queue>(); } - //public void QueueItem(ItemPrefab itemPrefab, Vector2 position, bool isNetworkMessage = false) - //{ - // if (!isNetworkMessage && GameMain.Client!=null) - // { - // //clients aren't allowed to spawn new items unless the server says so - // return; - // } + public void QueueItem(ItemPrefab itemPrefab, Vector2 worldPosition, bool isNetworkMessage = false) + { + if (!isNetworkMessage && GameMain.Client != null) + { + //clients aren't allowed to spawn new items unless the server says so + return; + } - // var itemInfo = new Pair(); - // itemInfo.First = itemPrefab; - // itemInfo.Second = position; + var itemInfo = new Pair(); + itemInfo.First = itemPrefab; + itemInfo.Second = worldPosition; - // spawnQueue.Enqueue(itemInfo); - //} + spawnQueue.Enqueue(itemInfo); + } public void QueueItem(ItemPrefab itemPrefab, Inventory inventory, bool isNetworkMessage = false) { @@ -58,17 +58,14 @@ namespace Barotrauma { var itemInfo = spawnQueue.Dequeue(); - //if (itemInfo.Second is Vector2) - //{ - // //todo: take multiple subs into account - // Vector2 position = (Vector2)itemInfo.Second - Submarine.MainSub.HiddenSubPosition; + if (itemInfo.Second is Vector2) + { + var item = new Item(itemInfo.First, (Vector2)itemInfo.Second, null); + AddToSpawnedList(item); - // items.Add(new Item(itemInfo.First, position, null)); - // inventories.Add(null); - - //} - //else - if (itemInfo.Second is Inventory) + items.Add(item); + } + else if (itemInfo.Second is Inventory) { var item = new Item(itemInfo.First, Vector2.Zero, null); AddToSpawnedList(item); @@ -77,7 +74,6 @@ namespace Barotrauma inventory.TryPutItem(item, null); items.Add(item); - //inventories.Add(inventory); } } diff --git a/Subsurface/Source/Map/Levels/LevelRenderer.cs b/Subsurface/Source/Map/Levels/LevelRenderer.cs index 22e4a433a..6324bcd89 100644 --- a/Subsurface/Source/Map/Levels/LevelRenderer.cs +++ b/Subsurface/Source/Map/Levels/LevelRenderer.cs @@ -30,7 +30,7 @@ namespace Barotrauma public LevelRenderer(Level level) { - if (shaftTexture == null) shaftTexture = TextureLoader.FromFile("Content/Map/shaft.png"); + if (shaftTexture == null) shaftTexture = TextureLoader.FromFile("Content/Map/iceWall.png"); if (background==null) { @@ -50,7 +50,12 @@ namespace Barotrauma if (backgroundSpriteManager==null) { - backgroundSpriteManager = new BackgroundSpriteManager("Content/BackgroundSprites/BackgroundSpritePrefabs.xml"); + + var files = GameMain.SelectedPackage.GetFilesOfType(ContentType.BackgroundSpritePrefabs); + if (files.Count > 0) + backgroundSpriteManager = new BackgroundSpriteManager(files); + else + backgroundSpriteManager = new BackgroundSpriteManager("Content/BackgroundSprites/BackgroundSpritePrefabs.xml"); } this.level = level; @@ -173,22 +178,21 @@ namespace Barotrauma Vector2 pos = new Vector2(0.0f, -level.Size.Y);// level.EndPosition; - if (GameMain.GameScreen.Cam.WorldView.Y < -pos.Y - 512) return; + if (GameMain.GameScreen.Cam.WorldView.Y < -pos.Y - 1024) return; - pos.X = GameMain.GameScreen.Cam.WorldView.X -512.0f; + pos.X = GameMain.GameScreen.Cam.WorldView.X -1024; - int width = (int)(Math.Ceiling(GameMain.GameScreen.Cam.WorldView.Width / 512.0f + 2.0f) * 512.0f); + int width = (int)(Math.Ceiling(GameMain.GameScreen.Cam.WorldView.Width / 1024 + 4.0f) * 1024); + GUI.DrawRectangle(spriteBatch,new Rectangle((int)(MathUtils.Round(pos.X, 1024)), (int)-GameMain.GameScreen.Cam.WorldView.Y, width, (int)(GameMain.GameScreen.Cam.WorldView.Y - level.Size.Y) + 30),Color.Black, true); spriteBatch.Draw(shaftTexture, - new Rectangle((int)(MathUtils.Round(pos.X, 512.0f)), (int)pos.Y, width, 512), - new Rectangle(0, 0, width, 256), + new Rectangle((int)(MathUtils.Round(pos.X, 1024)), (int)pos.Y, width, 1024), + new Rectangle(0, 0, width, 1024), level.BackgroundColor, 0.0f, Vector2.Zero, SpriteEffects.None, 0.0f); - GUI.DrawRectangle(spriteBatch, - new Rectangle((int)(MathUtils.Round(pos.X, 512.0f)), (int)-GameMain.GameScreen.Cam.WorldView.Y, width, (int)(GameMain.GameScreen.Cam.WorldView.Y - level.Size.Y)+10), - Color.Black, true ); + //background.DrawTiled(spriteBatch, // (backgroundPos.Y < 0) ? new Vector2(0.0f, -backgroundPos.Y) : Vector2.Zero, @@ -199,6 +203,7 @@ namespace Barotrauma public void RenderWalls(GraphicsDevice graphicsDevice, Camera cam) { + if (wallVertices == null) return; basicEffect.World = cam.ShaderTransform diff --git a/Subsurface/Source/Networking/BanList.cs b/Subsurface/Source/Networking/BanList.cs index f9960dbd1..8a650ed73 100644 --- a/Subsurface/Source/Networking/BanList.cs +++ b/Subsurface/Source/Networking/BanList.cs @@ -12,6 +12,20 @@ namespace Barotrauma.Networking public string Name; public string IP; + public bool CompareTo(string ipCompare) + { + int rangeBanIndex = IP.IndexOf(".x"); + if (rangeBanIndex<=-1) + { + return ipCompare == IP; + } + else + { + if (ipCompare.Length < rangeBanIndex) return false; + return ipCompare.Substring(0, rangeBanIndex) == IP.Substring(0, rangeBanIndex); + } + } + public BannedPlayer(string name, string ip) { this.Name = name; @@ -74,7 +88,7 @@ namespace Barotrauma.Networking public bool IsBanned(string IP) { - return bannedPlayers.Any(bp => bp.IP == IP); + return bannedPlayers.Any(bp => bp.CompareTo(IP)); } public GUIComponent CreateBanFrame(GUIComponent parent) @@ -94,6 +108,12 @@ namespace Barotrauma.Networking var removeButton = new GUIButton(new Rectangle(0, 0, 100, 20), "Remove", Alignment.Right | Alignment.CenterY, GUI.Style, textBlock); removeButton.UserData = bannedPlayer; removeButton.OnClicked = RemoveBan; + if (bannedPlayer.IP.IndexOf(".x") <= -1) + { + var rangeBanButton = new GUIButton(new Rectangle(-100, 0, 100, 20), "Ban range", Alignment.Right | Alignment.CenterY, GUI.Style, textBlock); + rangeBanButton.UserData = bannedPlayer; + rangeBanButton.OnClicked = RangeBan; + } } return banFrame; @@ -120,6 +140,46 @@ namespace Barotrauma.Networking return true; } + public string ToRange(string ip) + { + for (int i = ip.Length - 1; i > 0; i--) + { + if (ip[i] == '.') + { + ip = ip.Substring(0, i) + ".x"; + break; + } + } + return ip; + } + + private bool RangeBan(GUIButton button, object obj) + { + BannedPlayer banned = obj as BannedPlayer; + if (banned == null) return false; + + banned.IP = ToRange(banned.IP); + + BannedPlayer bp; + while ((bp = bannedPlayers.Find(x => banned.CompareTo(x.IP)))!=null) + { + //remove all specific bans that are now covered by the rangeban + bannedPlayers.Remove(bp); + } + + bannedPlayers.Add(banned); + + Save(); + + if (banFrame != null) + { + banFrame.Parent.RemoveChild(banFrame); + CreateBanFrame(banFrame.Parent); + } + + return true; + } + private bool CloseFrame(GUIButton button, object obj) { banFrame = null; diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs index 5ac52c0ae..7e28934e0 100644 --- a/Subsurface/Source/Networking/GameServer.cs +++ b/Subsurface/Source/Networking/GameServer.cs @@ -116,6 +116,12 @@ namespace Barotrauma.Networking settingsButton.OnClicked = ToggleSettingsFrame; settingsButton.UserData = "settingsButton"; + whitelist = new WhiteList(); + + GUIButton whitelistButton = new GUIButton(new Rectangle(GameMain.GraphicsWidth - 170 - 170 - 170 - 170, 20, 150, 20), "Whitelist", Alignment.TopLeft, GUI.Style, inGameHUD); + whitelistButton.OnClicked = ToggleWhiteListFrame; + whitelistButton.UserData = "whitelistButton"; + banList = new BanList(); LoadSettings(); @@ -284,6 +290,7 @@ namespace Barotrauma.Networking { if (ShowNetStats) netStats.Update(deltaTime); if (settingsFrame != null) settingsFrame.Update(deltaTime); + if (whitelist.WhiteListFrame != null) whitelist.WhiteListFrame.Update(deltaTime); if (!started) return; @@ -895,6 +902,10 @@ namespace Barotrauma.Networking log.LogFrame.Update(0.016f); log.LogFrame.Draw(spriteBatch); } + else if (whitelist.WhiteListFrame != null) + { + whitelist.WhiteListFrame.Draw(spriteBatch); + } if (!ShowNetStats) return; @@ -1009,6 +1020,10 @@ namespace Barotrauma.Networking banButton.UserData = character.Name; banButton.OnClicked += GameMain.NetLobbyScreen.BanPlayer; + var rangebanButton = new GUIButton(new Rectangle(0, -25, 100, 20), "Ban range", Alignment.BottomRight, GUI.Style, characterFrame); + rangebanButton.UserData = character.Name; + rangebanButton.OnClicked += GameMain.NetLobbyScreen.BanPlayerRange; + var kickButton = new GUIButton(new Rectangle(0, 0, 100, 20), "Kick", Alignment.BottomLeft, GUI.Style, characterFrame); kickButton.UserData = character.Name; kickButton.OnClicked += GameMain.NetLobbyScreen.KickPlayer; diff --git a/Subsurface/Source/Networking/GameServerLogin.cs b/Subsurface/Source/Networking/GameServerLogin.cs index b5be118b1..f50ca2198 100644 --- a/Subsurface/Source/Networking/GameServerLogin.cs +++ b/Subsurface/Source/Networking/GameServerLogin.cs @@ -156,6 +156,14 @@ namespace Barotrauma.Networking unauthenticatedClients.Remove(unauthClient); unauthClient = null; return; + } + +#endif + if (!whitelist.IsWhiteListed(name, inc.SenderConnection.RemoteEndPoint.Address.ToString())) + { + inc.SenderConnection.Disconnect("You're not in this server's whitelist."); + DebugConsole.NewMessage(name + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (not in whitelist)", Color.Red); + return; } if (!Client.IsValidName(name)) { diff --git a/Subsurface/Source/Networking/GameServerSettings.cs b/Subsurface/Source/Networking/GameServerSettings.cs index e0fcf3d7e..aec0b8047 100644 --- a/Subsurface/Source/Networking/GameServerSettings.cs +++ b/Subsurface/Source/Networking/GameServerSettings.cs @@ -55,6 +55,7 @@ namespace Barotrauma.Networking private bool registeredToMaster; + private WhiteList whitelist; private BanList banList; private string password; @@ -253,7 +254,7 @@ namespace Barotrauma.Networking private void CreateSettingsFrame() { - settingsFrame = new GUIFrame(new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.Black * 0.5f); + settingsFrame = new GUIFrame(new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.Black * 0.5f); GUIFrame innerFrame = new GUIFrame(new Rectangle(0, 0, 400, 430), null, Alignment.Center, GUI.Style, settingsFrame); innerFrame.Padding = new Vector4(20.0f, 20.0f, 20.0f, 20.0f); @@ -643,6 +644,20 @@ namespace Barotrauma.Networking return false; } + public bool ToggleWhiteListFrame(GUIButton button, object obj) + { + if (whitelist.WhiteListFrame == null) + { + whitelist.CreateWhiteListFrame(); + } + else + { + whitelist.CloseFrame(); + } + + return false; + } + public void ManagePlayersFrame(GUIFrame infoFrame) { GUIListBox cList = new GUIListBox(new Rectangle(0, 0, 0, 300), Color.White * 0.7f, GUI.Style, infoFrame); @@ -664,13 +679,17 @@ namespace Barotrauma.Networking Alignment.Left, Alignment.Left, null, frame); - var banButton = new GUIButton(new Rectangle(-120, 0, 100, 20), "Ban", Alignment.Right | Alignment.CenterY, GUI.Style, frame); + var banButton = new GUIButton(new Rectangle(-110, 0, 100, 20), "Ban", Alignment.Right | Alignment.CenterY, GUI.Style, frame); banButton.UserData = c.name; - banButton.OnClicked += GameMain.NetLobbyScreen.BanPlayer; + banButton.OnClicked = GameMain.NetLobbyScreen.BanPlayer; + + var rangebanButton = new GUIButton(new Rectangle(-220, 0, 100, 20), "Ban range", Alignment.Right | Alignment.CenterY, GUI.Style, frame); + rangebanButton.UserData = c.name; + rangebanButton.OnClicked = GameMain.NetLobbyScreen.BanPlayerRange; var kickButton = new GUIButton(new Rectangle(0, 0, 100, 20), "Kick", Alignment.Right | Alignment.CenterY, GUI.Style, frame); kickButton.UserData = c.name; - kickButton.OnClicked += GameMain.NetLobbyScreen.KickPlayer; + kickButton.OnClicked = GameMain.NetLobbyScreen.KickPlayer; textBlock.Padding = new Vector4(5.0f, 0.0f, 5.0f, 0.0f); } diff --git a/Subsurface/Source/Networking/NetworkMember.cs b/Subsurface/Source/Networking/NetworkMember.cs index 87adf7148..a0dfc2c65 100644 --- a/Subsurface/Source/Networking/NetworkMember.cs +++ b/Subsurface/Source/Networking/NetworkMember.cs @@ -272,7 +272,7 @@ namespace Barotrauma.Networking public virtual void SendChatMessage(string message, ChatMessageType? type = null) { } - public virtual void KickPlayer(string kickedName, bool ban) { } + public virtual void KickPlayer(string kickedName, bool ban, bool range = false) { } public virtual void Update(float deltaTime) { diff --git a/Subsurface/Source/Networking/WhiteList.cs b/Subsurface/Source/Networking/WhiteList.cs new file mode 100644 index 000000000..486bf32c3 --- /dev/null +++ b/Subsurface/Source/Networking/WhiteList.cs @@ -0,0 +1,224 @@ +using Microsoft.Xna.Framework; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace Barotrauma.Networking +{ + class WhiteListedPlayer + { + public string Name; + public string IP; + + public WhiteListedPlayer(string name,string ip) + { + Name = name; + IP = ip; + } + } + + class WhiteList + { + const string SavePath = "Data/whitelist.txt"; + + private List whitelistedPlayers; + public List WhiteListedPlayers + { + get { return whitelistedPlayers; } + } + + private GUIComponent whitelistFrame; + private GUIComponent innerlistFrame; + + private GUITextBox nameBox; + private GUITextBox ipBox; + + public bool enabled; + + public GUIComponent WhiteListFrame + { + get { return whitelistFrame; } + } + + public WhiteList() + { + enabled = false; + whitelistedPlayers = new List(); + + if (File.Exists(SavePath)) + { + string[] lines; + try + { + lines = File.ReadAllLines(SavePath); + } + catch (Exception e) + { + DebugConsole.ThrowError("Failed to open whitelist in " + SavePath, e); + return; + } + + foreach (string line in lines) + { + if (line[0] == '#') + { + string lineval = line.Substring(1, line.Length - 1); + if (lineval.ToLower()=="true" || Convert.ToInt32(lineval)!=0) + { + enabled = true; + } + else + { + enabled = false; + } + } + else + { + string[] separatedLine = line.Split(','); + if (separatedLine.Length < 2) continue; + + string name = String.Join(",", separatedLine.Take(separatedLine.Length - 1)); + string ip = separatedLine.Last(); + + whitelistedPlayers.Add(new WhiteListedPlayer(name, ip)); + } + } + } + } + + public void Save() + { + GameServer.Log("Saving whitelist", null); + + List lines = new List(); + + if (enabled) + { + lines.Add("#true"); + } + else + { + lines.Add("#false"); + } + foreach (WhiteListedPlayer wlp in whitelistedPlayers) + { + lines.Add(wlp.Name + "," + wlp.IP); + } + + try + { + File.WriteAllLines(SavePath, lines); + } + catch (Exception e) + { + DebugConsole.ThrowError("Saving the whitelist to " + SavePath + " failed", e); + } + } + + public bool IsWhiteListed(string name, string ip) + { + if (!enabled) return true; + WhiteListedPlayer wlp = whitelistedPlayers.Find(p => p.Name == name); + if (wlp == null) return false; + if (wlp.IP != ip && !string.IsNullOrWhiteSpace(wlp.IP)) return false; + return true; + } + + public GUIComponent CreateWhiteListFrame() + { + whitelistFrame = new GUIFrame(new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.Black * 0.5f); + + GUIFrame innerFrame = new GUIFrame(new Rectangle(0, 0, 500, 430), null, Alignment.Center, GUI.Style, whitelistFrame); + innerFrame.Padding = new Vector4(20.0f, 50.0f, 20.0f, 100.0f); + + var closeButton = new GUIButton(new Rectangle(0, 85, 100, 20), "Close", Alignment.BottomRight, GUI.Style, innerFrame); + closeButton.OnClicked = GameMain.Server.ToggleWhiteListFrame; + + new GUITextBlock(new Rectangle(0, -35, 200, 20), "Whitelist", GUI.Style, innerFrame, GUI.LargeFont); + var enabledTick = new GUITickBox(new Rectangle(200, -30, 20, 20), "Enabled", Alignment.Left, innerFrame); + enabledTick.Selected = enabled; + enabledTick.OnSelected = (GUITickBox box) => + { + enabled = !enabled; + if (enabled) + { + foreach (Client c in GameMain.Server.ConnectedClients) + { + if (!IsWhiteListed(c.name,c.Connection.RemoteEndPoint.Address.ToString())) + { + whitelistedPlayers.Add(new WhiteListedPlayer(c.name, c.Connection.RemoteEndPoint.Address.ToString())); + CloseFrame(); CreateWhiteListFrame(); + } + } + } + Save(); + return true; + }; + + new GUITextBlock(new Rectangle(0, 35, 90, 25), "Name:", GUI.Style, Alignment.BottomLeft, Alignment.TopLeft, innerFrame, false, GUI.Font); + nameBox = new GUITextBox(new Rectangle(100, 30, 170, 25), Alignment.BottomLeft, GUI.Style, innerFrame); + nameBox.Font = GUI.Font; + + new GUITextBlock(new Rectangle(0, 65, 90, 25), "IP Address:", GUI.Style, Alignment.BottomLeft, Alignment.TopLeft, innerFrame, false, GUI.Font); + ipBox = new GUITextBox(new Rectangle(100, 60, 170, 25), Alignment.BottomLeft, GUI.Style, innerFrame); + ipBox.Font = GUI.Font; + + var addnewButton = new GUIButton(new Rectangle(300, 45, 150, 20), "Add to whitelist", Alignment.BottomLeft, GUI.Style, innerFrame); + addnewButton.OnClicked = AddToWhiteList; + + innerlistFrame = new GUIListBox(new Rectangle(0, 0, 0, 0), GUI.Style, innerFrame); + + foreach (WhiteListedPlayer wlp in whitelistedPlayers) + { + string blockText = wlp.Name; + if (!string.IsNullOrWhiteSpace(wlp.IP)) blockText += " (" + wlp.IP + ")"; + GUITextBlock textBlock = new GUITextBlock( + new Rectangle(0, 0, 0, 25), + blockText, + GUI.Style, + Alignment.Left, Alignment.Left, innerlistFrame); + textBlock.Padding = new Vector4(10.0f, 10.0f, 0.0f, 0.0f); + textBlock.UserData = wlp; + + var removeButton = new GUIButton(new Rectangle(0, 0, 100, 20), "Remove", Alignment.Right | Alignment.CenterY, GUI.Style, textBlock); + removeButton.UserData = wlp; + removeButton.OnClicked = RemoveFromWhiteList; + } + + return whitelistFrame; + } + + private bool RemoveFromWhiteList(GUIButton button, object obj) + { + WhiteListedPlayer wlp = obj as WhiteListedPlayer; + if (wlp == null) return false; + + DebugConsole.Log("Removing " + wlp.Name + " from whitelist"); + GameServer.Log("Removing " + wlp.Name + " from whitelist", null); + + whitelistedPlayers.Remove(wlp); + Save(); + CloseFrame(); CreateWhiteListFrame(); + + return true; + } + + private bool AddToWhiteList(GUIButton button, object obj) + { + if (string.IsNullOrWhiteSpace(nameBox.Text) || whitelistedPlayers.Find(x => x.Name.ToLower() == nameBox.Text.ToLower()) != null) return false; + whitelistedPlayers.Add(new WhiteListedPlayer(nameBox.Text,ipBox.Text)); + Save(); + CloseFrame(); CreateWhiteListFrame(); + return true; + } + + public bool CloseFrame(GUIButton button=null, object obj=null) + { + whitelistFrame = null; + + return true; + } + } +} diff --git a/Subsurface/Source/Screens/GameScreen.cs b/Subsurface/Source/Screens/GameScreen.cs index dd0880ec7..611616aad 100644 --- a/Subsurface/Source/Screens/GameScreen.cs +++ b/Subsurface/Source/Screens/GameScreen.cs @@ -33,8 +33,12 @@ namespace Barotrauma renderTarget = new RenderTarget2D(graphics, GameMain.GraphicsWidth, GameMain.GraphicsHeight); renderTargetWater = new RenderTarget2D(graphics, GameMain.GraphicsWidth, GameMain.GraphicsHeight); renderTargetAir = new RenderTarget2D(graphics, GameMain.GraphicsWidth, GameMain.GraphicsHeight); - - BackgroundCreatureManager = new BackgroundCreatureManager("Content/BackgroundSprites/BackgroundCreaturePrefabs.xml"); + + var files = GameMain.SelectedPackage.GetFilesOfType(ContentType.BackgroundCreaturePrefabs); + if(files.Count > 0) + BackgroundCreatureManager = new BackgroundCreatureManager(files); + else + BackgroundCreatureManager = new BackgroundCreatureManager("Content/BackgroundSprites/BackgroundCreaturePrefabs.xml"); #if LINUX var blurEffect = content.Load("blurshader_opengl"); diff --git a/Subsurface/Source/Screens/NetLobbyScreen.cs b/Subsurface/Source/Screens/NetLobbyScreen.cs index 7cf4cf460..d90197890 100644 --- a/Subsurface/Source/Screens/NetLobbyScreen.cs +++ b/Subsurface/Source/Screens/NetLobbyScreen.cs @@ -413,8 +413,12 @@ namespace Barotrauma GUIButton settingsButton = new GUIButton(new Rectangle(-100, 0, 80, 30), "Settings", Alignment.BottomRight, GUI.Style, infoFrame); settingsButton.OnClicked = GameMain.Server.ToggleSettingsFrame; - settingsButton.UserData = "settingsButton"; - + settingsButton.UserData = "settingsButton"; + + GUIButton whitelistButton = new GUIButton(new Rectangle(-200, 0, 80, 30), "Whitelist", Alignment.BottomRight, GUI.Style, infoFrame); + whitelistButton.OnClicked = GameMain.Server.ToggleWhiteListFrame; + whitelistButton.UserData = "whitelistButton"; + if (subList.Selected == null) subList.Select(Math.Max(0, prevSelectedSub)); if (shuttleList.Selected == null) { @@ -788,7 +792,7 @@ namespace Barotrauma playerFrame = new GUIFrame(new Rectangle(0, 0, 0, 0), Color.Black * 0.3f); - var playerFrameInner = new GUIFrame(new Rectangle(0, 0, 300, 150), null, Alignment.Center, GUI.Style, playerFrame); + var playerFrameInner = new GUIFrame(new Rectangle(0, 0, 300, 250), null, Alignment.Center, GUI.Style, playerFrame); playerFrameInner.Padding = new Vector4(20.0f, 20.0f, 20.0f, 20.0f); new GUITextBlock(new Rectangle(0,0,200,20), component.UserData.ToString(), @@ -849,7 +853,7 @@ namespace Barotrauma if (GameMain.Server != null || GameMain.Client.HasPermission(ClientPermissions.Kick)) { - var kickButton = new GUIButton(new Rectangle(0, -30, 100, 20), "Kick", Alignment.BottomLeft, GUI.Style, playerFrameInner); + var kickButton = new GUIButton(new Rectangle(0, -50, 100, 20), "Kick", Alignment.BottomLeft, GUI.Style, playerFrameInner); kickButton.UserData = obj; kickButton.OnClicked += KickPlayer; kickButton.OnClicked += ClosePlayerFrame; @@ -861,6 +865,11 @@ namespace Barotrauma banButton.UserData = obj; banButton.OnClicked += BanPlayer; banButton.OnClicked += ClosePlayerFrame; + + var rangebanButton = new GUIButton(new Rectangle(0, -25, 100, 20), "Ban range", Alignment.BottomLeft, GUI.Style, playerFrameInner); + rangebanButton.UserData = obj; + rangebanButton.OnClicked += BanPlayerRange; + rangebanButton.OnClicked += ClosePlayerFrame; } var closeButton = new GUIButton(new Rectangle(0, 0, 100, 20), "Close", Alignment.BottomRight, GUI.Style, playerFrameInner); @@ -903,8 +912,24 @@ namespace Barotrauma else if (GameMain.Client != null && GameMain.Client.HasPermission(ClientPermissions.Ban)) { GameMain.Client.KickPlayer(userData.ToString(), true); - } + } + + return false; + } + public bool BanPlayerRange(GUIButton button, object userData) + { + if (userData == null) return false; + + if (GameMain.Server != null) + { + GameMain.Server.KickPlayer(userData.ToString(), true, true); + } + else if (GameMain.Client != null && GameMain.Client.HasPermission(ClientPermissions.Ban)) + { + GameMain.Client.KickPlayer(userData.ToString(), true, true); + } + return false; } diff --git a/Subsurface/changelog.txt b/Subsurface/changelog.txt index 261fa063d..6d3e0eb50 100644 --- a/Subsurface/changelog.txt +++ b/Subsurface/changelog.txt @@ -1,3 +1,13 @@ +--------------------------------------------------------------------------------------------------------- +v0.5.1.2 +--------------------------------------------------------------------------------------------------------- + +- hacked clients can't join a full server or change the name of their character anymore +- option to choose which character to control using the "control" command when there are multiple +characters/creatures with the same name +- a console command for spawning items +- the server logs show who sent each chat message + --------------------------------------------------------------------------------------------------------- v0.5.1.1 ---------------------------------------------------------------------------------------------------------