Esempio n. 1
0
        private static MiniYaml FlipFacings(MiniYaml info)
        {
            var d = info.ToDictionary();

            if (!LoadField(d, "FlipFacings", false))
            {
                return(info);
            }

            var source = info.Value;

            info.Value = null;

            var frames = LoadField <int[]>(d, "Frames", null);

            info.Nodes.Remove(info.Nodes.First(node => node.Key == "Frames"));

            var combine = "Combine:\n";

            for (var i = 0; i < frames.Length; i++)
            {
                combine += "\t" + source + ":\n\t\tStart:" + frames[i] + "\n\t\tAddExtension:false\n";
            }

            for (var i = frames.Length - 2; i > 0; i--)
            {
                combine += "\t" + source + ":\n\t\tStart:" + frames[i] + "\n\t\tAddExtension:false\n\t\tFlipX:true\n";
            }

            info.Nodes.Add(MiniYaml.FromString(combine)[0]);

            return(info);
        }
Esempio n. 2
0
        public void TestEscapedHashInValues()
        {
            var trailingWhitespace = MiniYaml.FromString(@"key: value # comment", "trailingWhitespace", discardCommentsAndWhitespace: false)[0];

            Assert.AreEqual("value", trailingWhitespace.Value.Value);
            Assert.AreEqual(" comment", trailingWhitespace.Comment);

            var noWhitespace = MiniYaml.FromString(@"key:value# comment", "noWhitespace", discardCommentsAndWhitespace: false)[0];

            Assert.AreEqual("value", noWhitespace.Value.Value);
            Assert.AreEqual(" comment", noWhitespace.Comment);

            var escapedHashInValue = MiniYaml.FromString(@"key: before \# after # comment", "escapedHashInValue", discardCommentsAndWhitespace: false)[0];

            Assert.AreEqual("before # after", escapedHashInValue.Value.Value);
            Assert.AreEqual(" comment", escapedHashInValue.Comment);

            var emptyValueAndComment = MiniYaml.FromString(@"key:#", "emptyValueAndComment", discardCommentsAndWhitespace: false)[0];

            Assert.AreEqual(null, emptyValueAndComment.Value.Value);
            Assert.AreEqual("", emptyValueAndComment.Comment);

            var noValue = MiniYaml.FromString(@"key:", "noValue", discardCommentsAndWhitespace: false)[0];

            Assert.AreEqual(null, noValue.Value.Value);
            Assert.AreEqual(null, noValue.Comment);

            var emptyKey = MiniYaml.FromString(@" : value", "emptyKey", discardCommentsAndWhitespace: false)[0];

            Assert.AreEqual(null, emptyKey.Key);
            Assert.AreEqual("value", emptyKey.Value.Value);
            Assert.AreEqual(null, emptyKey.Comment);
        }
Esempio n. 3
0
        public void TestSelfMerging()
        {
            var baseYaml = @"
Test:
	Merge: original
		Child: original
	Original:
Test:
	Merge: override
		Child: override
	Override:
";

            var result = MiniYaml.Merge(new[] { baseYaml }.Select(s => MiniYaml.FromString(s, "")));

            Assert.That(result.Count(n => n.Key == "Test"), Is.EqualTo(1), "Result should have exactly one Test node.");

            var testNodes = result.First(n => n.Key == "Test").Value.Nodes;

            Assert.That(testNodes.Select(n => n.Key), Is.EqualTo(new[] { "Merge", "Original", "Override" }), "Merged Test node has incorrect child nodes.");

            var mergeNode = testNodes.First(n => n.Key == "Merge").Value;

            Assert.That(mergeNode.Value, Is.EqualTo("override"), "Merge node has incorrect value.");
            Assert.That(mergeNode.Nodes[0].Value.Value, Is.EqualTo("override"), "Merge node Child value should be 'override', but is not");
        }
Esempio n. 4
0
        public void ChildCanBeOverriddenThenRemoved()
        {
            var baseYaml     = @"
^BaseA:
    MockString:
        AString: Base
^BaseB:
    Inherits: ^BaseA
    MockString:
        AString: Override
";
            var overrideYaml = @"
Test:
    Inherits: ^BaseB
    MockString:
        -AString:
";

            var result = MiniYaml.Merge(new[] { baseYaml, overrideYaml }.Select(s => MiniYaml.FromString(s, "")))
                         .First(n => n.Key == "Test").Value.Nodes;

            Assert.IsTrue(result.Any(n => n.Key == "MockString"), "Node should have the MockString child, but does not.");
            Assert.IsFalse(result.First(n => n.Key == "MockString").Value.Nodes.Any(n => n.Key == "AString"),
                           "MockString value should have been removed, but was not.");
        }
Esempio n. 5
0
        void RefreshServerList()
        {
            // Query in progress
            if (currentQuery != null)
            {
                return;
            }

            searchStatus = SearchStatus.Fetching;

            Action <DownloadDataCompletedEventArgs, bool> onComplete = (i, cancelled) =>
            {
                currentQuery = null;

                if (i.Error != null || cancelled)
                {
                    RefreshServerListInner(null);
                    return;
                }

                var data = Encoding.UTF8.GetString(i.Result);
                var yaml = MiniYaml.FromString(data);

                var games = yaml.Select(a => new GameServer(a.Value))
                            .Where(gs => gs.Address != null);

                Game.RunAfterTick(() => RefreshServerListInner(games));
            };

            currentQuery = new Download(Game.Settings.Server.MasterServer + "games", _ => { }, onComplete);
        }
