From 400084f9e598b00f261d862104c71b397d7cd024 Mon Sep 17 00:00:00 2001 From: Sebastian Broberg Date: Sat, 3 Sep 2016 18:05:26 +0200 Subject: [PATCH 1/7] BackgroundCreatureManager and BackgroundSpriteManager can be overridden via Content packages Changed "topshaft" --- .../BackgroundCreatureManager.cs | 34 +++++++++++++------ .../BackgroundSpriteManager.cs | 34 +++++++++++++------ Subsurface/Source/ContentPackage.cs | 2 +- Subsurface/Source/Map/Levels/LevelRenderer.cs | 25 ++++++++------ Subsurface/Source/Screens/GameScreen.cs | 8 +++-- 5 files changed, 70 insertions(+), 33 deletions(-) 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/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/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"); From 05f8805f8139e4a96c11510d0dcc7b12df9144aa Mon Sep 17 00:00:00 2001 From: Sebastian Broberg Date: Sat, 3 Sep 2016 18:08:10 +0200 Subject: [PATCH 2/7] Forgot updated package. --- Subsurface/Data/ContentPackages/Vanilla 0.3.xml | 2 ++ 1 file changed, 2 insertions(+) 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 @@ + + From ef2b0d8721d3fc19ba3eb252b5dde857f536b559 Mon Sep 17 00:00:00 2001 From: juanjp600 Date: Sat, 3 Sep 2016 14:57:36 -0300 Subject: [PATCH 3/7] Whitelist + conflict resolve --- .vs/Subsurface_Solution/v14/.suo | Bin 837120 -> 951808 bytes Subsurface/Barotrauma.csproj | 100 +++++------ Subsurface/Source/GameSession/GameSession.cs | 4 +- Subsurface/Source/Networking/BanList.cs | 62 ++++++- Subsurface/Source/Networking/GameClient.cs | 2 +- Subsurface/Source/Networking/GameServer.cs | 30 +++- .../Source/Networking/GameServerLogin.cs | 25 ++- .../Source/Networking/GameServerSettings.cs | 23 ++- Subsurface/Source/Networking/NetworkMember.cs | 2 +- Subsurface/Source/Networking/WhiteList.cs | 155 ++++++++++++++++++ Subsurface/Source/Screens/NetLobbyScreen.cs | 35 +++- 11 files changed, 368 insertions(+), 70 deletions(-) create mode 100644 Subsurface/Source/Networking/WhiteList.cs diff --git a/.vs/Subsurface_Solution/v14/.suo b/.vs/Subsurface_Solution/v14/.suo index 188fc21d54af280052ad9995ae6d2807c2c2c798..f87552f79d3c88533326ad9e2ea2d45ab373a83f 100644 GIT binary patch delta 90385 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∋CyJlmfoHqokJa&X3 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