Esempio n. 6
0
        public static HandshakeRequest Deserialize(string data)
        {
            var handshake = new HandshakeRequest();

            FieldLoader.Load(handshake, MiniYaml.FromString(data).First().Value);
            return(handshake);
        }
Esempio n. 7
0
        public static Session Deserialize(string data)
        {
            var session = new Session(Game.Settings.Game.Mods);

            var ys = MiniYaml.FromString(data);

            foreach (var y in ys)
            {
                var yy = y.Key.Split('@');

                switch (yy[0])
                {
                case "GlobalSettings":
                    FieldLoader.Load(session.GlobalSettings, y.Value);
                    break;

                case "Client":
                    session.Clients.Add(FieldLoader.Load <Session.Client>(y.Value));
                    break;

                case "Slot":
                    var s = FieldLoader.Load <Session.Slot>(y.Value);
                    session.Slots.Add(s.PlayerReference, s);
                    break;
                }
            }

            return(session);
        }
Esempio n. 8
0
        public static HandshakeResponse Deserialize(string data)
        {
            var handshake = new HandshakeResponse
            {
                Client = new Session.Client()
            };

            var ys = MiniYaml.FromString(data);

            foreach (var y in ys)
            {
                switch (y.Key)
                {
                case "Handshake":
                    FieldLoader.Load(handshake, y.Value);
                    break;

                case "Client":
                    FieldLoader.Load(handshake.Client, y.Value);
                    break;
                }
            }

            return(handshake);
        }
Esempio n. 9
0
 public void SetUp()
 {
     parentList = MiniYaml.FromString(yamlForParent);
     childList  = MiniYaml.FromString(yamlForChild);
     parent     = parentList.First().Value;
     child      = childList.First().Value;
 }
Esempio n. 10
0
        public void TestGuardedWhitespace()
        {
            var testYaml = @"key:   \      test value    \   ";
            var nodes    = MiniYaml.FromString(testYaml, "testYaml");

            Assert.AreEqual("      test value    ", nodes[0].Value.Value);
        }
Esempio n. 11
0
        public GameSave(string filepath)
        {
            using (var rs = File.OpenRead(filepath))
            {
                rs.Seek(-12, SeekOrigin.End);
                var metadataOffset  = rs.ReadInt32();
                var traitDataOffset = rs.ReadInt32();
                if (rs.ReadInt32() != EOFMarker)
                {
                    throw new InvalidDataException("Invalid orasav file");
                }

                rs.Seek(metadataOffset, SeekOrigin.Begin);
                if (rs.ReadInt32() != MetadataMarker)
                {
                    throw new InvalidDataException("Invalid orasav file");
                }

                LastOrdersFrame = rs.ReadInt32();
                LastSyncFrame   = rs.ReadInt32();
                lastSyncPacket  = rs.ReadBytes(Order.SyncHashOrderLength);

                var globalSettings = MiniYaml.FromString(rs.ReadString(Encoding.UTF8, Connection.MaxOrderLength));
                GlobalSettings = Session.Global.Deserialize(globalSettings[0].Value);

                var slots = MiniYaml.FromString(rs.ReadString(Encoding.UTF8, Connection.MaxOrderLength));
                Slots = new Dictionary <string, Session.Slot>();
                foreach (var s in slots)
                {
                    var slot = Session.Slot.Deserialize(s.Value);
                    Slots.Add(slot.PlayerReference, slot);
                }

                var slotClients = MiniYaml.FromString(rs.ReadString(Encoding.UTF8, Connection.MaxOrderLength));
                SlotClients = new Dictionary <string, SlotClient>();
                foreach (var s in slotClients)
                {
                    var slotClient = SlotClient.Deserialize(s.Value);
                    SlotClients.Add(slotClient.Slot, slotClient);
                }

                if (rs.Position != traitDataOffset || rs.ReadInt32() != TraitDataMarker)
                {
                    throw new InvalidDataException("Invalid orasav file");
                }

                var traitData = MiniYaml.FromString(rs.ReadString(Encoding.UTF8, Connection.MaxOrderLength));
                foreach (var td in traitData)
                {
                    TraitData.Add(int.Parse(td.Key), td.Value);
                }

                rs.Seek(0, SeekOrigin.Begin);
                ordersStream.Write(rs.ReadBytes(metadataOffset), 0, metadataOffset);
            }
        }
Esempio n. 12
0
        public void TestIndents()
        {
            var tabs = MiniYaml.FromString(yamlTabStyle, "yamlTabStyle").WriteToString();

            Console.WriteLine(tabs);
            var mixed = MiniYaml.FromString(yamlMixedStyle, "yamlMixedStyle").WriteToString();

            Console.WriteLine(mixed);
            Assert.That(tabs, Is.EqualTo(mixed));
        }
Esempio n. 13
0
        public void MergeYamlA()
        {
            var a = MiniYaml.FromString(mixedMergeA, "mixedMergeA");
            var b = MiniYaml.FromString(mixedMergeB, "mixedMergeB");

            // Merge order should not matter
            // Note: All the Merge* variants are different plumbing over the same
            // internal logic.  Testing only MergeStrict is sufficent.
            TestMixedMerge(MiniYaml.MergeStrict(a, b).First().Value);
            TestMixedMerge(MiniYaml.MergeStrict(b, a).First().Value);
        }
Esempio n. 14
0
        static IEnumerable <NewsItem> ReadNews(byte[] bytes)
        {
            var str = Encoding.UTF8.GetString(bytes);

            return(MiniYaml.FromString(str).Select(node => new NewsItem
            {
                Title = node.Value.NodesDict["Title"].Value,
                Author = node.Value.NodesDict["Author"].Value,
                DateTime = FieldLoader.GetValue <DateTime>("DateTime", node.Key),
                Content = node.Value.NodesDict["Content"].Value
            }));
        }
Esempio n. 15
0
        // This needs to match the logic used in RulesetCache.LoadYamlRules
        ActorInfo CreateActorInfoFromYaml(string name, string mapYaml, params string[] yamls)
        {
            var initialNodes = mapYaml == null ? new List <MiniYamlNode>() : MiniYaml.FromString(mapYaml);
            var yaml         = yamls
                               .Select(s => MiniYaml.FromString(s))
                               .Aggregate(initialNodes, MiniYaml.MergePartial);
            var allUnits = yaml.ToDictionary(node => node.Key, node => node.Value);
            var unit     = allUnits[name];
            var creator  = new ObjectCreator(new[] { typeof(ActorInfoTest).Assembly });

            return(new ActorInfo(creator, name, unit, allUnits));
        }
Esempio n. 16
0
        public void CommentsSurviveRoundTrip()
        {
            var yaml = @"
# Top level comment node
Parent: # comment without value
	# Indented comment node
	First: value containing a \# character
	Second: value # node with inline comment
".Replace("\r\n", "\n");

            var result = MiniYaml.FromString(yaml, discardCommentsAndWhitespace: false).WriteToString();

            Assert.AreEqual(yaml, result);
        }
Esempio n. 17
0
        public void EmptyLinesShouldCountTowardLineNumbers()
        {
            var yaml = @"
TestA:
	Nothing:

TestB:
	Nothing:
";

            var result = MiniYaml.FromString(yaml).First(n => n.Key == "TestB");

            Assert.AreEqual(5, result.Location.Line);
        }
Esempio n. 18
0
        public static Session Deserialize(string data)
        {
            try
            {
                var session = new Session();

                var nodes = MiniYaml.FromString(data);
                foreach (var node in nodes)
                {
                    var strings = node.Key.Split('@');

                    switch (strings[0])
                    {
                    case "Client":
                        session.Clients.Add(Client.Deserialize(node.Value));
                        break;

                    case "ClientPing":
                        session.ClientPings.Add(ClientPing.Deserialize(node.Value));
                        break;

                    case "GlobalSettings":
                        session.GlobalSettings = Global.Deserialize(node.Value);
                        break;

                    case "Slot":
                        var s = Slot.Deserialize(node.Value);
                        session.Slots.Add(s.PlayerReference, s);
                        break;

                    case "DisabledSpawnPoints":
                        session.DisabledSpawnPoints = FieldLoader.GetValue <HashSet <int> >("DisabledSpawnPoints", node.Value.Value);
                        break;
                    }
                }

                return(session);
            }
            catch (YamlException)
            {
                throw new YamlException("Session deserialized invalid MiniYaml:\n{0}".F(data));
            }
            catch (InvalidOperationException)
            {
                throw new YamlException("Session deserialized invalid MiniYaml:\n{0}".F(data));
            }
        }
Esempio n. 19
0
        public void TestEscapedHashInValues()
        {
            var trailingWhitespace = @"key: value # comment";

            Assert.AreEqual("value", MiniYaml.FromString(trailingWhitespace, "trailingWhitespace")[0].Value.Value);

            var noWhitespace = @"key:value# comment";

            Assert.AreEqual("value", MiniYaml.FromString(noWhitespace, "noWhitespace")[0].Value.Value);

            var escapedHashInValue = @"key: before \# after # comment";

            Assert.AreEqual("before # after", MiniYaml.FromString(escapedHashInValue, "escapedHashInValue")[0].Value.Value);

            var emptyValue = @"key:# comment";

            Assert.AreEqual(null, MiniYaml.FromString(emptyValue, "emptyValue")[0].Value.Value);
        }
Esempio n. 20
0
        public void CommentsShouldntSurviveRoundTrip()
        {
            var yaml = @"
# Top level comment node
Parent: # comment without value
	# Indented comment node
	First: value containing a \# character
	Second: value # node with inline comment
";

            var strippedYaml = @"Parent:
	First: value containing a \# character
	Second: value"    .Replace("\r\n", "\n");

            var result = MiniYaml.FromString(yaml).WriteToString();

            Assert.AreEqual(strippedYaml, result);
        }
Esempio n. 21
0
        public void ChildCanBeRemovedAfterMultipleInheritance()
        {
            var baseYaml     = @"
^BaseA:
	MockA2:
Test:
	Inherits: ^BaseA
	MockA2:
";
            var overrideYaml = @"
Test:
	-MockA2
";

            var result = MiniYaml.Merge(new[] { baseYaml, overrideYaml }.Select(s => MiniYaml.FromString(s, "")))
                         .First(n => n.Key == "Test").Value.Nodes;

            Assert.IsFalse(result.Any(n => n.Key == "MockA2"), "Node should not have the MockA2 child, but does.");
        }