1X3u?S!;KRw6V}oAH7vo zB-o@1W9|nKnpZix_8X_kuI#WhkxK42Maa9JH!jf8@TpJ$O4DG>nee_>1Rm_2k)h)? zQx$jKo!DhKTa$~e8eEP&j;GSKVg#Walc?-#AzaS+i}7)97$+2Q3;q(%ec@F#tm3%Q zLc7ND{urnN%pTKC!>Po_6e8zm7~eKh_~RZc-Zi*^GBM0KFX*Y{4Y9pegBE%Q##Bo< zEYd~Oj0Y(3St(V1@CBop_bOX}z+_uNtdTK$fh6J&dOU}zF7dq}BB3-ia6nd<+}yi# zD9hA}ijIgeR51e{*P`jLXfEApjBeruaZ@R8wdZujhvEGj`Id2@!E4^X8X^MXvVo0L zDap8_UUCmq3R{I?Vfuatr9NmxIKv_16v@j12B89>LKz<94aEk7`GUK{9Cl@^-2P+Z zKEbPFOclM_PchRS_&#$~B{Akux*&y6VKx-y*pa5i9E}_8vG%IU4rTwH zCwB!klsq|iu`%kx+&iHs&pwfy%rU>peTKKcE$|Yx{!MizMIcb9FNshE% zNYmt^&y44rdzlQFo}qo!YgXKA%d7M>;{^HS&&K24bve|KD@7lAVRW}8RRGGcy>z)Q zvZ?rUV-l5Tm?Pz}lIe5a3)G4M{SRjNyMu}@z`FI&BwZLHKTO>T-qIkl++y;TZB0xA z0d1+P#Tro=V)Bj-%;f^tv;zBB0X^N4z zC7Ze%yqWirT!vQNm91U1u4AcHwY4Qe&ONjS&lylq^$sJ%@i}fge z+%%2Wy&(;ujgOf^<%`2iyq0XTF^(!SL~HBn&HD`A>EHfTzC;YtR_J8k0CRh>euI}$ zyVDr);V!`na`_L)#cR`6G;Az)i8+1eQbkj}ue>YNY&Ou2S3MTMwRM|f>e##59Kh|N zmXFuVEAOoPsBJ;LBZ%OW);pQ0bUoxzN3r${e z+qwENlw#J10o;4uAq~a4?XQSHh}e%obKWp=SDCdc=9;bCC-SEird9&k?huoUPYDS0 z9$~i2kMrh<9F@ew^lKRo^(K0xxx@>G8CN?+(5_CLtitSsLK|!jgIU#-!5<7Vm_;-LA%ZU=){ZWbu@O5xeEoq zYHm)wUp5b?kGGp&mQTp$r#a$YG54Ww7xI2oy3H(6MPIEimF_f0vkQCD8{08A3wjAY zi+Qh^yU}wmnO9QL%jRT?UZpj*NlmAu6?Q%z z6*N3q7WG`9C*sQ#g6cY+ev#DgH*`LB*O zu~K%h_-Q${*t}k#qErliF9k8xM(fe?fYoML#=XyWxi95M=9-7<<=|}d5Y7vAP`b4A zE)y^1!HIRVCQCDsmUl4)YJGSrY=%`zIj>^n-n2sV2Ei-(Vs&=!@H^hgVLfj32sW+H F{{!O}pIHC^ delta 28597 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 diff --git a/Subsurface/Barotrauma.csproj b/Subsurface/Barotrauma.csproj index 7840f615f..223362a38 100644 --- a/Subsurface/Barotrauma.csproj +++ b/Subsurface/Barotrauma.csproj @@ -1,52 +1,52 @@ - - - - Debug - x86 - 8.0.30703 - 2.0 - {008C0F83-E914-4966-9135-EA885059EDD8} - WinExe - Properties - Barotrauma - Barotrauma - 512 - false - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 0.1.0.%2a - false - true - v4.5 - - - - x86 - true - full - false - bin\Windows\Debug\ - DEBUG;TRACE;WINDOWS - prompt - 4 - false - - - x86 - pdbonly - true - bin\Windows\Release\ - TRACE;WINDOWS - + + + + Debug + x86 + 8.0.30703 + 2.0 + {008C0F83-E914-4966-9135-EA885059EDD8} + WinExe + Properties + Barotrauma + Barotrauma + 512 + false + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 0.1.0.%2a + false + true + v4.5 + + + + x86 + true + full + false + bin\Windows\Debug\ + DEBUG;TRACE;WINDOWS + prompt + 4 + false + + + x86 + pdbonly + true + bin\Windows\Release\ + TRACE;WINDOWS + @@ -1455,5 +1455,5 @@ - --> + --> \ No newline at end of file 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/Networking/BanList.cs b/Subsurface/Source/Networking/BanList.cs index f9960dbd1..0b80fb717 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/GameClient.cs b/Subsurface/Source/Networking/GameClient.cs index 22faf005a..a415b93f1 100644 --- a/Subsurface/Source/Networking/GameClient.cs +++ b/Subsurface/Source/Networking/GameClient.cs @@ -1025,7 +1025,7 @@ namespace Barotrauma.Networking client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered); } - public override void KickPlayer(string kickedName, bool ban) + public override void KickPlayer(string kickedName, bool ban, bool range = false) { if (!permissions.HasFlag(ClientPermissions.Kick) && !ban) return; if (!permissions.HasFlag(ClientPermissions.Ban) && ban) return; diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs index 8e4898810..6cfa964d1 100644 --- a/Subsurface/Source/Networking/GameServer.cs +++ b/Subsurface/Source/Networking/GameServer.cs @@ -114,6 +114,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(); @@ -282,6 +288,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; @@ -477,6 +484,11 @@ namespace Barotrauma.Networking } break; case NetIncomingMessageType.Data: + if (banList.IsBanned(inc.SenderEndPoint.Address.ToString())) + { + inc.SenderConnection.Disconnect("You have been banned from the server"); + return; + } byte packetType = inc.ReadByte(); @@ -1172,7 +1184,7 @@ namespace Barotrauma.Networking //if (GameMain.GameSession!=null) GameMain.GameSession.CrewManager.CreateCrewFrame(crew); } - public override void KickPlayer(string playerName, bool ban) + public override void KickPlayer(string playerName, bool ban, bool range = false) { playerName = playerName.ToLowerInvariant(); @@ -1180,17 +1192,19 @@ namespace Barotrauma.Networking c.name.ToLowerInvariant() == playerName || (c.Character != null && c.Character.Name.ToLowerInvariant() == playerName)); - KickClient(client, ban); + KickClient(client, ban, range); } - public void KickClient(Client client, bool ban = false) + public void KickClient(Client client, bool ban = false, bool range = false) { if (client == null) return; if (ban) { DisconnectClient(client, client.name + " has been banned from the server", "You have been banned from the server"); - banList.BanPlayer(client.name, client.Connection.RemoteEndPoint.Address.ToString()); + string ip = client.Connection.RemoteEndPoint.Address.ToString(); + if (range) { ip = banList.ToRange(ip); } + banList.BanPlayer(client.name, ip); } else { @@ -1291,6 +1305,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; @@ -1431,6 +1449,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 ff617de88..762281a01 100644 --- a/Subsurface/Source/Networking/GameServerLogin.cs +++ b/Subsurface/Source/Networking/GameServerLogin.cs @@ -45,7 +45,7 @@ namespace Barotrauma.Networking inc.SenderConnection.Deny("Connection error - already joined"); return; } - + int nonce = CryptoRandom.Instance.Next(); var msg = server.CreateMessage(); msg.Write(nonce); @@ -57,6 +57,7 @@ namespace Barotrauma.Networking private void CheckAuthentication(NetIncomingMessage inc) { + string whitelistPw = ""; var unauthenticatedClient = unauthenticatedClients.Find(uc => uc.Connection == inc.SenderConnection); if (unauthenticatedClient != null) { @@ -69,10 +70,26 @@ namespace Barotrauma.Networking inc.Decrypt(algo); string rdPw = inc.ReadString(); - if (rdPw != saltedPw) + if (!whitelist.enabled) { - inc.SenderConnection.Disconnect("Wrong password!"); - return; + if (rdPw != saltedPw) + { + inc.SenderConnection.Disconnect("Wrong password!"); + return; + } + } + else + { + WhiteListedPlayer wlp = whitelist.WhiteListedPlayers.Find(x => x.GetHashedPassword(unauthenticatedClient.Nonce) == saltedPw); + if (wlp==null) + { + inc.SenderConnection.Disconnect("Wrong password or name!"); + return; + } + else + { + whitelistPw = wlp.Password; + } } } else diff --git a/Subsurface/Source/Networking/GameServerSettings.cs b/Subsurface/Source/Networking/GameServerSettings.cs index fe6161671..0da9f9202 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; @@ -257,7 +258,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); @@ -647,6 +648,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); @@ -668,10 +683,14 @@ 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; + 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; diff --git a/Subsurface/Source/Networking/NetworkMember.cs b/Subsurface/Source/Networking/NetworkMember.cs index d18587249..c75ee1094 100644 --- a/Subsurface/Source/Networking/NetworkMember.cs +++ b/Subsurface/Source/Networking/NetworkMember.cs @@ -336,7 +336,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..ad12adf56 --- /dev/null +++ b/Subsurface/Source/Networking/WhiteList.cs @@ -0,0 +1,155 @@ +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 Password; + public string IP; + + public WhiteListedPlayer(string name,string password,string ip) + { + Name = name; + Password = password; + IP = ip; + } + + public string GetHashedPassword(int nonce) + { + string saltedPw = Password; + saltedPw = saltedPw + Convert.ToString(nonce); + saltedPw = Encoding.UTF8.GetString(Lidgren.Network.NetUtility.ComputeSHAHash(Encoding.UTF8.GetBytes(saltedPw))); + return saltedPw; + } + } + + class WhiteList + { + private List whitelistedPlayers; + public List WhiteListedPlayers + { + get { return whitelistedPlayers; } + } + + private GUIComponent whitelistFrame; + private GUIComponent innerlistFrame; + + private GUITextBox nameBox; + private GUITextBox ipBox; + private GUITextBox pwBox; + + public bool enabled; + + public GUIComponent WhiteListFrame + { + get { return whitelistFrame; } + } + + public WhiteList() + { + enabled = false; + whitelistedPlayers = new List(); + } + + public bool IsWhiteListed(string name, string password, string ip) + { + if (!enabled) return true; + WhiteListedPlayer wlp = whitelistedPlayers.Find(p => p.Name == name); + if (wlp == null) return false; + if (wlp.Password != password && !string.IsNullOrWhiteSpace(wlp.Password)) 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, 460), null, Alignment.Center, GUI.Style, whitelistFrame); + innerFrame.Padding = new Vector4(20.0f, 50.0f, 20.0f, 130.0f); + + var closeButton = new GUIButton(new Rectangle(0, 115, 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; + 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), "Password:", GUI.Style, Alignment.BottomLeft, Alignment.TopLeft, innerFrame, false, GUI.Font); + pwBox = new GUITextBox(new Rectangle(100, 60, 170, 25), Alignment.BottomLeft, GUI.Style, innerFrame); + pwBox.Font = GUI.Font; + + new GUITextBlock(new Rectangle(0, 95, 90, 25), "IP Address:", GUI.Style, Alignment.BottomLeft, Alignment.TopLeft, innerFrame, false, GUI.Font); + ipBox = new GUITextBox(new Rectangle(100, 90, 170, 25), Alignment.BottomLeft, GUI.Style, innerFrame); + ipBox.Font = GUI.Font; + + var addnewButton = new GUIButton(new Rectangle(300, 55, 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); + 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,pwBox.Text,ipBox.Text)); + CloseFrame(); CreateWhiteListFrame(); + return true; + } + + public bool CloseFrame(GUIButton button=null, object obj=null) + { + whitelistFrame = null; + + return true; + } + } +} diff --git a/Subsurface/Source/Screens/NetLobbyScreen.cs b/Subsurface/Source/Screens/NetLobbyScreen.cs index 309306e04..8c9fb70a5 100644 --- a/Subsurface/Source/Screens/NetLobbyScreen.cs +++ b/Subsurface/Source/Screens/NetLobbyScreen.cs @@ -396,8 +396,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) { @@ -771,7 +775,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(), @@ -832,7 +836,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; @@ -844,6 +848,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); @@ -886,8 +895,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; } From efa8b4da5102d8e1a76d1558328144fa394ff9fb Mon Sep 17 00:00:00 2001 From: juanjp600 Date: Sat, 3 Sep 2016 17:18:44 -0300 Subject: [PATCH 4/7] Removed per-user password from whitelist --- Subsurface/Barotrauma.csproj | 2797 +++++++++-------- .../Source/Networking/GameServerLogin.cs | 33 +- Subsurface/Source/Networking/WhiteList.cs | 104 +- 3 files changed, 1454 insertions(+), 1480 deletions(-) diff --git a/Subsurface/Barotrauma.csproj b/Subsurface/Barotrauma.csproj index 223362a38..dd382214a 100644 --- a/Subsurface/Barotrauma.csproj +++ b/Subsurface/Barotrauma.csproj @@ -51,1404 +51,1405 @@ Only *.allowedextension files will be included, which doesn't exist in my case. --> .allowedextension - - prompt - 4 - false - - - Icon.ico - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - False - C:\Program Files (x86)\MonoGame\v3.0\Assemblies\Windows\MonoGame.Framework.dll - - - False - .\NVorbis.dll - - - False - C:\Program Files (x86)\MonoGame\v3.0\Assemblies\DesktopGL\OpenTK.dll - - - - ..\packages\RestSharp.105.1.0\lib\net4\RestSharp.dll - - - - - - - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - Designer - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - Designer - PreserveNewest - - - PreserveNewest - - - Designer - PreserveNewest - - - PreserveNewest - - - Designer - PreserveNewest - - - Designer - PreserveNewest - - - Designer - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - Designer - PreserveNewest - - - Designer - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - Designer - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - Designer - PreserveNewest - - - PreserveNewest - - - PreserveNewest - Designer - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - Designer - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - Designer - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - Designer - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - Designer - - - PreserveNewest - Designer - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - Designer - - - PreserveNewest - - - Designer - PreserveNewest - - - PreserveNewest - - - Designer - PreserveNewest - - - PreserveNewest - - - Designer - PreserveNewest - - - PreserveNewest - Designer - - - PreserveNewest - - - PreserveNewest - Designer - - - PreserveNewest - - - PreserveNewest - Designer - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - Designer - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - Designer - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - Designer - - - PreserveNewest - - - PreserveNewest - Designer - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - Designer - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - Designer - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - Designer - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - Designer - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - Designer - - - PreserveNewest - - - PreserveNewest - Designer - - - PreserveNewest - Designer - - - PreserveNewest - - - PreserveNewest - Designer - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - Designer - - - PreserveNewest - Designer - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - Designer - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - Designer - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - Always - - - PreserveNewest - Designer - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - Designer - - - PreserveNewest - - - PreserveNewest - Designer - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - Designer - - - PreserveNewest - Designer - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - Designer - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - - - - - False - Microsoft .NET Framework 4 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - false - - - False - Windows Installer 4.5 - true - - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - - - - - - - - - - {0aad36e3-51a5-4a07-ab60-5c8a66bd38b7} - Farseer Physics MonoGame - - - {3b8f9edb-6e5e-450c-abc2-ec49075d0b50} - Hyper.ComponentModel - - - {49ba1c69-6104-41ac-a5d8-b54fa9f696e8} - Lidgren.Network - - - + + prompt + 4 + false + + + Icon.ico + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + False + C:\Program Files (x86)\MonoGame\v3.0\Assemblies\Windows\MonoGame.Framework.dll + + + False + .\NVorbis.dll + + + False + C:\Program Files (x86)\MonoGame\v3.0\Assemblies\DesktopGL\OpenTK.dll + + + + ..\packages\RestSharp.105.1.0\lib\net4\RestSharp.dll + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + Designer + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + Designer + PreserveNewest + + + PreserveNewest + + + Designer + PreserveNewest + + + PreserveNewest + + + Designer + PreserveNewest + + + Designer + PreserveNewest + + + Designer + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + Designer + PreserveNewest + + + Designer + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + Designer + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + Designer + PreserveNewest + + + PreserveNewest + + + PreserveNewest + Designer + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + Designer + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + Designer + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + Designer + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + Designer + + + PreserveNewest + Designer + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + Designer + + + PreserveNewest + + + Designer + PreserveNewest + + + PreserveNewest + + + Designer + PreserveNewest + + + PreserveNewest + + + Designer + PreserveNewest + + + PreserveNewest + Designer + + + PreserveNewest + + + PreserveNewest + Designer + + + PreserveNewest + + + PreserveNewest + Designer + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + Designer + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + Designer + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + Designer + + + PreserveNewest + + + PreserveNewest + Designer + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + Designer + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + Designer + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + Designer + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + Designer + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + Designer + + + PreserveNewest + + + PreserveNewest + Designer + + + PreserveNewest + Designer + + + PreserveNewest + + + PreserveNewest + Designer + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + Designer + + + PreserveNewest + Designer + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + Designer + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + Designer + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + Always + + + PreserveNewest + Designer + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + Designer + + + PreserveNewest + + + PreserveNewest + Designer + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + Designer + + + PreserveNewest + Designer + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + Designer + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + + + + False + Microsoft .NET Framework 4 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + false + + + False + Windows Installer 4.5 + true + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + + + + + + + + + {0aad36e3-51a5-4a07-ab60-5c8a66bd38b7} + Farseer Physics MonoGame + + + {3b8f9edb-6e5e-450c-abc2-ec49075d0b50} + Hyper.ComponentModel + + + {49ba1c69-6104-41ac-a5d8-b54fa9f696e8} + Lidgren.Network + + +