Esempio n. 22
0
        void RefreshServerList()
        {
            // Query in progress
            if (currentQuery != null)
            {
                return;
            }

            searchStatus = SearchStatus.Fetching;

            Action <DownloadDataCompletedEventArgs> onComplete = i =>
            {
                currentQuery = null;

                List <GameServer> games = null;
                if (i.Error == null)
                {
                    try
                    {
                        var data = Encoding.UTF8.GetString(i.Result);
                        var yaml = MiniYaml.FromString(data);

                        games = yaml.Select(a => new GameServer(a.Value))
                                .Where(gs => gs.Address != null)
                                .ToList();
                    }
                    catch
                    {
                        searchStatus = SearchStatus.Failed;
                    }
                }

                Game.RunAfterTick(() => RefreshServerListInner(games));
            };

            var queryURL = Game.Settings.Server.MasterServer + "games?version={0}&mod={1}&modversion={2}".F(
                Uri.EscapeUriString(Game.Mods["modchooser"].Metadata.Version),
                Uri.EscapeUriString(Game.ModData.Manifest.Id),
                Uri.EscapeUriString(Game.ModData.Manifest.Metadata.Version));

            currentQuery = new Download(queryURL, _ => { }, onComplete);
        }
Esempio n. 23
0
        public static Session Deserialize(string data)
        {
            try
            {
                var session = new Session();

                var nodes = MiniYaml.FromString(data);
                foreach (var node in nodes)
                {
                    var strings = node.Key.Split('@');

                    switch (strings[0])
                    {
                    case "Client":
                        session.Clients.Add(Client.Deserialize(node.Value));
                        break;

                    case "ClientPing":
                        session.ClientPings.Add(ClientPing.Deserialize(node.Value));
                        break;

                    case "GlobalSettings":
                        session.GlobalSettings = Global.Deserialize(node.Value);
                        break;

                    case "Slot":
                        var s = Slot.Deserialize(node.Value);
                        session.Slots.Add(s.PlayerReference, s);
                        break;
                    }
                }

                return(session);
            }
            catch (InvalidOperationException)
            {
                Log.Write("exception", "Session deserialized invalid MiniYaml:\n{0}".F(data));
                throw;
            }
        }
Esempio n. 24
0
        public void CommentsShouldCountTowardLineNumbers()
        {
            var yaml              = @"
TestA:
	Nothing:

# Comment
TestB:
	Nothing:
";
            var resultDiscard     = MiniYaml.FromString(yaml);
            var resultDiscardLine = resultDiscard.First(n => n.Key == "TestB").Location.Line;

            Assert.That(resultDiscardLine, Is.EqualTo(6), "Node TestB should report its location as line 6, but is not (discarding comments)");
            Assert.That(resultDiscard[1].Key, Is.EqualTo("TestB"), "Node TestB should be the second child of the root node, but is not (discarding comments)");

            var resultKeep     = MiniYaml.FromString(yaml, discardCommentsAndWhitespace: false);
            var resultKeepLine = resultKeep.First(n => n.Key == "TestB").Location.Line;

            Assert.That(resultKeepLine, Is.EqualTo(6), "Node TestB should report its location as line 6, but is not (parsing comments)");
            Assert.That(resultKeep[4].Key, Is.EqualTo("TestB"), "Node TestB should be the fifth child of the root node, but is not (parsing comments)");
        }
Esempio n. 25
0
        public void ChildCanBeRemovedAndLaterOverridden()
        {
            var baseYaml     = @"
^BaseA:
    MockString:
        AString: Base
Test:
    Inherits: ^BaseA
    -MockString:
";
            var overrideYaml = @"
Test:
    MockString:
        AString: Override
";

            var result = MiniYaml.Merge(new[] { baseYaml, overrideYaml }.Select(s => MiniYaml.FromString(s, "")))
                         .First(n => n.Key == "Test").Value.Nodes;

            Assert.IsTrue(result.Any(n => n.Key == "MockString"), "Node should have the MockString child, but does not.");
            Assert.IsTrue(result.First(n => n.Key == "MockString").Value.ToDictionary()["AString"].Value == "Override",
                          "MockString value has not been set with the correct override value for AString.");
        }
Esempio n. 26
0
        public static void Query(Action <GameServer[]> onComplete)
        {
            var masterServerUrl = Game.Settings.Server.MasterServer;

            new Thread(() =>
            {
                GameServer[] games = null;
                try
                {
                    var str = GetData(new Uri(masterServerUrl + "list.php"));

                    var yaml = MiniYaml.FromString(str);

                    games = yaml.Select(a => FieldLoader.Load <GameServer>(a.Value))
                            .Where(gs => gs.Address != null).ToArray();
                }
                catch { }

                Game.RunAfterTick(() => onComplete(games));
            })
            {
                IsBackground = true
            }.Start();
        }
Esempio n. 27
0
        public static Session Deserialize(string data)
        {
            try
            {
                var session = new Session(Game.Settings.Game.Mods);

                var ys = MiniYaml.FromString(data);
                foreach (var y in ys)
                {
                    var yy = y.Key.Split('@');

                    switch (yy[0])
                    {
                    case "GlobalSettings":
                        FieldLoader.Load(session.GlobalSettings, y.Value);
                        break;

                    case "Client":
                        session.Clients.Add(FieldLoader.Load <Session.Client>(y.Value));
                        break;

                    case "Slot":
                        var s = FieldLoader.Load <Session.Slot>(y.Value);
                        session.Slots.Add(s.PlayerReference, s);
                        break;
                    }
                }

                return(session);
            }
            catch (InvalidOperationException)
            {
                Log.Write("exception", "Session deserialized invalid MiniYaml:\n{0}".F(data));
                throw;
            }
        }
Esempio n. 28
0
        public RegisteredProfileTooltipLogic(Widget widget, WorldRenderer worldRenderer, ModData modData, Session.Client client)
        {
            playerDatabase = modData.Manifest.Get <PlayerDatabase>();

            var header         = widget.Get("HEADER");
            var badgeContainer = widget.Get("BADGES_CONTAINER");
            var badgeSeparator = badgeContainer.GetOrNull("SEPARATOR");

            var profileHeader = header.Get("PROFILE_HEADER");
            var messageHeader = header.Get("MESSAGE_HEADER");
            var message       = messageHeader.Get <LabelWidget>("MESSAGE");
            var messageFont   = Game.Renderer.Fonts[message.Font];

            profileHeader.IsVisible = () => profileLoaded;
            messageHeader.IsVisible = () => !profileLoaded;

            var profileWidth    = 0;
            var maxProfileWidth = widget.Bounds.Width;
            var messageText     = "Loading player profile...";
            var messageWidth    = messageFont.Measure(messageText).X + 2 * message.Bounds.Left;

            Task.Run(async() =>
            {
                try
                {
                    var httpClient = HttpClientFactory.Create();

                    var httpResponseMessage = await httpClient.GetAsync(playerDatabase.Profile + client.Fingerprint);
                    var result = await httpResponseMessage.Content.ReadAsStringAsync();

                    var yaml = MiniYaml.FromString(result).First();
                    if (yaml.Key == "Player")
                    {
                        profile = FieldLoader.Load <PlayerProfile>(yaml.Value);
                        Game.RunAfterTick(() =>
                        {
                            var nameLabel = profileHeader.Get <LabelWidget>("PROFILE_NAME");
                            var nameFont  = Game.Renderer.Fonts[nameLabel.Font];
                            var rankLabel = profileHeader.Get <LabelWidget>("PROFILE_RANK");
                            var rankFont  = Game.Renderer.Fonts[rankLabel.Font];

                            var adminContainer = profileHeader.Get("GAME_ADMIN");
                            var adminLabel     = adminContainer.Get <LabelWidget>("LABEL");
                            var adminFont      = Game.Renderer.Fonts[adminLabel.Font];

                            var headerSizeOffset = profileHeader.Bounds.Height - messageHeader.Bounds.Height;

                            nameLabel.GetText = () => profile.ProfileName;
                            rankLabel.GetText = () => profile.ProfileRank;

                            profileWidth = Math.Max(profileWidth, nameFont.Measure(profile.ProfileName).X + 2 * nameLabel.Bounds.Left);
                            profileWidth = Math.Max(profileWidth, rankFont.Measure(profile.ProfileRank).X + 2 * rankLabel.Bounds.Left);

                            header.Bounds.Height    += headerSizeOffset;
                            badgeContainer.Bounds.Y += header.Bounds.Height;
                            if (client.IsAdmin)
                            {
                                profileWidth = Math.Max(profileWidth, adminFont.Measure(adminLabel.Text).X + 2 * adminLabel.Bounds.Left);

                                adminContainer.IsVisible     = () => true;
                                profileHeader.Bounds.Height += adminLabel.Bounds.Height;
                                header.Bounds.Height        += adminLabel.Bounds.Height;
                                badgeContainer.Bounds.Y     += adminLabel.Bounds.Height;
                            }

                            Func <int, int> negotiateWidth = badgeWidth =>
                            {
                                profileWidth = Math.Min(Math.Max(badgeWidth, profileWidth), maxProfileWidth);
                                return(profileWidth);
                            };

                            if (profile.Badges.Any())
                            {
                                var badges = Ui.LoadWidget("PLAYER_PROFILE_BADGES_INSERT", badgeContainer, new WidgetArgs()
                                {
                                    { "worldRenderer", worldRenderer },
                                    { "profile", profile },
                                    { "negotiateWidth", negotiateWidth }
                                });

                                if (badges.Bounds.Height > 0)
                                {
                                    badgeContainer.Bounds.Height = badges.Bounds.Height;
                                    badgeContainer.IsVisible     = () => true;
                                }
                            }

                            profileWidth         = Math.Min(profileWidth, maxProfileWidth);
                            header.Bounds.Width  = widget.Bounds.Width = badgeContainer.Bounds.Width = profileWidth;
                            widget.Bounds.Height = header.Bounds.Height + badgeContainer.Bounds.Height;

                            if (badgeSeparator != null)
                            {
                                badgeSeparator.Bounds.Width = profileWidth - 2 * badgeSeparator.Bounds.X;
                            }

                            profileLoaded = true;
                        });
                    }
                }
                catch (Exception e)
                {
                    Log.Write("debug", "Failed to parse player data result with exception: {0}", e);
                }
                finally
                {
                    if (profile == null)
                    {
                        messageText         = "Failed to load player profile.";
                        messageWidth        = messageFont.Measure(messageText).X + 2 * message.Bounds.Left;
                        header.Bounds.Width = widget.Bounds.Width = messageWidth;
                    }
                }
            });

            message.GetText        = () => messageText;
            header.Bounds.Height  += messageHeader.Bounds.Height;
            header.Bounds.Width    = widget.Bounds.Width = messageWidth;
            widget.Bounds.Height   = header.Bounds.Height;
            badgeContainer.Visible = false;
        }
Esempio n. 29
0
        void InterpretServerOrder(Connection conn, Order o)
        {
            lock (LobbyInfo)
            {
                // Only accept handshake responses from unvalidated clients
                // Anything else may be an attempt to exploit the server
                if (!conn.Validated)
                {
                    if (o.OrderString == "HandshakeResponse")
                    {
                        ValidateClient(conn, o.TargetString);
                    }
                    else
                    {
                        Log.Write("server", "Rejected connection from {0}; Order `{1}` is not a `HandshakeResponse`.",
                                  conn.Socket.RemoteEndPoint, o.OrderString);

                        DropClient(conn);
                    }

                    return;
                }

                switch (o.OrderString)
                {
                case "Command":
                {
                    var handledBy = serverTraits.WithInterface <IInterpretCommand>()
                                    .FirstOrDefault(t => t.InterpretCommand(this, conn, GetClient(conn), o.TargetString));

                    if (handledBy == null)
                    {
                        Log.Write("server", "Unknown server command: {0}", o.TargetString);
                        SendOrderTo(conn, "Message", "Unknown server command: {0}".F(o.TargetString));
                    }

                    break;
                }

                case "Chat":
                    DispatchOrdersToClients(conn, 0, o.Serialize());
                    break;

                case "Pong":
                {
                    if (!OpenRA.Exts.TryParseInt64Invariant(o.TargetString, out var pingSent))
                    {
                        Log.Write("server", "Invalid order pong payload: {0}", o.TargetString);
                        break;
                    }

                    var client = GetClient(conn);
                    if (client == null)
                    {
                        return;
                    }

                    var pingFromClient = LobbyInfo.PingFromClient(client);
                    if (pingFromClient == null)
                    {
                        return;
                    }

                    var history = pingFromClient.LatencyHistory.ToList();
                    history.Add(Game.RunTime - pingSent);

                    // Cap ping history at 5 values (25 seconds)
                    if (history.Count > 5)
                    {
                        history.RemoveRange(0, history.Count - 5);
                    }

                    pingFromClient.Latency        = history.Sum() / history.Count;
                    pingFromClient.LatencyJitter  = (history.Max() - history.Min()) / 2;
                    pingFromClient.LatencyHistory = history.ToArray();

                    SyncClientPing();

                    break;
                }

                case "GameSaveTraitData":
                {
                    if (GameSave != null)
                    {
                        var data = MiniYaml.FromString(o.TargetString)[0];
                        GameSave.AddTraitData(int.Parse(data.Key), data.Value);
                    }

                    break;
                }

                case "CreateGameSave":
                {
                    if (GameSave != null)
                    {
                        // Sanitize potentially malicious input
                        var filename     = o.TargetString;
                        var invalidIndex = -1;
                        var invalidChars = Path.GetInvalidFileNameChars();
                        while ((invalidIndex = filename.IndexOfAny(invalidChars)) != -1)
                        {
                            filename = filename.Remove(invalidIndex, 1);
                        }

                        var baseSavePath = Platform.ResolvePath(
                            Platform.SupportDirPrefix,
                            "Saves",
                            ModData.Manifest.Id,
                            ModData.Manifest.Metadata.Version);

                        if (!Directory.Exists(baseSavePath))
                        {
                            Directory.CreateDirectory(baseSavePath);
                        }

                        GameSave.Save(Path.Combine(baseSavePath, filename));
                        DispatchOrdersToClients(null, 0, Order.FromTargetString("GameSaved", filename, true).Serialize());
                    }

                    break;
                }

                case "LoadGameSave":
                {
                    if (Type == ServerType.Dedicated || State >= ServerState.GameStarted)
                    {
                        break;
                    }

                    // Sanitize potentially malicious input
                    var filename     = o.TargetString;
                    var invalidIndex = -1;
                    var invalidChars = Path.GetInvalidFileNameChars();
                    while ((invalidIndex = filename.IndexOfAny(invalidChars)) != -1)
                    {
                        filename = filename.Remove(invalidIndex, 1);
                    }

                    var savePath = Platform.ResolvePath(
                        Platform.SupportDirPrefix,
                        "Saves",
                        ModData.Manifest.Id,
                        ModData.Manifest.Metadata.Version,
                        filename);

                    GameSave = new GameSave(savePath);
                    LobbyInfo.GlobalSettings = GameSave.GlobalSettings;
                    LobbyInfo.Slots          = GameSave.Slots;

                    // Reassign clients to slots
                    //  - Bot ordering is preserved
                    //  - Humans are assigned on a first-come-first-serve basis
                    //  - Leftover humans become spectators

                    // Start by removing all bots and assigning all players as spectators
                    foreach (var c in LobbyInfo.Clients)
                    {
                        if (c.Bot != null)
                        {
                            LobbyInfo.Clients.Remove(c);
                            var ping = LobbyInfo.PingFromClient(c);
                            if (ping != null)
                            {
                                LobbyInfo.ClientPings.Remove(ping);
                            }
                        }
                        else
                        {
                            c.Slot = null;
                        }
                    }

                    // Rebuild/remap the saved client state
                    // TODO: Multiplayer saves should leave all humans as spectators so they can manually pick slots
                    var adminClientIndex = LobbyInfo.Clients.First(c => c.IsAdmin).Index;
                    foreach (var kv in GameSave.SlotClients)
                    {
                        if (kv.Value.Bot != null)
                        {
                            var bot = new Session.Client()
                            {
                                Index = ChooseFreePlayerIndex(),
                                State = Session.ClientState.NotReady,
                                BotControllerClientIndex = adminClientIndex
                            };

                            kv.Value.ApplyTo(bot);
                            LobbyInfo.Clients.Add(bot);
                        }
                        else
                        {
                            // This will throw if the server doesn't have enough human clients to fill all player slots
                            // See TODO above - this isn't a problem in practice because MP saves won't use this
                            var client = LobbyInfo.Clients.First(c => c.Slot == null);
                            kv.Value.ApplyTo(client);
                        }
                    }

                    SyncLobbyInfo();
                    SyncLobbyClients();
                    SyncClientPing();

                    break;
                }
                }
            }
        }
Esempio n. 30
0
        void ValidateClient(Connection newConn, string data)
        {
            try
            {
                if (State == ServerState.GameStarted)
                {
                    Log.Write("server", "Rejected connection from {0}; game is already started.",
                              newConn.Socket.RemoteEndPoint);

                    SendOrderTo(newConn, "ServerError", "The game has already started");
                    DropClient(newConn);
                    return;
                }

                var handshake = HandshakeResponse.Deserialize(data);

                if (!string.IsNullOrEmpty(Settings.Password) && handshake.Password != Settings.Password)
                {
                    var message = string.IsNullOrEmpty(handshake.Password) ? "Server requires a password" : "Incorrect password";
                    SendOrderTo(newConn, "AuthenticationError", message);
                    DropClient(newConn);
                    return;
                }

                var ipAddress = ((IPEndPoint)newConn.Socket.RemoteEndPoint).Address;
                var client    = new Session.Client
                {
                    Name                = OpenRA.Settings.SanitizedPlayerName(handshake.Client.Name),
                    IPAddress           = ipAddress.ToString(),
                    AnonymizedIPAddress = Type != ServerType.Local && Settings.ShareAnonymizedIPs ? Session.AnonymizeIP(ipAddress) : null,
                    Location            = GeoIP.LookupCountry(ipAddress),
                    Index               = newConn.PlayerIndex,
                    PreferredColor      = handshake.Client.PreferredColor,
                    Color               = handshake.Client.Color,
                    Faction             = "Random",
                    SpawnPoint          = 0,
                    Team                = 0,
                    State               = Session.ClientState.Invalid,
                };

                if (ModData.Manifest.Id != handshake.Mod)
                {
                    Log.Write("server", "Rejected connection from {0}; mods do not match.",
                              newConn.Socket.RemoteEndPoint);

                    SendOrderTo(newConn, "ServerError", "Server is running an incompatible mod");
                    DropClient(newConn);
                    return;
                }

                if (ModData.Manifest.Metadata.Version != handshake.Version)
                {
                    Log.Write("server", "Rejected connection from {0}; Not running the same version.",
                              newConn.Socket.RemoteEndPoint);

                    SendOrderTo(newConn, "ServerError", "Server is running an incompatible version");
                    DropClient(newConn);
                    return;
                }

                if (handshake.OrdersProtocol != ProtocolVersion.Orders)
                {
                    Log.Write("server", "Rejected connection from {0}; incompatible Orders protocol version {1}.",
                              newConn.Socket.RemoteEndPoint, handshake.OrdersProtocol);

                    SendOrderTo(newConn, "ServerError", "Server is running an incompatible protocol");
                    DropClient(newConn);
                    return;
                }

                // Check if IP is banned
                var bans = Settings.Ban.Union(TempBans);
                if (bans.Contains(client.IPAddress))
                {
                    Log.Write("server", "Rejected connection from {0}; Banned.", newConn.Socket.RemoteEndPoint);
                    SendOrderTo(newConn, "ServerError", "You have been {0} from the server".F(Settings.Ban.Contains(client.IPAddress) ? "banned" : "temporarily banned"));
                    DropClient(newConn);
                    return;
                }

                Action completeConnection = () =>
                {
                    lock (LobbyInfo)
                    {
                        client.Slot    = LobbyInfo.FirstEmptySlot();
                        client.IsAdmin = !LobbyInfo.Clients.Any(c1 => c1.IsAdmin);

                        if (client.IsObserver && !LobbyInfo.GlobalSettings.AllowSpectators)
                        {
                            SendOrderTo(newConn, "ServerError", "The game is full");
                            DropClient(newConn);
                            return;
                        }

                        if (client.Slot != null)
                        {
                            SyncClientToPlayerReference(client, Map.Players.Players[client.Slot]);
                        }
                        else
                        {
                            client.Color = Color.White;
                        }

                        // Promote connection to a valid client
                        PreConns.Remove(newConn);
                        Conns.Add(newConn);
                        LobbyInfo.Clients.Add(client);
                        newConn.Validated = true;

                        var clientPing = new Session.ClientPing {
                            Index = client.Index
                        };
                        LobbyInfo.ClientPings.Add(clientPing);

                        Log.Write("server", "Client {0}: Accepted connection from {1}.",
                                  newConn.PlayerIndex, newConn.Socket.RemoteEndPoint);

                        if (client.Fingerprint != null)
                        {
                            Log.Write("server", "Client {0}: Player fingerprint is {1}.",
                                      newConn.PlayerIndex, client.Fingerprint);
                        }

                        foreach (var t in serverTraits.WithInterface <IClientJoined>())
                        {
                            t.ClientJoined(this, newConn);
                        }

                        SyncLobbyInfo();

                        Log.Write("server", "{0} ({1}) has joined the game.",
                                  client.Name, newConn.Socket.RemoteEndPoint);

                        // Report to all other players
                        SendMessage("{0} has joined the game.".F(client.Name), newConn);

                        // Send initial ping
                        SendOrderTo(newConn, "Ping", Game.RunTime.ToString(CultureInfo.InvariantCulture));

                        if (Type == ServerType.Dedicated)
                        {
                            var motdFile = Platform.ResolvePath(Platform.SupportDirPrefix, "motd.txt");
                            if (!File.Exists(motdFile))
                            {
                                File.WriteAllText(motdFile, "Welcome, have fun and good luck!");
                            }

                            var motd = File.ReadAllText(motdFile);
                            if (!string.IsNullOrEmpty(motd))
                            {
                                SendOrderTo(newConn, "Message", motd);
                            }
                        }

                        if (Map.DefinesUnsafeCustomRules)
                        {
                            SendOrderTo(newConn, "Message", "This map contains custom rules. Game experience may change.");
                        }

                        if (!LobbyInfo.GlobalSettings.EnableSingleplayer)
                        {
                            SendOrderTo(newConn, "Message", TwoHumansRequiredText);
                        }
                        else if (Map.Players.Players.Where(p => p.Value.Playable).All(p => !p.Value.AllowBots))
                        {
                            SendOrderTo(newConn, "Message", "Bots have been disabled on this map.");
                        }
                    }
                };

                if (Type == ServerType.Local)
                {
                    // Local servers can only be joined by the local client, so we can trust their identity without validation
                    client.Fingerprint = handshake.Fingerprint;
                    completeConnection();
                }
                else if (!string.IsNullOrEmpty(handshake.Fingerprint) && !string.IsNullOrEmpty(handshake.AuthSignature))
                {
                    waitingForAuthenticationCallback++;

                    Action <DownloadDataCompletedEventArgs> onQueryComplete = i =>
                    {
                        PlayerProfile profile = null;

                        if (i.Error == null)
                        {
                            try
                            {
                                var yaml = MiniYaml.FromString(Encoding.UTF8.GetString(i.Result)).First();
                                if (yaml.Key == "Player")
                                {
                                    profile = FieldLoader.Load <PlayerProfile>(yaml.Value);

                                    var publicKey  = Encoding.ASCII.GetString(Convert.FromBase64String(profile.PublicKey));
                                    var parameters = CryptoUtil.DecodePEMPublicKey(publicKey);
                                    if (!profile.KeyRevoked && CryptoUtil.VerifySignature(parameters, newConn.AuthToken, handshake.AuthSignature))
                                    {
                                        client.Fingerprint = handshake.Fingerprint;
                                        Log.Write("server", "{0} authenticated as {1} (UID {2})", newConn.Socket.RemoteEndPoint,
                                                  profile.ProfileName, profile.ProfileID);
                                    }
                                    else if (profile.KeyRevoked)
                                    {
                                        profile = null;
                                        Log.Write("server", "{0} failed to authenticate as {1} (key revoked)", newConn.Socket.RemoteEndPoint, handshake.Fingerprint);
                                    }
                                    else
                                    {
                                        profile = null;
                                        Log.Write("server", "{0} failed to authenticate as {1} (signature verification failed)",
                                                  newConn.Socket.RemoteEndPoint, handshake.Fingerprint);
                                    }
                                }
                                else
                                {
                                    Log.Write("server", "{0} failed to authenticate as {1} (invalid server response: `{2}` is not `Player`)",
                                              newConn.Socket.RemoteEndPoint, handshake.Fingerprint, yaml.Key);
                                }
                            }
                            catch (Exception ex)
                            {
                                Log.Write("server", "{0} failed to authenticate as {1} (exception occurred)",
                                          newConn.Socket.RemoteEndPoint, handshake.Fingerprint);
                                Log.Write("server", ex.ToString());
                            }
                        }
                        else
                        {
                            Log.Write("server", "{0} failed to authenticate as {1} (server error: `{2}`)",
                                      newConn.Socket.RemoteEndPoint, handshake.Fingerprint, i.Error);
                        }

                        delayedActions.Add(() =>
                        {
                            var notAuthenticated = Type == ServerType.Dedicated && profile == null && (Settings.RequireAuthentication || Settings.ProfileIDWhitelist.Any());
                            var blacklisted      = Type == ServerType.Dedicated && profile != null && Settings.ProfileIDBlacklist.Contains(profile.ProfileID);
                            var notWhitelisted   = Type == ServerType.Dedicated && Settings.ProfileIDWhitelist.Any() &&
                                                   (profile == null || !Settings.ProfileIDWhitelist.Contains(profile.ProfileID));

                            if (notAuthenticated)
                            {
                                Log.Write("server", "Rejected connection from {0}; Not authenticated.", newConn.Socket.RemoteEndPoint);
                                SendOrderTo(newConn, "ServerError", "Server requires players to have an OpenRA forum account");
                                DropClient(newConn);
                            }
                            else if (blacklisted || notWhitelisted)
                            {
                                if (blacklisted)
                                {
                                    Log.Write("server", "Rejected connection from {0}; In server blacklist.", newConn.Socket.RemoteEndPoint);
                                }
                                else
                                {
                                    Log.Write("server", "Rejected connection from {0}; Not in server whitelist.", newConn.Socket.RemoteEndPoint);
                                }

                                SendOrderTo(newConn, "ServerError", "You do not have permission to join this server");
                                DropClient(newConn);
                            }
                            else
                            {
                                completeConnection();
                            }

                            waitingForAuthenticationCallback--;
                        }, 0);
                    };

                    new Download(playerDatabase.Profile + handshake.Fingerprint, _ => { }, onQueryComplete);
                }
                else
                {
                    if (Type == ServerType.Dedicated && (Settings.RequireAuthentication || Settings.ProfileIDWhitelist.Any()))
                    {
                        Log.Write("server", "Rejected connection from {0}; Not authenticated.", newConn.Socket.RemoteEndPoint);
                        SendOrderTo(newConn, "ServerError", "Server requires players to have an OpenRA forum account");
                        DropClient(newConn);
                    }
                    else
                    {
                        completeConnection();
                    }
                }
            }
            catch (Exception ex)
            {
                Log.Write("server", "Dropping connection {0} because an error occurred:", newConn.Socket.RemoteEndPoint);
                Log.Write("server", ex.ToString());
                DropClient(newConn);
            }
        }