Пример #1
0
        public IngameChatLogic(Widget widget, OrderManager orderManager, World world, ModData modData, bool isMenuChat, Dictionary <string, MiniYaml> logicArgs)
        {
            this.orderManager = orderManager;
            modRules          = modData.DefaultRules;
            this.isMenuChat   = isMenuChat;
            this.world        = world;

            var chatTraits      = world.WorldActor.TraitsImplementing <INotifyChat>().ToArray();
            var players         = world.Players.Where(p => p != world.LocalPlayer && !p.NonCombatant && !p.IsBot);
            var isObserver      = orderManager.LocalClient != null && orderManager.LocalClient.IsObserver;
            var alwaysDisabled  = world.IsReplay || world.LobbyInfo.NonBotClients.Count() == 1;
            var disableTeamChat = alwaysDisabled || (world.LocalPlayer != null && !players.Any(p => p.IsAlliedWith(world.LocalPlayer)));
            var teamChat        = !disableTeamChat;

            tabCompletion.Commands = chatTraits.OfType <ChatCommands>().SelectMany(x => x.Commands.Keys).ToList();
            tabCompletion.Names    = orderManager.LobbyInfo.Clients.Select(c => c.Name).Distinct().ToList();

            if (logicArgs.TryGetValue("Templates", out var templateIds))
            {
                foreach (var item in templateIds.Nodes)
                {
                    var key = FieldLoader.GetValue <TextNotificationPool>("key", item.Key);
                    templates[key] = Ui.LoadWidget(item.Value.Value, null, new WidgetArgs());
                }
            }

            var chatPanel = (ContainerWidget)widget;

            chatOverlay = chatPanel.GetOrNull <ContainerWidget>("CHAT_OVERLAY");
            if (chatOverlay != null)
            {
                chatOverlayDisplay  = chatOverlay.Get <TextNotificationsDisplayWidget>("CHAT_DISPLAY");
                chatOverlay.Visible = false;
            }

            chatChrome         = chatPanel.Get <ContainerWidget>("CHAT_CHROME");
            chatChrome.Visible = true;

            var chatMode = chatChrome.Get <ButtonWidget>("CHAT_MODE");

            chatMode.GetText = () => teamChat && !disableTeamChat ? "Team" : "All";
            chatMode.OnClick = () => teamChat ^= true;

            // Enable teamchat if we are a player and die,
            // or disable it when we are the only one left in the team
            if (!alwaysDisabled && world.LocalPlayer != null)
            {
                chatMode.IsDisabled = () =>
                {
                    if (world.IsGameOver || !chatEnabled)
                    {
                        return(true);
                    }

                    // The game is over for us, join spectator team chat
                    if (world.LocalPlayer.WinState != WinState.Undefined)
                    {
                        disableTeamChat = false;
                        return(disableTeamChat);
                    }

                    // If team chat isn't already disabled, check if we are the only living team member
                    if (!disableTeamChat)
                    {
                        disableTeamChat = players.All(p => p.WinState != WinState.Undefined || !p.IsAlliedWith(world.LocalPlayer));
                    }

                    return(disableTeamChat);
                };
            }
            else
            {
                chatMode.IsDisabled = () => disableTeamChat || !chatEnabled;
            }

            // Disable team chat after the game ended
            world.GameOver += () => disableTeamChat = true;

            chatText            = chatChrome.Get <TextFieldWidget>("CHAT_TEXTFIELD");
            chatText.MaxLength  = UnitOrders.ChatMessageMaxLength;
            chatText.OnEnterKey = _ =>
            {
                var team = teamChat && !disableTeamChat;
                if (chatText.Text != "")
                {
                    if (!chatText.Text.StartsWith("/", StringComparison.Ordinal))
                    {
                        // This should never happen, but avoid a crash if it does somehow (chat will just stay open)
                        if (!isObserver && orderManager.LocalClient == null && world.LocalPlayer == null)
                        {
                            return(true);
                        }

                        var teamNumber = 0U;
                        if (team)
                        {
                            teamNumber = (isObserver || world.LocalPlayer.WinState != WinState.Undefined) ? uint.MaxValue : (uint)orderManager.LocalClient.Team;
                        }

                        orderManager.IssueOrder(Order.Chat(chatText.Text.Trim(), teamNumber));
                    }
                    else if (chatTraits != null)
                    {
                        var text = chatText.Text.Trim();
                        var from = world.IsReplay ? null : orderManager.LocalClient.Name;
                        foreach (var trait in chatTraits)
                        {
                            trait.OnChat(from, text);
                        }
                    }
                }

                chatText.Text = "";
                if (!isMenuChat)
                {
                    CloseChat();
                }

                return(true);
            };

            chatText.OnTabKey = e =>
            {
                if (!chatMode.Key.IsActivatedBy(e) || chatMode.IsDisabled())
                {
                    chatText.Text           = tabCompletion.Complete(chatText.Text);
                    chatText.CursorPosition = chatText.Text.Length;
                }
                else
                {
                    chatMode.OnKeyPress(e);
                }

                return(true);
            };

            chatText.OnEscKey = _ =>
            {
                if (!isMenuChat)
                {
                    CloseChat();
                }
                else
                {
                    chatText.YieldKeyboardFocus();
                }

                return(true);
            };

            chatDisabledLabel = new CachedTransform <int, string>(x => x > 0 ? $"Chat available in {x} seconds..." : "Chat Disabled");

            if (!isMenuChat)
            {
                var openTeamChatKey = new HotkeyReference();
                if (logicArgs.TryGetValue("OpenTeamChatKey", out var hotkeyArg))
                {
                    openTeamChatKey = modData.Hotkeys[hotkeyArg.Value];
                }

                var openGeneralChatKey = new HotkeyReference();
                if (logicArgs.TryGetValue("OpenGeneralChatKey", out hotkeyArg))
                {
                    openGeneralChatKey = modData.Hotkeys[hotkeyArg.Value];
                }

                var chatClose = chatChrome.Get <ButtonWidget>("CHAT_CLOSE");
                chatClose.OnClick += CloseChat;

                chatPanel.OnKeyPress = e =>
                {
                    if (e.Event == KeyInputEvent.Up)
                    {
                        return(false);
                    }

                    if (!chatChrome.IsVisible() && (openTeamChatKey.IsActivatedBy(e) || openGeneralChatKey.IsActivatedBy(e)))
                    {
                        teamChat = !disableTeamChat && !openGeneralChatKey.IsActivatedBy(e);

                        OpenChat();
                        return(true);
                    }

                    return(false);
                };
            }

            chatScrollPanel = chatChrome.Get <ScrollPanelWidget>("CHAT_SCROLLPANEL");
            chatScrollPanel.RemoveChildren();
            chatScrollPanel.ScrollToBottom();

            foreach (var notification in orderManager.NotificationsCache)
            {
                if (IsNotificationEligible(notification))
                {
                    AddNotification(notification, true);
                }
            }

            orderManager.AddTextNotification += AddNotificationWrapper;

            chatText.IsDisabled = () => !chatEnabled || (world.IsReplay && !Game.Settings.Debug.EnableDebugCommandsInReplays);

            if (!isMenuChat)
            {
                CloseChat();

                var keyListener = chatChrome.Get <LogicKeyListenerWidget>("KEY_LISTENER");
                keyListener.AddHandler(e =>
                {
                    if (e.Event == KeyInputEvent.Up || !chatText.IsDisabled())
                    {
                        return(false);
                    }

                    if ((e.Key == Keycode.RETURN || e.Key == Keycode.KP_ENTER || e.Key == Keycode.ESCAPE) && e.Modifiers == Modifiers.None)
                    {
                        CloseChat();
                        return(true);
                    }

                    return(false);
                });
            }

            if (logicArgs.TryGetValue("ChatLineSound", out var yaml))
            {
                chatLineSound = yaml.Value;
            }
        }
Пример #2
0
        void CheckInner(ModData modData, string[] namedKeys, Pair <string, string>[] checkWidgetFields, Dictionary <string, List <string> > customLintMethods,
                        List <MiniYamlNode> nodes, string filename, MiniYamlNode parent, Action <string> emitError, Action <string> emitWarning)
        {
            foreach (var node in nodes)
            {
                if (node.Value == null)
                {
                    continue;
                }

                foreach (var x in checkWidgetFields)
                {
                    if (node.Key == x.Second && parent != null && parent.Key.StartsWith(x.First, StringComparison.Ordinal))
                    {
                        // Keys are valid if they refer to a named key or can be parsed as a regular Hotkey.
                        Hotkey unused;
                        if (!namedKeys.Contains(node.Value.Value) && !Hotkey.TryParse(node.Value.Value, out unused))
                        {
                            emitError("{0} refers to a Key named `{1}` that does not exist".F(node.Location, node.Value.Value));
                        }
                    }
                }

                // Check runtime-defined hotkey names
                List <string> checkMethods;
                var           widgetType = node.Key.Split('@')[0];
                if (customLintMethods.TryGetValue(widgetType, out checkMethods))
                {
                    var type     = modData.ObjectCreator.FindType(widgetType + "Widget");
                    var keyNames = checkMethods.SelectMany(m => (IEnumerable <string>)type.GetMethod(m).Invoke(null, new object[] { node, emitError, emitWarning }));

                    Hotkey unused;
                    foreach (var name in keyNames)
                    {
                        if (!namedKeys.Contains(name) && !Hotkey.TryParse(name, out unused))
                        {
                            emitError("{0} refers to a Key named `{1}` that does not exist".F(node.Location, name));
                        }
                    }
                }

                // Logic classes can declare the data key names that specify hotkeys
                if (node.Key == "Logic" && node.Value.Nodes.Any())
                {
                    var typeNames    = FieldLoader.GetValue <string[]>(node.Key, node.Value.Value);
                    var checkArgKeys = new List <string>();
                    foreach (var typeName in typeNames)
                    {
                        var type = Game.ModData.ObjectCreator.FindType(typeName);
                        if (type == null)
                        {
                            continue;
                        }

                        checkArgKeys.AddRange(type.GetCustomAttributes <ChromeLogicArgsHotkeys>(true).SelectMany(x => x.LogicArgKeys));
                    }

                    Hotkey unused;
                    foreach (var n in node.Value.Nodes)
                    {
                        if (checkArgKeys.Contains(n.Key))
                        {
                            if (!namedKeys.Contains(n.Value.Value) && !Hotkey.TryParse(n.Value.Value, out unused))
                            {
                                emitError("{0} {1}:{2} refers to a Key named `{3}` that does not exist".F(filename, node.Value.Value, n.Key, n.Value.Value));
                            }
                        }
                    }
                }

                if (node.Value.Nodes != null)
                {
                    CheckInner(modData, namedKeys, checkWidgetFields, customLintMethods, node.Value.Nodes, filename, node, emitError, emitWarning);
                }
            }
        }
        static void ExtractFromPackage(ExtractionType type, string path, MiniYaml actionYaml, List <string> extractedFiles, Action <string> updateMessage)
        {
            var sourcePath = Path.Combine(path, actionYaml.Value);

            // Try as an absolute path
            if (!File.Exists(sourcePath))
            {
                sourcePath = Platform.ResolvePath(actionYaml.Value);
            }

            using (var source = File.OpenRead(sourcePath))
            {
                foreach (var node in actionYaml.Nodes)
                {
                    var targetPath = Platform.ResolvePath(node.Key);

                    if (File.Exists(targetPath))
                    {
                        Log.Write("install", "Skipping installed file " + targetPath);
                        continue;
                    }

                    var offsetNode = node.Value.Nodes.FirstOrDefault(n => n.Key == "Offset");
                    if (offsetNode == null)
                    {
                        Log.Write("install", "Skipping entry with missing Offset definition " + targetPath);
                        continue;
                    }

                    var lengthNode = node.Value.Nodes.FirstOrDefault(n => n.Key == "Length");
                    if (lengthNode == null)
                    {
                        Log.Write("install", "Skipping entry with missing Length definition " + targetPath);
                        continue;
                    }

                    var length = FieldLoader.GetValue <int>("Length", lengthNode.Value.Value);
                    source.Position = FieldLoader.GetValue <int>("Offset", offsetNode.Value.Value);

                    extractedFiles.Add(targetPath);
                    Directory.CreateDirectory(Path.GetDirectoryName(targetPath));
                    var displayFilename = Path.GetFileName(Path.GetFileName(targetPath));

                    Action <long> onProgress = null;
                    if (length < ShowPercentageThreshold)
                    {
                        updateMessage("Extracting " + displayFilename);
                    }
                    else
                    {
                        onProgress = b => updateMessage("Extracting " + displayFilename + " ({0}%)".F(100 * b / length));
                    }

                    using (var target = File.OpenWrite(targetPath))
                    {
                        Log.Write("install", "Extracting {0} -> {1}".F(sourcePath, targetPath));
                        if (type == ExtractionType.Blast)
                        {
                            Action <long, long> onBlastProgress = (read, _) =>
                            {
                                if (onProgress != null)
                                {
                                    onProgress(read);
                                }
                            };

                            Blast.Decompress(source, target, onBlastProgress);
                        }
                        else
                        {
                            CopyStream(source, target, length, onProgress);
                        }
                    }
                }
            }
        }
Пример #4
0
 public Consideration(MiniYaml yaml)
 {
     FieldLoader.Load(this, yaml);
 }
Пример #5
0
        public Sequence(SpriteLoader loader, string unit, string name, MiniYaml info)
        {
            var srcOverride = info.Value;

            Name = name;
            var d         = info.ToDictionary();
            var offset    = float2.Zero;
            var blendMode = BlendMode.Alpha;

            try
            {
                if (d.ContainsKey("Start"))
                {
                    Start = Exts.ParseIntegerInvariant(d["Start"].Value);
                }

                if (d.ContainsKey("Offset"))
                {
                    offset = FieldLoader.GetValue <float2>("Offset", d["Offset"].Value);
                }

                if (d.ContainsKey("BlendMode"))
                {
                    blendMode = FieldLoader.GetValue <BlendMode>("BlendMode", d["BlendMode"].Value);
                }

                // Apply offset to each sprite in the sequence
                // Different sequences may apply different offsets to the same frame
                sprites = loader.LoadAllSprites(srcOverride ?? unit).Select(
                    s => new Sprite(s.sheet, s.bounds, s.offset + offset, s.channel, blendMode)).ToArray();

                if (!d.ContainsKey("Length"))
                {
                    Length = 1;
                }
                else if (d["Length"].Value == "*")
                {
                    Length = sprites.Length - Start;
                }
                else
                {
                    Length = Exts.ParseIntegerInvariant(d["Length"].Value);
                }

                if (d.ContainsKey("Stride"))
                {
                    Stride = Exts.ParseIntegerInvariant(d["Stride"].Value);
                }
                else
                {
                    Stride = Length;
                }

                if (d.ContainsKey("Facings"))
                {
                    var f = Exts.ParseIntegerInvariant(d["Facings"].Value);
                    Facings        = Math.Abs(f);
                    reverseFacings = f < 0;
                }
                else
                {
                    Facings = 1;
                }

                if (d.ContainsKey("Tick"))
                {
                    Tick = Exts.ParseIntegerInvariant(d["Tick"].Value);
                }
                else
                {
                    Tick = 40;
                }

                if (d.ContainsKey("Transpose"))
                {
                    transpose = bool.Parse(d["Transpose"].Value);
                }

                if (d.ContainsKey("Frames"))
                {
                    Frames = Array.ConvertAll <string, int>(d["Frames"].Value.Split(','), Exts.ParseIntegerInvariant);
                }

                if (d.ContainsKey("ShadowStart"))
                {
                    ShadowStart = Exts.ParseIntegerInvariant(d["ShadowStart"].Value);
                }
                else
                {
                    ShadowStart = -1;
                }

                if (d.ContainsKey("ShadowZOffset"))
                {
                    WRange r;
                    if (WRange.TryParse(d["ShadowZOffset"].Value, out r))
                    {
                        ShadowZOffset = r.Range;
                    }
                }
                else
                {
                    ShadowZOffset = -5;
                }

                if (d.ContainsKey("ZOffset"))
                {
                    WRange r;
                    if (WRange.TryParse(d["ZOffset"].Value, out r))
                    {
                        ZOffset = r.Range;
                    }
                }

                if (Length > Stride)
                {
                    throw new InvalidOperationException(
                              "{0}: Sequence {1}.{2}: Length must be <= stride"
                              .F(info.Nodes[0].Location, unit, name));
                }

                if (Start < 0 || Start + Facings * Stride > sprites.Length || ShadowStart + Facings * Stride > sprites.Length)
                {
                    throw new InvalidOperationException(
                              "{6}: Sequence {0}.{1} uses frames [{2}..{3}] of SHP `{4}`, but only 0..{5} actually exist"
                              .F(unit, name, Start, Start + Facings * Stride - 1, srcOverride ?? unit, sprites.Length - 1,
                                 info.Nodes[0].Location));
                }
            }
            catch (FormatException f)
            {
                throw new FormatException("Failed to parse sequences for {0}.{1} at {2}:\n{3}".F(unit, name, info.Nodes[0].Location, f));
            }
        }
Пример #6
0
 public ResourceTypeInfo(MiniYaml yaml)
 {
     FieldLoader.Load(this, yaml);
 }
Пример #7
0
 public static Slot Deserialize(MiniYaml data)
 {
     return(FieldLoader.Load <Slot>(data));
 }
Пример #8
0
 public static T NodeValue <T>(this MiniYamlNode node)
 {
     return(FieldLoader.GetValue <T>(node.Key, node.Value.Value));
 }
Пример #9
0
        public void DropClient(Connection toDrop)
        {
            if (preConns.Contains(toDrop))
            {
                preConns.Remove(toDrop);
            }
            else
            {
                conns.Remove(toDrop);

                var dropClient = lobbyInfo.Clients.FirstOrDefault(c1 => c1.Index == toDrop.PlayerIndex);
                if (dropClient == null)
                {
                    return;
                }

                // Send disconnected order, even if still in the lobby
                SendMessage("{0} has disconnected.".F(dropClient.Name));
                DispatchOrdersToClients(toDrop, 0, new ServerOrder("Disconnected", "").Serialize());

                lobbyInfo.Clients.RemoveAll(c => c.Index == toDrop.PlayerIndex);

                // Client was the server admin
                // TODO: Reassign admin for game in progress via an order
                if (lobbyInfo.GlobalSettings.Dedicated && dropClient.IsAdmin && State == ServerState.WaitingPlayers)
                {
                    // Remove any bots controlled by the admin
                    lobbyInfo.Clients.RemoveAll(c => c.Bot != null && c.BotControllerClientIndex == toDrop.PlayerIndex);

                    var nextAdmin = lobbyInfo.Clients.Where(c1 => c1.Bot == null)
                                    .OrderBy(c => c.Index).FirstOrDefault();

                    if (nextAdmin != null)
                    {
                        nextAdmin.IsAdmin = true;
                        SendMessage("{0} is now the admin.".F(nextAdmin.Name));
                    }
                }

                DispatchOrders(toDrop, toDrop.MostRecentFrame, new byte[] { 0xbf });

                if (!conns.Any())
                {
                    FieldLoader.Load(lobbyInfo.GlobalSettings, ModData.Manifest.LobbyDefaults);
                    TempBans.Clear();
                }

                if (conns.Any() || lobbyInfo.GlobalSettings.Dedicated)
                {
                    SyncLobbyInfo();
                }

                if (!lobbyInfo.GlobalSettings.Dedicated && dropClient.IsAdmin)
                {
                    Shutdown();
                }
            }

            try
            {
                toDrop.socket.Disconnect(false);
            }
            catch { }

            SetOrderLag();
        }
        Action InitDisplayPanel(Widget panel)
        {
            var ds = Game.Settings.Graphics;
            var gs = Game.Settings.Game;

            BindCheckboxPref(panel, "HARDWARECURSORS_CHECKBOX", ds, "HardwareCursors");
            BindCheckboxPref(panel, "PIXELDOUBLE_CHECKBOX", ds, "PixelDouble");
            BindCheckboxPref(panel, "CURSORDOUBLE_CHECKBOX", ds, "CursorDouble");
            BindCheckboxPref(panel, "FRAME_LIMIT_CHECKBOX", ds, "CapFramerate");
            BindCheckboxPref(panel, "DISPLAY_TARGET_LINES_CHECKBOX", gs, "DrawTargetLine");
            BindCheckboxPref(panel, "PLAYER_STANCE_COLORS_CHECKBOX", gs, "UsePlayerStanceColors");

            var languageDropDownButton = panel.Get <DropDownButtonWidget>("LANGUAGE_DROPDOWNBUTTON");

            languageDropDownButton.OnMouseDown = _ => ShowLanguageDropdown(languageDropDownButton, modData.Languages);
            languageDropDownButton.GetText     = () => FieldLoader.Translate(ds.Language);

            var windowModeDropdown = panel.Get <DropDownButtonWidget>("MODE_DROPDOWN");

            windowModeDropdown.OnMouseDown = _ => ShowWindowModeDropdown(windowModeDropdown, ds);
            windowModeDropdown.GetText     = () => ds.Mode == WindowMode.Windowed ?
                                             "Windowed" : ds.Mode == WindowMode.Fullscreen ? "Fullscreen (Legacy)" : "Fullscreen";

            var statusBarsDropDown = panel.Get <DropDownButtonWidget>("STATUS_BAR_DROPDOWN");

            statusBarsDropDown.OnMouseDown = _ => ShowStatusBarsDropdown(statusBarsDropDown, gs);
            statusBarsDropDown.GetText     = () => gs.StatusBars.ToString() == "Standard" ?
                                             "Standard" : gs.StatusBars.ToString() == "DamageShow" ? "Show On Damage" : "Always Show";

            // Update zoom immediately
            var pixelDoubleCheckbox = panel.Get <CheckboxWidget>("PIXELDOUBLE_CHECKBOX");
            var pixelDoubleOnClick  = pixelDoubleCheckbox.OnClick;

            pixelDoubleCheckbox.OnClick = () =>
            {
                pixelDoubleOnClick();
                worldRenderer.Viewport.Zoom = ds.PixelDouble ? 2 : 1;
            };

            // Cursor doubling is only supported with software cursors and when pixel doubling is enabled
            var cursorDoubleCheckbox = panel.Get <CheckboxWidget>("CURSORDOUBLE_CHECKBOX");

            cursorDoubleCheckbox.IsDisabled = () => !ds.PixelDouble || Game.Cursor is HardwareCursor;

            var cursorDoubleIsChecked = cursorDoubleCheckbox.IsChecked;

            cursorDoubleCheckbox.IsChecked = () => !cursorDoubleCheckbox.IsDisabled() && cursorDoubleIsChecked();

            panel.Get("WINDOW_RESOLUTION").IsVisible = () => ds.Mode == WindowMode.Windowed;
            var windowWidth = panel.Get <TextFieldWidget>("WINDOW_WIDTH");

            windowWidth.Text = ds.WindowedSize.X.ToString();

            var windowHeight = panel.Get <TextFieldWidget>("WINDOW_HEIGHT");

            windowHeight.Text = ds.WindowedSize.Y.ToString();

            var frameLimitTextfield = panel.Get <TextFieldWidget>("FRAME_LIMIT_TEXTFIELD");

            frameLimitTextfield.Text = ds.MaxFramerate.ToString();
            var escPressed = false;

            frameLimitTextfield.OnLoseFocus = () =>
            {
                if (escPressed)
                {
                    escPressed = false;
                    return;
                }

                int fps;
                Exts.TryParseIntegerInvariant(frameLimitTextfield.Text, out fps);
                ds.MaxFramerate          = fps.Clamp(1, 1000);
                frameLimitTextfield.Text = ds.MaxFramerate.ToString();
            };

            frameLimitTextfield.OnEnterKey = () => { frameLimitTextfield.YieldKeyboardFocus(); return(true); };
            frameLimitTextfield.OnEscKey   = () =>
            {
                frameLimitTextfield.Text = ds.MaxFramerate.ToString();
                escPressed = true;
                frameLimitTextfield.YieldKeyboardFocus();
                return(true);
            };

            frameLimitTextfield.IsDisabled = () => !ds.CapFramerate;

            // Player profile
            var ps = Game.Settings.Player;

            var nameTextfield = panel.Get <TextFieldWidget>("PLAYERNAME");

            nameTextfield.IsDisabled  = () => worldRenderer.World.Type != WorldType.Shellmap;
            nameTextfield.Text        = Settings.SanitizedPlayerName(ps.Name);
            nameTextfield.OnLoseFocus = () =>
            {
                if (escPressed)
                {
                    escPressed = false;
                    return;
                }

                nameTextfield.Text = nameTextfield.Text.Trim();
                if (nameTextfield.Text.Length == 0)
                {
                    nameTextfield.Text = Settings.SanitizedPlayerName(ps.Name);
                }
                else
                {
                    nameTextfield.Text = Settings.SanitizedPlayerName(nameTextfield.Text);
                    ps.Name            = nameTextfield.Text;
                }
            };

            nameTextfield.OnEnterKey = () => { nameTextfield.YieldKeyboardFocus(); return(true); };
            nameTextfield.OnEscKey   = () =>
            {
                nameTextfield.Text = Settings.SanitizedPlayerName(ps.Name);
                escPressed         = true;
                nameTextfield.YieldKeyboardFocus();
                return(true);
            };

            var colorPreview = panel.Get <ColorPreviewManagerWidget>("COLOR_MANAGER");

            colorPreview.Color = ps.Color;

            var colorDropdown = panel.Get <DropDownButtonWidget>("PLAYERCOLOR");

            colorDropdown.IsDisabled  = () => worldRenderer.World.Type != WorldType.Shellmap;
            colorDropdown.OnMouseDown = _ => ColorPickerLogic.ShowColorDropDown(colorDropdown, colorPreview, worldRenderer.World);
            colorDropdown.Get <ColorBlockWidget>("COLORBLOCK").GetColor = () => ps.Color.RGB;

            return(() =>
            {
                int x, y;
                Exts.TryParseIntegerInvariant(windowWidth.Text, out x);
                Exts.TryParseIntegerInvariant(windowHeight.Text, out y);
                ds.WindowedSize = new int2(x, y);
                frameLimitTextfield.YieldKeyboardFocus();
                nameTextfield.YieldKeyboardFocus();
            });
        }
Пример #11
0
 public PlayerReference(MiniYaml my)
 {
     FieldLoader.Load(this, my);
 }
Пример #12
0
        public CommandBarLogic(Widget widget, World world, Dictionary <string, MiniYaml> logicArgs)
        {
            this.world = world;

            var highlightOnButtonPress = false;

            if (logicArgs.ContainsKey("HighlightOnButtonPress"))
            {
                highlightOnButtonPress = FieldLoader.GetValue <bool>("HighlightOnButtonPress", logicArgs["HighlightOnButtonPress"].Value);
            }

            var attackMoveButton = widget.GetOrNull <ButtonWidget>("ATTACK_MOVE");

            if (attackMoveButton != null)
            {
                BindButtonIcon(attackMoveButton);

                attackMoveButton.IsDisabled    = () => { UpdateStateIfNecessary(); return(attackMoveDisabled); };
                attackMoveButton.IsHighlighted = () => world.OrderGenerator is AttackMoveOrderGenerator;

                Action <bool> toggle = allowCancel =>
                {
                    if (attackMoveButton.IsHighlighted())
                    {
                        if (allowCancel)
                        {
                            world.CancelInputMode();
                        }
                    }
                    else
                    {
                        world.OrderGenerator = new AttackMoveOrderGenerator(selectedActors, Game.Settings.Game.MouseButtonPreference.Action);
                    }
                };

                attackMoveButton.OnClick    = () => toggle(true);
                attackMoveButton.OnKeyPress = _ => toggle(false);
            }

            var forceMoveButton = widget.GetOrNull <ButtonWidget>("FORCE_MOVE");

            if (forceMoveButton != null)
            {
                BindButtonIcon(forceMoveButton);

                forceMoveButton.IsDisabled    = () => { UpdateStateIfNecessary(); return(forceMoveDisabled); };
                forceMoveButton.IsHighlighted = () => !forceMoveButton.IsDisabled() && IsForceModifiersActive(Modifiers.Alt);
                forceMoveButton.OnClick       = () =>
                {
                    if (forceMoveButton.IsHighlighted())
                    {
                        world.CancelInputMode();
                    }
                    else
                    {
                        world.OrderGenerator = new ForceModifiersOrderGenerator(Modifiers.Alt, true);
                    }
                };
            }

            var forceAttackButton = widget.GetOrNull <ButtonWidget>("FORCE_ATTACK");

            if (forceAttackButton != null)
            {
                BindButtonIcon(forceAttackButton);

                forceAttackButton.IsDisabled    = () => { UpdateStateIfNecessary(); return(forceAttackDisabled); };
                forceAttackButton.IsHighlighted = () => !forceAttackButton.IsDisabled() && IsForceModifiersActive(Modifiers.Ctrl) &&
                                                  !(world.OrderGenerator is AttackMoveOrderGenerator);

                forceAttackButton.OnClick = () =>
                {
                    if (forceAttackButton.IsHighlighted())
                    {
                        world.CancelInputMode();
                    }
                    else
                    {
                        world.OrderGenerator = new ForceModifiersOrderGenerator(Modifiers.Ctrl, true);
                    }
                };
            }

            var guardButton = widget.GetOrNull <ButtonWidget>("GUARD");

            if (guardButton != null)
            {
                BindButtonIcon(guardButton);

                guardButton.IsDisabled    = () => { UpdateStateIfNecessary(); return(guardDisabled); };
                guardButton.IsHighlighted = () => world.OrderGenerator is GenericSelectTarget &&
                                            ((GenericSelectTarget)world.OrderGenerator).OrderName == "Guard";

                Action <bool> toggle = allowCancel =>
                {
                    if (guardButton.IsHighlighted())
                    {
                        if (allowCancel)
                        {
                            world.CancelInputMode();
                        }
                    }
                    else
                    {
                        world.OrderGenerator = new GuardOrderGenerator(selectedActors,
                                                                       "Guard", "guard", Game.Settings.Game.MouseButtonPreference.Action);
                    }
                };

                guardButton.OnClick    = () => toggle(true);
                guardButton.OnKeyPress = _ => toggle(false);
            }

            var scatterButton = widget.GetOrNull <ButtonWidget>("SCATTER");

            if (scatterButton != null)
            {
                BindButtonIcon(scatterButton);

                scatterButton.IsDisabled    = () => { UpdateStateIfNecessary(); return(scatterDisabled); };
                scatterButton.IsHighlighted = () => scatterHighlighted > 0;
                scatterButton.OnClick       = () =>
                {
                    if (highlightOnButtonPress)
                    {
                        scatterHighlighted = 2;
                    }

                    PerformKeyboardOrderOnSelection(a => new Order("Scatter", a, false));
                };

                scatterButton.OnKeyPress = ki => { scatterHighlighted = 2; scatterButton.OnClick(); };
            }

            var deployButton = widget.GetOrNull <ButtonWidget>("DEPLOY");

            if (deployButton != null)
            {
                BindButtonIcon(deployButton);

                deployButton.IsDisabled    = () => { UpdateStateIfNecessary(); return(!selectedDeploys.Any(pair => pair.Trait.CanIssueDeployOrder(pair.Actor))); };
                deployButton.IsHighlighted = () => deployHighlighted > 0;
                deployButton.OnClick       = () =>
                {
                    if (highlightOnButtonPress)
                    {
                        deployHighlighted = 2;
                    }

                    var queued = Game.GetModifierKeys().HasModifier(Modifiers.Shift);
                    PerformDeployOrderOnSelection(queued);
                };

                deployButton.OnKeyPress = ki => { deployHighlighted = 2; deployButton.OnClick(); };
            }

            var stopButton = widget.GetOrNull <ButtonWidget>("STOP");

            if (stopButton != null)
            {
                BindButtonIcon(stopButton);

                stopButton.IsDisabled    = () => { UpdateStateIfNecessary(); return(stopDisabled); };
                stopButton.IsHighlighted = () => stopHighlighted > 0;
                stopButton.OnClick       = () =>
                {
                    if (highlightOnButtonPress)
                    {
                        stopHighlighted = 2;
                    }

                    PerformKeyboardOrderOnSelection(a => new Order("Stop", a, false));
                };

                stopButton.OnKeyPress = ki => { stopHighlighted = 2; stopButton.OnClick(); };
            }

            var queueOrdersButton = widget.GetOrNull <ButtonWidget>("QUEUE_ORDERS");

            if (queueOrdersButton != null)
            {
                BindButtonIcon(queueOrdersButton);

                queueOrdersButton.IsDisabled    = () => { UpdateStateIfNecessary(); return(waypointModeDisabled); };
                queueOrdersButton.IsHighlighted = () => !queueOrdersButton.IsDisabled() && IsForceModifiersActive(Modifiers.Shift);
                queueOrdersButton.OnClick       = () =>
                {
                    if (queueOrdersButton.IsHighlighted())
                    {
                        world.CancelInputMode();
                    }
                    else
                    {
                        world.OrderGenerator = new ForceModifiersOrderGenerator(Modifiers.Shift, false);
                    }
                };
            }

            var keyOverrides = widget.GetOrNull <LogicKeyListenerWidget>("MODIFIER_OVERRIDES");

            if (keyOverrides != null)
            {
                keyOverrides.AddHandler(e =>
                {
                    // HACK: allow attack move to be triggered if the ctrl key is pressed (assault move)
                    var eNoCtrl        = e;
                    eNoCtrl.Modifiers &= ~Modifiers.Ctrl;

                    if (attackMoveButton != null && !attackMoveDisabled && attackMoveButton.Key.IsActivatedBy(eNoCtrl))
                    {
                        attackMoveButton.OnKeyPress(e);
                        return(true);
                    }

                    // HACK: allow deploy to be triggered if the shift key is pressed (queued order)
                    if (e.Modifiers.HasModifier(Modifiers.Shift) && e.Event == KeyInputEvent.Down)
                    {
                        var eNoShift        = e;
                        eNoShift.Modifiers &= ~Modifiers.Shift;

                        if (deployButton != null && !deployButton.IsDisabled() &&
                            deployButton.Key.IsActivatedBy(eNoShift))
                        {
                            deployButton.OnKeyPress(e);
                            return(true);
                        }
                    }

                    return(false);
                });
            }
        }
Пример #13
0
        static void Run(string[] args)
        {
            var arguments = new Arguments(args);

            var engineDirArg = arguments.GetValue("Engine.EngineDir", null);

            if (!string.IsNullOrEmpty(engineDirArg))
            {
                Platform.OverrideEngineDir(engineDirArg);
            }

            var supportDirArg = arguments.GetValue("Engine.SupportDir", null);

            if (!string.IsNullOrEmpty(supportDirArg))
            {
                Platform.OverrideSupportDir(supportDirArg);
            }

            Log.AddChannel("debug", "dedicated-debug.log", true);
            Log.AddChannel("perf", "dedicated-perf.log", true);
            Log.AddChannel("server", "dedicated-server.log", true);
            Log.AddChannel("nat", "dedicated-nat.log", true);
            Log.AddChannel("geoip", "dedicated-geoip.log", true);

            // Special case handling of Game.Mod argument: if it matches a real filesystem path
            // then we use this to override the mod search path, and replace it with the mod id
            var modID            = arguments.GetValue("Game.Mod", null);
            var explicitModPaths = Array.Empty <string>();

            if (modID != null && (File.Exists(modID) || Directory.Exists(modID)))
            {
                explicitModPaths = new[] { modID };
                modID            = Path.GetFileNameWithoutExtension(modID);
            }

            if (modID == null)
            {
                throw new InvalidOperationException("Game.Mod argument missing or mod could not be found.");
            }

            // HACK: The engine code assumes that Game.Settings is set.
            // This isn't nearly as bad as ModData, but is still not very nice.
            Game.InitializeSettings(arguments);
            var settings = Game.Settings.Server;

            Nat.Initialize();

            var envModSearchPaths = Environment.GetEnvironmentVariable("MOD_SEARCH_PATHS");
            var modSearchPaths    = !string.IsNullOrWhiteSpace(envModSearchPaths) ?
                                    FieldLoader.GetValue <string[]>("MOD_SEARCH_PATHS", envModSearchPaths) :
                                    new[] { Path.Combine(Platform.EngineDir, "mods") };

            var mods = new InstalledMods(modSearchPaths, explicitModPaths);

            Console.WriteLine("[{0}] Starting dedicated server for mod: {1}", DateTime.Now.ToString(settings.TimestampFormat), modID);
            while (true)
            {
                // HACK: The engine code *still* assumes that Game.ModData is set
                var modData = Game.ModData = new ModData(mods[modID], mods);
                modData.MapCache.LoadMaps();

                settings.Map = modData.MapCache.ChooseInitialMap(settings.Map, new MersenneTwister());

                var endpoints = new List <IPEndPoint> {
                    new IPEndPoint(IPAddress.IPv6Any, settings.ListenPort), new IPEndPoint(IPAddress.Any, settings.ListenPort)
                };
                var server = new Server(endpoints, settings, modData, ServerType.Dedicated);

                GC.Collect();
                while (true)
                {
                    Thread.Sleep(1000);
                    if (server.State == ServerState.GameStarted && server.Conns.Count < 1)
                    {
                        Console.WriteLine("[{0}] No one is playing, shutting down...", DateTime.Now.ToString(settings.TimestampFormat));
                        server.Shutdown();
                        break;
                    }
                }

                modData.Dispose();
                Console.WriteLine("[{0}] Starting a new server instance...", DateTime.Now.ToString(settings.TimestampFormat));
            }
        }
Пример #14
0
 public void Initialize(MiniYaml yaml)
 {
     Initialize((int)FieldLoader.GetValue("value", typeof(int), yaml.Value));
 }
Пример #15
0
        void IUtilityCommand.Run(Utility utility, string[] args)
        {
            // HACK: The engine code assumes that Game.modData is set.
            Game.ModData = utility.ModData;

            var version = utility.ModData.Manifest.Metadata.Version;

            if (args.Length > 1)
            {
                version = args[1];
            }

            Console.WriteLine(
                "This documentation is aimed at modders. It displays all traits with default values and developer commentary. " +
                "Please do not edit it directly, but add new `[Desc(\"String\")]` tags to the source code. This file has been " +
                "automatically generated for version {0} of OpenRA.", version);
            Console.WriteLine();

            var doc = new StringBuilder();
            var currentNamespace = "";

            foreach (var t in Game.ModData.ObjectCreator.GetTypesImplementing <TraitInfo>().OrderBy(t => t.Namespace))
            {
                if (t.ContainsGenericParameters || t.IsAbstract)
                {
                    continue;                     // skip helpers like TraitInfo<T>
                }
                if (currentNamespace != t.Namespace)
                {
                    currentNamespace = t.Namespace;
                    doc.AppendLine();
                    doc.AppendLine($"## {currentNamespace}");
                }

                var traitName      = t.Name.EndsWith("Info") ? t.Name.Substring(0, t.Name.Length - 4) : t.Name;
                var traitDescLines = t.GetCustomAttributes <DescAttribute>(false).SelectMany(d => d.Lines);
                doc.AppendLine();
                doc.AppendLine($"### {traitName}");
                foreach (var line in traitDescLines)
                {
                    doc.AppendLine(line);
                }

                var requires = RequiredTraitTypes(t);
                var reqCount = requires.Length;
                if (reqCount > 0)
                {
                    if (t.HasAttribute <DescAttribute>())
                    {
                        doc.AppendLine();
                    }

                    doc.Append($"Requires trait{(reqCount > 1 ? "s" : "")}: ");

                    var i = 0;
                    foreach (var require in requires)
                    {
                        var n    = require.Name;
                        var name = n.EndsWith("Info") ? n.Remove(n.Length - 4, 4) : n;
                        doc.Append($"[`{name}`](#{name.ToLowerInvariant()}){(i + 1 == reqCount ? ".\n" : ", ")}");
                        i++;
                    }
                }

                var infos = FieldLoader.GetTypeLoadInfo(t);
                if (!infos.Any())
                {
                    continue;
                }
                doc.AppendLine("<table>");
                doc.AppendLine("<tr><th>Property</th><th>Default Value</th><th>Type</th><th>Description</th></tr>");
                var liveTraitInfo = Game.ModData.ObjectCreator.CreateBasic(t);
                foreach (var info in infos)
                {
                    var fieldDescLines = info.Field.GetCustomAttributes <DescAttribute>(true).SelectMany(d => d.Lines);
                    var fieldType      = Util.FriendlyTypeName(info.Field.FieldType);
                    var loadInfo       = info.Field.GetCustomAttributes <FieldLoader.SerializeAttribute>(true).FirstOrDefault();
                    var defaultValue   = loadInfo != null && loadInfo.Required ? "<em>(required)</em>" : FieldSaver.SaveField(liveTraitInfo, info.Field.Name).Value.Value;
                    doc.Append($"<tr><td>{info.YamlName}</td><td>{defaultValue}</td><td>{fieldType}</td>");
                    doc.Append("<td>");
                    foreach (var line in fieldDescLines)
                    {
                        doc.Append(line + " ");
                    }
                    doc.AppendLine("</td></tr>");
                }

                doc.AppendLine("</table>");
            }

            Console.Write(doc.ToString());
        }
Пример #16
0
        public Server(IPEndPoint endpoint, string[] mods, ServerSettings settings, ModData modData)
        {
            Log.AddChannel("server", "server.log");

            pState   = ServerState.WaitingPlayers;
            listener = new TcpListener(endpoint);
            listener.Start();
            var localEndpoint = (IPEndPoint)listener.LocalEndpoint;

            Ip   = localEndpoint.Address;
            Port = localEndpoint.Port;

            Settings = settings;
            ModData  = modData;

            randomSeed = (int)DateTime.Now.ToBinary();

            if (Settings.AllowPortForward)
            {
                UPnP.ForwardPort();
            }

            foreach (var trait in modData.Manifest.ServerTraits)
            {
                ServerTraits.Add(modData.ObjectCreator.CreateObject <ServerTrait>(trait));
            }

            lobbyInfo = new Session(mods);
            lobbyInfo.GlobalSettings.RandomSeed = randomSeed;
            lobbyInfo.GlobalSettings.Map        = settings.Map;
            lobbyInfo.GlobalSettings.ServerName = settings.Name;
            lobbyInfo.GlobalSettings.Dedicated  = settings.Dedicated;
            FieldLoader.Load(lobbyInfo.GlobalSettings, modData.Manifest.LobbyDefaults);

            foreach (var t in ServerTraits.WithInterface <INotifyServerStart>())
            {
                t.ServerStarted(this);
            }

            Log.Write("server", "Initial mods: ");
            foreach (var m in lobbyInfo.GlobalSettings.Mods)
            {
                Log.Write("server", "- {0}", m);
            }

            Log.Write("server", "Initial map: {0}", lobbyInfo.GlobalSettings.Map);

            new Thread(_ =>
            {
                var timeout = ServerTraits.WithInterface <ITick>().Min(t => t.TickTimeout);
                for (;;)
                {
                    var checkRead = new List <Socket>();
                    checkRead.Add(listener.Server);
                    foreach (var c in conns)
                    {
                        checkRead.Add(c.socket);
                    }
                    foreach (var c in preConns)
                    {
                        checkRead.Add(c.socket);
                    }

                    Socket.Select(checkRead, null, null, timeout);
                    if (State == ServerState.ShuttingDown)
                    {
                        EndGame();
                        break;
                    }

                    foreach (var s in checkRead)
                    {
                        if (s == listener.Server)
                        {
                            AcceptConnection();
                        }
                        else if (preConns.Count > 0)
                        {
                            var p = preConns.SingleOrDefault(c => c.socket == s);
                            if (p != null)
                            {
                                p.ReadData(this);
                            }
                        }
                        else if (conns.Count > 0)
                        {
                            var conn = conns.SingleOrDefault(c => c.socket == s);
                            if (conn != null)
                            {
                                conn.ReadData(this);
                            }
                        }
                    }

                    foreach (var t in ServerTraits.WithInterface <ITick>())
                    {
                        t.Tick(this);
                    }

                    if (State == ServerState.ShuttingDown)
                    {
                        EndGame();
                        if (Settings.AllowPortForward)
                        {
                            UPnP.RemovePortforward();
                        }
                        break;
                    }
                }

                foreach (var t in ServerTraits.WithInterface <INotifyServerShutdown>())
                {
                    t.ServerShutdown(this);
                }

                preConns.Clear();
                conns.Clear();
                try { listener.Stop(); }
                catch { }
            })
            {
                IsBackground = true
            }.Start();
        }
Пример #17
0
        public bool InterpretCommand(S server, Connection conn, Session.Client client, string cmd)
        {
            if (!ValidateCommand(server, conn, client, cmd))
            {
                return(false);
            }

            var dict = new Dictionary <string, Func <string, bool> >
            {
                { "state",
                  s =>
                  {
                      var state = Session.ClientState.Invalid;
                      if (!Enum <Session.ClientState> .TryParse(s, false, out state))
                      {
                          server.SendOrderTo(conn, "Message", "Malformed state command");
                          return(true);
                      }

                      client.State = state;

                      Log.Write("server", "Player @{0} is {1}",
                                conn.Socket.RemoteEndPoint, client.State);

                      server.SyncLobbyClients();

                      CheckAutoStart(server);

                      return(true);
                  } },
                { "startgame",
                  s =>
                  {
                      if (!client.IsAdmin)
                      {
                          server.SendOrderTo(conn, "Message", "Only the host can start the game.");
                          return(true);
                      }

                      if (server.LobbyInfo.Slots.Any(sl => sl.Value.Required &&
                                                     server.LobbyInfo.ClientInSlot(sl.Key) == null))
                      {
                          server.SendOrderTo(conn, "Message", "Unable to start the game until required slots are full.");
                          return(true);
                      }

                      server.StartGame();
                      return(true);
                  } },
                { "slot",
                  s =>
                  {
                      if (!server.LobbyInfo.Slots.ContainsKey(s))
                      {
                          Log.Write("server", "Invalid slot: {0}", s);
                          return(false);
                      }

                      var slot = server.LobbyInfo.Slots[s];

                      if (slot.Closed || server.LobbyInfo.ClientInSlot(s) != null)
                      {
                          return(false);
                      }

                      client.Slot = s;
                      S.SyncClientToPlayerReference(client, server.MapPlayers.Players[s]);
                      server.SyncLobbyClients();
                      CheckAutoStart(server);

                      return(true);
                  } },
                { "allow_spectators",
                  s =>
                  {
                      if (bool.TryParse(s, out server.LobbyInfo.GlobalSettings.AllowSpectators))
                      {
                          server.SyncLobbyGlobalSettings();
                          return(true);
                      }
                      else
                      {
                          server.SendOrderTo(conn, "Message", "Malformed allow_spectate command");
                          return(true);
                      }
                  } },
                { "spectate",
                  s =>
                  {
                      if (server.LobbyInfo.GlobalSettings.AllowSpectators || client.IsAdmin)
                      {
                          client.Slot       = null;
                          client.SpawnPoint = 0;
                          client.Color      = HSLColor.FromRGB(255, 255, 255);
                          server.SyncLobbyClients();
                          return(true);
                      }
                      else
                      {
                          return(false);
                      }
                  } },
                { "slot_close",
                  s =>
                  {
                      if (!ValidateSlotCommand(server, conn, client, s, true))
                      {
                          return(false);
                      }

                      // kick any player that's in the slot
                      var occupant = server.LobbyInfo.ClientInSlot(s);
                      if (occupant != null)
                      {
                          if (occupant.Bot != null)
                          {
                              server.LobbyInfo.Clients.Remove(occupant);
                              server.SyncLobbyClients();
                              var ping = server.LobbyInfo.PingFromClient(occupant);
                              server.LobbyInfo.ClientPings.Remove(ping);
                              server.SyncClientPing();
                          }
                          else
                          {
                              var occupantConn = server.Conns.FirstOrDefault(c => c.PlayerIndex == occupant.Index);
                              if (occupantConn != null)
                              {
                                  server.SendOrderTo(occupantConn, "ServerError", "Your slot was closed by the host.");
                                  server.DropClient(occupantConn);
                              }
                          }
                      }

                      server.LobbyInfo.Slots[s].Closed = true;
                      server.SyncLobbySlots();
                      return(true);
                  } },
                { "slot_open",
                  s =>
                  {
                      if (!ValidateSlotCommand(server, conn, client, s, true))
                      {
                          return(false);
                      }

                      var slot = server.LobbyInfo.Slots[s];
                      slot.Closed = false;
                      server.SyncLobbySlots();

                      // Slot may have a bot in it
                      var occupant = server.LobbyInfo.ClientInSlot(s);
                      if (occupant != null && occupant.Bot != null)
                      {
                          server.LobbyInfo.Clients.Remove(occupant);
                          var ping = server.LobbyInfo.PingFromClient(occupant);
                          server.LobbyInfo.ClientPings.Remove(ping);
                      }

                      server.SyncLobbyClients();
                      return(true);
                  } },
                { "slot_bot",
                  s =>
                  {
                      var parts = s.Split(' ');

                      if (parts.Length < 3)
                      {
                          server.SendOrderTo(conn, "Message", "Malformed slot_bot command");
                          return(true);
                      }

                      if (!ValidateSlotCommand(server, conn, client, parts[0], true))
                      {
                          return(false);
                      }

                      var slot = server.LobbyInfo.Slots[parts[0]];
                      var bot  = server.LobbyInfo.ClientInSlot(parts[0]);
                      int controllerClientIndex;
                      if (!Exts.TryParseIntegerInvariant(parts[1], out controllerClientIndex))
                      {
                          Log.Write("server", "Invalid bot controller client index: {0}", parts[1]);
                          return(false);
                      }

                      var botType = parts.Skip(2).JoinWith(" ");

                      // Invalid slot
                      if (bot != null && bot.Bot == null)
                      {
                          server.SendOrderTo(conn, "Message", "Can't add bots to a slot with another client.");
                          return(true);
                      }

                      slot.Closed = false;
                      if (bot == null)
                      {
                          // Create a new bot
                          bot = new Session.Client()
                          {
                              Index      = server.ChooseFreePlayerIndex(),
                              Name       = botType,
                              Bot        = botType,
                              Slot       = parts[0],
                              Race       = "Random",
                              SpawnPoint = 0,
                              Team       = 0,
                              State      = Session.ClientState.NotReady,
                              BotControllerClientIndex = controllerClientIndex
                          };

                          // Pick a random color for the bot
                          HSLColor botColor;
                          do
                          {
                              var hue = (byte)server.Random.Next(255);
                              var sat = (byte)server.Random.Next(255);
                              var lum = (byte)server.Random.Next(51, 255);
                              botColor = new HSLColor(hue, sat, lum);
                          } while (!ColorValidator.ValidatePlayerNewColor(server, botColor.RGB, bot.Index));

                          bot.Color = bot.PreferredColor = botColor;

                          server.LobbyInfo.Clients.Add(bot);
                      }
                      else
                      {
                          // Change the type of the existing bot
                          bot.Name = botType;
                          bot.Bot  = botType;
                      }

                      S.SyncClientToPlayerReference(bot, server.MapPlayers.Players[parts[0]]);
                      server.SyncLobbyClients();
                      server.SyncLobbySlots();
                      return(true);
                  } },
                { "map",
                  s =>
                  {
                      if (!client.IsAdmin)
                      {
                          server.SendOrderTo(conn, "Message", "Only the host can change the map.");
                          return(true);
                      }

                      if (server.ModData.MapCache[s].Status != MapStatus.Available)
                      {
                          server.SendOrderTo(conn, "Message", "Map was not found on server.");
                          return(true);
                      }

                      server.LobbyInfo.GlobalSettings.Map = s;

                      var oldSlots = server.LobbyInfo.Slots.Keys.ToArray();
                      LoadMap(server);
                      SetDefaultDifficulty(server);

                      // Reset client states
                      foreach (var c in server.LobbyInfo.Clients)
                      {
                          c.State = Session.ClientState.Invalid;
                      }

                      // Reassign players into new slots based on their old slots:
                      //  - Observers remain as observers
                      //  - Players who now lack a slot are made observers
                      //  - Bots who now lack a slot are dropped
                      var slots = server.LobbyInfo.Slots.Keys.ToArray();
                      var i     = 0;
                      foreach (var os in oldSlots)
                      {
                          var c = server.LobbyInfo.ClientInSlot(os);
                          if (c == null)
                          {
                              continue;
                          }

                          c.SpawnPoint = 0;
                          c.Slot       = i < slots.Length ? slots[i++] : null;
                          if (c.Slot != null)
                          {
                              // Remove Bot from slot if slot forbids bots
                              if (c.Bot != null && !server.MapPlayers.Players[c.Slot].AllowBots)
                              {
                                  server.LobbyInfo.Clients.Remove(c);
                              }
                              S.SyncClientToPlayerReference(c, server.MapPlayers.Players[c.Slot]);
                          }
                          else if (c.Bot != null)
                          {
                              server.LobbyInfo.Clients.Remove(c);
                          }
                      }

                      foreach (var c in server.LobbyInfo.Clients)
                      {
                          // Validate if color is allowed and get an alternative it it isn't
                          c.Color = c.PreferredColor = ColorValidator.ValidatePlayerColorAndGetAlternative(server, c.Color, c.Index, conn);
                      }

                      server.SyncLobbyInfo();

                      server.SendMessage("{0} changed the map to {1}.".F(client.Name, server.Map.Title));

                      return(true);
                  } },
                { "fragilealliance",
                  s =>
                  {
                      if (!client.IsAdmin)
                      {
                          server.SendOrderTo(conn, "Message", "Only the host can set that option.");
                          return(true);
                      }

                      if (server.Map.Options.FragileAlliances.HasValue)
                      {
                          server.SendOrderTo(conn, "Message", "Map has disabled alliance configuration.");
                          return(true);
                      }

                      bool.TryParse(s, out server.LobbyInfo.GlobalSettings.FragileAlliances);
                      server.SyncLobbyGlobalSettings();
                      server.SendMessage("{0} {1} Diplomacy Changes."
                                         .F(client.Name, server.LobbyInfo.GlobalSettings.FragileAlliances ? "enabled" : "disabled"));

                      return(true);
                  } },
                { "allowcheats",
                  s =>
                  {
                      if (!client.IsAdmin)
                      {
                          server.SendOrderTo(conn, "Message", "Only the host can set that option.");
                          return(true);
                      }

                      if (server.Map.Options.Cheats.HasValue)
                      {
                          server.SendOrderTo(conn, "Message", "Map has disabled cheat configuration.");
                          return(true);
                      }

                      bool.TryParse(s, out server.LobbyInfo.GlobalSettings.AllowCheats);
                      server.SyncLobbyGlobalSettings();
                      server.SendMessage("{0} {1} Developer Cheats."
                                         .F(client.Name, server.LobbyInfo.GlobalSettings.AllowCheats ? "allowed" : "disallowed"));

                      return(true);
                  } },
                { "shroud",
                  s =>
                  {
                      if (!client.IsAdmin)
                      {
                          server.SendOrderTo(conn, "Message", "Only the host can set that option.");
                          return(true);
                      }

                      if (server.Map.Options.Shroud.HasValue)
                      {
                          server.SendOrderTo(conn, "Message", "Map has disabled shroud configuration.");
                          return(true);
                      }

                      bool.TryParse(s, out server.LobbyInfo.GlobalSettings.Shroud);
                      server.SyncLobbyGlobalSettings();
                      server.SendMessage("{0} {1} Shroud."
                                         .F(client.Name, server.LobbyInfo.GlobalSettings.Shroud ? "enabled" : "disabled"));

                      return(true);
                  } },
                { "fog",
                  s =>
                  {
                      if (!client.IsAdmin)
                      {
                          server.SendOrderTo(conn, "Message", "Only the host can set that option.");
                          return(true);
                      }

                      if (server.Map.Options.Fog.HasValue)
                      {
                          server.SendOrderTo(conn, "Message", "Map has disabled fog configuration.");
                          return(true);
                      }

                      bool.TryParse(s, out server.LobbyInfo.GlobalSettings.Fog);
                      server.SyncLobbyGlobalSettings();
                      server.SendMessage("{0} {1} Fog of War."
                                         .F(client.Name, server.LobbyInfo.GlobalSettings.Fog ? "enabled" : "disabled"));

                      return(true);
                  } },
                { "assignteams",
                  s =>
                  {
                      if (!client.IsAdmin)
                      {
                          server.SendOrderTo(conn, "Message", "Only the host can set that option.");
                          return(true);
                      }

                      int teamCount;
                      if (!Exts.TryParseIntegerInvariant(s, out teamCount))
                      {
                          server.SendOrderTo(conn, "Message", "Number of teams could not be parsed: {0}".F(s));
                          return(true);
                      }

                      var maxTeams = (server.LobbyInfo.Clients.Count(c => c.Slot != null) + 1) / 2;
                      teamCount = teamCount.Clamp(0, maxTeams);
                      var clients = server.LobbyInfo.Slots
                                    .Select(slot => server.LobbyInfo.ClientInSlot(slot.Key))
                                    .Where(c => c != null && !server.LobbyInfo.Slots[c.Slot].LockTeam);

                      var assigned    = 0;
                      var clientCount = clients.Count();
                      foreach (var player in clients)
                      {
                          // Free for all
                          if (teamCount == 0)
                          {
                              player.Team = 0;
                          }

                          // Humans vs Bots
                          else if (teamCount == 1)
                          {
                              player.Team = player.Bot == null ? 1 : 2;
                          }
                          else
                          {
                              player.Team = assigned++ *teamCount / clientCount + 1;
                          }
                      }

                      server.SyncLobbyClients();
                      return(true);
                  } },
                { "crates",
                  s =>
                  {
                      if (!client.IsAdmin)
                      {
                          server.SendOrderTo(conn, "Message", "Only the host can set that option.");
                          return(true);
                      }

                      if (server.Map.Options.Crates.HasValue)
                      {
                          server.SendOrderTo(conn, "Message", "Map has disabled crate configuration.");
                          return(true);
                      }

                      bool.TryParse(s, out server.LobbyInfo.GlobalSettings.Crates);
                      server.SyncLobbyGlobalSettings();
                      server.SendMessage("{0} {1} Crates."
                                         .F(client.Name, server.LobbyInfo.GlobalSettings.Crates ? "enabled" : "disabled"));

                      return(true);
                  } },
                { "creeps",
                  s =>
                  {
                      if (!client.IsAdmin)
                      {
                          server.SendOrderTo(conn, "Message", "Only the host can set that option.");
                          return(true);
                      }

                      if (server.Map.Options.Creeps.HasValue)
                      {
                          server.SendOrderTo(conn, "Message", "Map has disabled Creeps spawning configuration.");
                          return(true);
                      }

                      bool.TryParse(s, out server.LobbyInfo.GlobalSettings.Creeps);
                      server.SyncLobbyGlobalSettings();
                      server.SendMessage("{0} {1} Creeps spawning."
                                         .F(client.Name, server.LobbyInfo.GlobalSettings.Creeps ? "enabled" : "disabled"));

                      return(true);
                  } },
                { "allybuildradius",
                  s =>
                  {
                      if (!client.IsAdmin)
                      {
                          server.SendOrderTo(conn, "Message", "Only the host can set that option.");
                          return(true);
                      }

                      if (server.Map.Options.AllyBuildRadius.HasValue)
                      {
                          server.SendOrderTo(conn, "Message", "Map has disabled ally build radius configuration.");
                          return(true);
                      }

                      bool.TryParse(s, out server.LobbyInfo.GlobalSettings.AllyBuildRadius);
                      server.SyncLobbyGlobalSettings();
                      server.SendMessage("{0} {1} Build off Allies' ConYards."
                                         .F(client.Name, server.LobbyInfo.GlobalSettings.AllyBuildRadius ? "enabled" : "disabled"));

                      return(true);
                  } },
                { "difficulty",
                  s =>
                  {
                      if (!server.Map.Options.Difficulties.Any())
                      {
                          return(true);
                      }

                      if (!client.IsAdmin)
                      {
                          server.SendOrderTo(conn, "Message", "Only the host can set that option.");
                          return(true);
                      }

                      if (s != null && !server.Map.Options.Difficulties.Contains(s))
                      {
                          server.SendOrderTo(conn, "Message", "Unsupported difficulty selected: {0}".F(s));
                          server.SendOrderTo(conn, "Message", "Supported difficulties: {0}".F(server.Map.Options.Difficulties.JoinWith(",")));
                          return(true);
                      }

                      server.LobbyInfo.GlobalSettings.Difficulty = s;
                      server.SyncLobbyGlobalSettings();
                      server.SendMessage("{0} changed difficulty to {1}.".F(client.Name, s));

                      return(true);
                  } },
                { "startingunits",
                  s =>
                  {
                      if (!client.IsAdmin)
                      {
                          server.SendOrderTo(conn, "Message", "Only the host can set that option.");
                          return(true);
                      }

                      if (!server.Map.Options.ConfigurableStartingUnits)
                      {
                          server.SendOrderTo(conn, "Message", "Map has disabled start unit configuration.");
                          return(true);
                      }

                      var startUnitsInfo = server.Map.Rules.Actors["world"].Traits.WithInterface <MPStartUnitsInfo>();
                      var selectedClass  = startUnitsInfo.Where(u => u.Class == s).Select(u => u.ClassName).FirstOrDefault();
                      var className      = selectedClass != null ? selectedClass : s;

                      server.LobbyInfo.GlobalSettings.StartingUnitsClass = s;
                      server.SyncLobbyGlobalSettings();
                      server.SendMessage("{0} changed Starting Units to {1}.".F(client.Name, className));

                      return(true);
                  } },
                { "startingcash",
                  s =>
                  {
                      if (!client.IsAdmin)
                      {
                          server.SendOrderTo(conn, "Message", "Only the host can set that option.");
                          return(true);
                      }

                      if (server.Map.Options.StartingCash.HasValue)
                      {
                          server.SendOrderTo(conn, "Message", "Map has disabled cash configuration.");
                          return(true);
                      }

                      server.LobbyInfo.GlobalSettings.StartingCash = Exts.ParseIntegerInvariant(s);
                      server.SyncLobbyGlobalSettings();
                      server.SendMessage("{0} changed Starting Cash to ${1}.".F(client.Name, s));

                      return(true);
                  } },
                { "techlevel",
                  s =>
                  {
                      if (!client.IsAdmin)
                      {
                          server.SendOrderTo(conn, "Message", "Only the host can set that option.");
                          return(true);
                      }

                      if (server.Map.Options.TechLevel != null)
                      {
                          server.SendOrderTo(conn, "Message", "Map has disabled Tech configuration.");
                          return(true);
                      }

                      server.LobbyInfo.GlobalSettings.TechLevel = s;
                      server.SyncLobbyInfo();
                      server.SendMessage("{0} changed Tech Level to {1}.".F(client.Name, s));

                      return(true);
                  } },
                { "kick",
                  s =>
                  {
                      if (!client.IsAdmin)
                      {
                          server.SendOrderTo(conn, "Message", "Only the host can kick players.");
                          return(true);
                      }

                      var split = s.Split(' ');
                      if (split.Length < 2)
                      {
                          server.SendOrderTo(conn, "Message", "Malformed kick command");
                          return(true);
                      }

                      int kickClientID;
                      Exts.TryParseIntegerInvariant(split[0], out kickClientID);

                      var kickConn = server.Conns.SingleOrDefault(c => server.GetClient(c) != null && server.GetClient(c).Index == kickClientID);
                      if (kickConn == null)
                      {
                          server.SendOrderTo(conn, "Message", "Noone in that slot.");
                          return(true);
                      }

                      var kickClient = server.GetClient(kickConn);

                      Log.Write("server", "Kicking client {0}.", kickClientID);
                      server.SendMessage("{0} kicked {1} from the server.".F(client.Name, kickClient.Name));
                      server.SendOrderTo(kickConn, "ServerError", "You have been kicked from the server.");
                      server.DropClient(kickConn);

                      bool tempBan;
                      bool.TryParse(split[1], out tempBan);

                      if (tempBan)
                      {
                          Log.Write("server", "Temporarily banning client {0} ({1}).", kickClientID, kickClient.IpAddress);
                          server.SendMessage("{0} temporarily banned {1} from the server.".F(client.Name, kickClient.Name));
                          server.TempBans.Add(kickClient.IpAddress);
                      }

                      server.SyncLobbyClients();
                      server.SyncLobbySlots();

                      return(true);
                  } },
                { "name",
                  s =>
                  {
                      Log.Write("server", "Player@{0} is now known as {1}.", conn.Socket.RemoteEndPoint, s);
                      server.SendMessage("{0} is now known as {1}.".F(client.Name, s));
                      client.Name = s;
                      server.SyncLobbyClients();
                      return(true);
                  } },
                { "race",
                  s =>
                  {
                      var parts        = s.Split(' ');
                      var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0]));

                      // Only the host can change other client's info
                      if (targetClient.Index != client.Index && !client.IsAdmin)
                      {
                          return(true);
                      }

                      // Map has disabled race changes
                      if (server.LobbyInfo.Slots[targetClient.Slot].LockRace)
                      {
                          return(true);
                      }

                      targetClient.Race = parts[1];
                      server.SyncLobbyClients();
                      return(true);
                  } },
                { "team",
                  s =>
                  {
                      var parts        = s.Split(' ');
                      var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0]));

                      // Only the host can change other client's info
                      if (targetClient.Index != client.Index && !client.IsAdmin)
                      {
                          return(true);
                      }

                      // Map has disabled team changes
                      if (server.LobbyInfo.Slots[targetClient.Slot].LockTeam)
                      {
                          return(true);
                      }

                      int team;
                      if (!Exts.TryParseIntegerInvariant(parts[1], out team))
                      {
                          Log.Write("server", "Invalid team: {0}", s);
                          return(false);
                      }

                      targetClient.Team = team;
                      server.SyncLobbyClients();
                      return(true);
                  } },
                { "spawn",
                  s =>
                  {
                      var parts        = s.Split(' ');
                      var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0]));

                      // Only the host can change other client's info
                      if (targetClient.Index != client.Index && !client.IsAdmin)
                      {
                          return(true);
                      }

                      // Spectators don't need a spawnpoint
                      if (targetClient.Slot == null)
                      {
                          return(true);
                      }

                      // Map has disabled spawn changes
                      if (server.LobbyInfo.Slots[targetClient.Slot].LockSpawn)
                      {
                          return(true);
                      }

                      int spawnPoint;
                      if (!Exts.TryParseIntegerInvariant(parts[1], out spawnPoint) ||
                          spawnPoint <0 || spawnPoint> server.Map.SpawnPoints.Value.Length)
                      {
                          Log.Write("server", "Invalid spawn point: {0}", parts[1]);
                          return(true);
                      }

                      if (server.LobbyInfo.Clients.Where(cc => cc != client).Any(cc => (cc.SpawnPoint == spawnPoint) && (cc.SpawnPoint != 0)))
                      {
                          server.SendOrderTo(conn, "Message", "You cannot occupy the same spawn point as another player.");
                          return(true);
                      }

                      targetClient.SpawnPoint = spawnPoint;
                      server.SyncLobbyClients();
                      return(true);
                  } },
                { "color",
                  s =>
                  {
                      var parts        = s.Split(' ');
                      var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0]));

                      // Only the host can change other client's info
                      if (targetClient.Index != client.Index && !client.IsAdmin)
                      {
                          return(true);
                      }

                      // Spectator or map has disabled color changes
                      if (targetClient.Slot == null || server.LobbyInfo.Slots[targetClient.Slot].LockColor)
                      {
                          return(true);
                      }

                      var newHslColor = FieldLoader.GetValue <HSLColor>("(value)", parts[1]);

                      // Validate if color is allowed and get an alternative it it isn't
                      var altHslColor = ColorValidator.ValidatePlayerColorAndGetAlternative(server, newHslColor, targetClient.Index, conn);

                      targetClient.Color = altHslColor;

                      // Only update player's preferred color if new color is valid
                      if (newHslColor == altHslColor)
                      {
                          targetClient.PreferredColor = altHslColor;
                      }

                      server.SyncLobbyClients();
                      return(true);
                  } },
                { "shortgame",
                  s =>
                  {
                      if (!client.IsAdmin)
                      {
                          server.SendOrderTo(conn, "Message", "Only the host can set that option.");
                          return(true);
                      }

                      if (server.Map.Options.ShortGame.HasValue)
                      {
                          server.SendOrderTo(conn, "Message", "Map has disabled short game configuration.");
                          return(true);
                      }

                      bool.TryParse(s, out server.LobbyInfo.GlobalSettings.ShortGame);
                      server.SyncLobbyGlobalSettings();
                      server.SendMessage("{0} {1} Short Game."
                                         .F(client.Name, server.LobbyInfo.GlobalSettings.ShortGame ? "enabled" : "disabled"));

                      return(true);
                  } }
            };

            var cmdName  = cmd.Split(' ').First();
            var cmdValue = cmd.Split(' ').Skip(1).JoinWith(" ");

            Func <string, bool> a;

            if (!dict.TryGetValue(cmdName, out a))
            {
                return(false);
            }

            return(a(cmdValue));
        }
Пример #18
0
 public WeaponInfo(string name, MiniYaml content)
 {
     FieldLoader.Load(this, content);
 }
Пример #19
0
 public static ClientPing Deserialize(MiniYaml data)
 {
     return(FieldLoader.Load <ClientPing>(data));
 }
Пример #20
0
 public WarheadInfo(MiniYaml yaml)
 {
     FieldLoader.Load(this, yaml);
 }
Пример #21
0
 public AutoConnectInfo(MiniYaml my)
 {
     FieldLoader.Load(this, my);
 }
Пример #22
0
        public CommandBarLogic(Widget widget, World world, Dictionary <string, MiniYaml> logicArgs)
        {
            this.world = world;

            var highlightOnButtonPress = false;

            if (logicArgs.ContainsKey("HighlightOnButtonPress"))
            {
                highlightOnButtonPress = FieldLoader.GetValue <bool>("HighlightOnButtonPress", logicArgs["HighlightOnButtonPress"].Value);
            }

            var attackMoveButton = widget.GetOrNull <ButtonWidget>("ATTACK_MOVE");

            if (attackMoveButton != null)
            {
                WidgetUtils.BindButtonIcon(attackMoveButton);

                attackMoveButton.IsDisabled    = () => { UpdateStateIfNecessary(); return(attackMoveDisabled); };
                attackMoveButton.IsHighlighted = () => world.OrderGenerator is AttackMoveOrderGenerator;

                Action <bool> toggle = allowCancel =>
                {
                    if (attackMoveButton.IsHighlighted())
                    {
                        if (allowCancel)
                        {
                            world.CancelInputMode();
                        }
                    }
                    else
                    {
                        world.OrderGenerator = new AttackMoveOrderGenerator(selectedActors, Game.Settings.Game.MouseButtonPreference.Action);
                    }
                };

                attackMoveButton.OnClick    = () => toggle(true);
                attackMoveButton.OnKeyPress = _ => toggle(false);
            }

            var forceMoveButton = widget.GetOrNull <ButtonWidget>("FORCE_MOVE");

            if (forceMoveButton != null)
            {
                WidgetUtils.BindButtonIcon(forceMoveButton);

                forceMoveButton.IsDisabled    = () => { UpdateStateIfNecessary(); return(forceMoveDisabled); };
                forceMoveButton.IsHighlighted = () => !forceMoveButton.IsDisabled() && IsForceModifiersActive(Modifiers.Alt);
                forceMoveButton.OnClick       = () =>
                {
                    if (forceMoveButton.IsHighlighted())
                    {
                        world.CancelInputMode();
                    }
                    else
                    {
                        world.OrderGenerator = new ForceModifiersOrderGenerator(Modifiers.Alt, true);
                    }
                };
            }

            var forceAttackButton = widget.GetOrNull <ButtonWidget>("FORCE_ATTACK");

            if (forceAttackButton != null)
            {
                WidgetUtils.BindButtonIcon(forceAttackButton);

                forceAttackButton.IsDisabled    = () => { UpdateStateIfNecessary(); return(forceAttackDisabled); };
                forceAttackButton.IsHighlighted = () => !forceAttackButton.IsDisabled() && IsForceModifiersActive(Modifiers.Ctrl) &&
                                                  !(world.OrderGenerator is AttackMoveOrderGenerator);

                forceAttackButton.OnClick = () =>
                {
                    if (forceAttackButton.IsHighlighted())
                    {
                        world.CancelInputMode();
                    }
                    else
                    {
                        world.OrderGenerator = new ForceModifiersOrderGenerator(Modifiers.Ctrl, true);
                    }
                };
            }

            var guardButton = widget.GetOrNull <ButtonWidget>("GUARD");

            if (guardButton != null)
            {
                WidgetUtils.BindButtonIcon(guardButton);

                guardButton.IsDisabled    = () => { UpdateStateIfNecessary(); return(guardDisabled); };
                guardButton.IsHighlighted = () => world.OrderGenerator is GuardOrderGenerator;

                Action <bool> toggle = allowCancel =>
                {
                    if (guardButton.IsHighlighted())
                    {
                        if (allowCancel)
                        {
                            world.CancelInputMode();
                        }
                    }
                    else
                    {
                        world.OrderGenerator = new GuardOrderGenerator(selectedActors,
                                                                       "Guard", "guard", Game.Settings.Game.MouseButtonPreference.Action);
                    }
                };

                guardButton.OnClick    = () => toggle(true);
                guardButton.OnKeyPress = _ => toggle(false);
            }

            var scatterButton = widget.GetOrNull <ButtonWidget>("SCATTER");

            if (scatterButton != null)
            {
                WidgetUtils.BindButtonIcon(scatterButton);

                scatterButton.IsDisabled    = () => { UpdateStateIfNecessary(); return(scatterDisabled); };
                scatterButton.IsHighlighted = () => scatterHighlighted > 0;
                scatterButton.OnClick       = () =>
                {
                    if (highlightOnButtonPress)
                    {
                        scatterHighlighted = 2;
                    }

                    PerformKeyboardOrderOnSelection(a => new Order("Scatter", a, false));
                };

                scatterButton.OnKeyPress = ki => { scatterHighlighted = 2; scatterButton.OnClick(); };
            }

            var deployButton = widget.GetOrNull <ButtonWidget>("DEPLOY");

            if (deployButton != null)
            {
                WidgetUtils.BindButtonIcon(deployButton);

                deployButton.IsDisabled = () =>
                {
                    UpdateStateIfNecessary();

                    var queued = Game.GetModifierKeys().HasModifier(Modifiers.Shift);
                    return(!selectedDeploys.Any(pair => pair.Trait.CanIssueDeployOrder(pair.Actor, queued)));
                };

                deployButton.IsHighlighted = () => deployHighlighted > 0;
                deployButton.OnClick       = () =>
                {
                    if (highlightOnButtonPress)
                    {
                        deployHighlighted = 2;
                    }

                    var queued = Game.GetModifierKeys().HasModifier(Modifiers.Shift);
                    PerformDeployOrderOnSelection(queued);
                };

                deployButton.OnKeyPress = ki => { deployHighlighted = 2; deployButton.OnClick(); };
            }

            var stopButton = widget.GetOrNull <ButtonWidget>("STOP");

            if (stopButton != null)
            {
                WidgetUtils.BindButtonIcon(stopButton);

                stopButton.IsDisabled    = () => { UpdateStateIfNecessary(); return(stopDisabled); };
                stopButton.IsHighlighted = () => stopHighlighted > 0;
                stopButton.OnClick       = () =>
                {
                    if (highlightOnButtonPress)
                    {
                        stopHighlighted = 2;
                    }

                    PerformKeyboardOrderOnSelection(a => new Order("Stop", a, false));
                };

                stopButton.OnKeyPress = ki => { stopHighlighted = 2; stopButton.OnClick(); };
            }

            var queueOrdersButton = widget.GetOrNull <ButtonWidget>("QUEUE_ORDERS");

            if (queueOrdersButton != null)
            {
                WidgetUtils.BindButtonIcon(queueOrdersButton);

                queueOrdersButton.IsDisabled    = () => { UpdateStateIfNecessary(); return(waypointModeDisabled); };
                queueOrdersButton.IsHighlighted = () => !queueOrdersButton.IsDisabled() && IsForceModifiersActive(Modifiers.Shift);
                queueOrdersButton.OnClick       = () =>
                {
                    if (queueOrdersButton.IsHighlighted())
                    {
                        world.CancelInputMode();
                    }
                    else
                    {
                        world.OrderGenerator = new ForceModifiersOrderGenerator(Modifiers.Shift, false);
                    }
                };
            }

            var keyOverrides = widget.GetOrNull <LogicKeyListenerWidget>("MODIFIER_OVERRIDES");

            if (keyOverrides != null)
            {
                var noShiftButtons = new[] { guardButton, deployButton, attackMoveButton };
                var keyUpButtons   = new[] { guardButton, attackMoveButton };
                keyOverrides.AddHandler(e =>
                {
                    // HACK: allow command buttons to be triggered if the shift (queue order modifier) key is held
                    if (e.Modifiers.HasModifier(Modifiers.Shift))
                    {
                        var eNoShift        = e;
                        eNoShift.Modifiers &= ~Modifiers.Shift;

                        foreach (var b in noShiftButtons)
                        {
                            // Button is not used by this mod
                            if (b == null)
                            {
                                continue;
                            }

                            // Button is not valid for this event
                            if (b.IsDisabled() || !b.Key.IsActivatedBy(eNoShift))
                            {
                                continue;
                            }

                            // Event is not valid for this button
                            if (!(b.DisableKeyRepeat ^ e.IsRepeat) || (e.Event == KeyInputEvent.Up && !keyUpButtons.Contains(b)))
                            {
                                continue;
                            }

                            b.OnKeyPress(e);
                            return(true);
                        }
                    }

                    // HACK: Attack move can be triggered if the ctrl (assault move modifier)
                    // or shift (queue order modifier) keys are pressed, on both key down and key up
                    var eNoMods        = e;
                    eNoMods.Modifiers &= ~(Modifiers.Ctrl | Modifiers.Shift);

                    if (attackMoveButton != null && !attackMoveDisabled && attackMoveButton.Key.IsActivatedBy(eNoMods))
                    {
                        attackMoveButton.OnKeyPress(e);
                        return(true);
                    }

                    return(false);
                });
            }
        }
Пример #23
0
 public SupportPowerDecision(MiniYaml yaml)
 {
     FieldLoader.Load(this, yaml);
 }
Пример #24
0
 static object LoadActorList(MiniYaml y, string field)
 {
     return(y.NodesDict[field].Nodes.ToDictionary(
                t => t.Key,
                t => FieldLoader.GetValue <float>(field, t.Value.Value)));
 }
Пример #25
0
        public AssetBrowserLogic(Widget widget, Action onExit, ModData modData, World world, Dictionary <string, MiniYaml> logicArgs)
        {
            this.world   = world;
            this.modData = modData;
            panel        = widget;

            var ticker = panel.GetOrNull <LogicTickerWidget>("ANIMATION_TICKER");

            if (ticker != null)
            {
                ticker.OnTick = () =>
                {
                    if (animateFrames)
                    {
                        SelectNextFrame();
                    }
                };
            }

            var sourceDropdown = panel.GetOrNull <DropDownButtonWidget>("SOURCE_SELECTOR");

            if (sourceDropdown != null)
            {
                sourceDropdown.OnMouseDown = _ => ShowSourceDropdown(sourceDropdown);
                sourceDropdown.GetText     = () =>
                {
                    var name = assetSource != null?Platform.UnresolvePath(assetSource.Name) : "All Packages";

                    if (name.Length > 15)
                    {
                        name = "..." + name.Substring(name.Length - 15);
                    }

                    return(name);
                };
            }

            var spriteWidget = panel.GetOrNull <SpriteWidget>("SPRITE");

            if (spriteWidget != null)
            {
                spriteWidget.GetSprite  = () => currentSprites != null ? currentSprites[currentFrame] : null;
                currentPalette          = spriteWidget.Palette;
                spriteWidget.GetPalette = () => currentPalette;
                spriteWidget.IsVisible  = () => !isVideoLoaded && !IsErrorLabelVisible;
            }

            var playerWidget = panel.GetOrNull <VqaPlayerWidget>("PLAYER");

            if (playerWidget != null)
            {
                playerWidget.IsVisible = () => isVideoLoaded && !IsErrorLabelVisible;
            }

            errorLabelWidget = panel.GetOrNull <LabelWidget>("ERROR");
            if (errorLabelWidget != null)
            {
                errorFont = Game.Renderer.Fonts[errorLabelWidget.Font];
            }

            var paletteDropDown = panel.GetOrNull <DropDownButtonWidget>("PALETTE_SELECTOR");

            if (paletteDropDown != null)
            {
                paletteDropDown.OnMouseDown = _ => ShowPaletteDropdown(paletteDropDown, world);
                paletteDropDown.GetText     = () => currentPalette;
            }

            var colorPreview = panel.GetOrNull <ColorPreviewManagerWidget>("COLOR_MANAGER");

            if (colorPreview != null)
            {
                colorPreview.Color = Game.Settings.Player.Color;
            }

            var colorDropdown = panel.GetOrNull <DropDownButtonWidget>("COLOR");

            if (colorDropdown != null)
            {
                colorDropdown.IsDisabled  = () => currentPalette != colorPreview.PaletteName;
                colorDropdown.OnMouseDown = _ => ColorPickerLogic.ShowColorDropDown(colorDropdown, colorPreview, world);
                panel.Get <ColorBlockWidget>("COLORBLOCK").GetColor = () => Game.Settings.Player.Color.RGB;
            }

            filenameInput = panel.Get <TextFieldWidget>("FILENAME_INPUT");
            filenameInput.OnTextEdited = () => ApplyFilter(filenameInput.Text);
            filenameInput.OnEscKey     = filenameInput.YieldKeyboardFocus;

            var frameContainer = panel.GetOrNull("FRAME_SELECTOR");

            if (frameContainer != null)
            {
                frameContainer.IsVisible = () => (currentSprites != null && currentSprites.Length > 1) ||
                                           (isVideoLoaded && player != null && player.Video != null && player.Video.Frames > 1);
            }

            frameSlider = panel.Get <SliderWidget>("FRAME_SLIDER");
            if (frameSlider != null)
            {
                frameSlider.OnChange += x =>
                {
                    if (!isVideoLoaded)
                    {
                        currentFrame = (int)Math.Round(x);
                    }
                };

                frameSlider.GetValue   = () => isVideoLoaded ? player.Video.CurrentFrame : currentFrame;
                frameSlider.IsDisabled = () => isVideoLoaded;
            }

            var frameText = panel.GetOrNull <LabelWidget>("FRAME_COUNT");

            if (frameText != null)
            {
                frameText.GetText = () =>
                                    isVideoLoaded ?
                                    "{0} / {1}".F(player.Video.CurrentFrame + 1, player.Video.Frames) :
                                    "{0} / {1}".F(currentFrame, currentSprites.Length - 1);
            }

            var playButton = panel.GetOrNull <ButtonWidget>("BUTTON_PLAY");

            if (playButton != null)
            {
                playButton.Key     = new Hotkey(Keycode.SPACE, Modifiers.None);
                playButton.OnClick = () =>
                {
                    if (isVideoLoaded)
                    {
                        player.Play();
                    }
                    else
                    {
                        animateFrames = true;
                    }
                };

                playButton.IsVisible = () => isVideoLoaded ? player.Paused : !animateFrames;
            }

            var pauseButton = panel.GetOrNull <ButtonWidget>("BUTTON_PAUSE");

            if (pauseButton != null)
            {
                pauseButton.Key     = new Hotkey(Keycode.SPACE, Modifiers.None);
                pauseButton.OnClick = () =>
                {
                    if (isVideoLoaded)
                    {
                        player.Pause();
                    }
                    else
                    {
                        animateFrames = false;
                    }
                };

                pauseButton.IsVisible = () => isVideoLoaded ? !player.Paused : animateFrames;
            }

            var stopButton = panel.GetOrNull <ButtonWidget>("BUTTON_STOP");

            if (stopButton != null)
            {
                stopButton.Key     = new Hotkey(Keycode.RETURN, Modifiers.None);
                stopButton.OnClick = () =>
                {
                    if (isVideoLoaded)
                    {
                        player.Stop();
                    }
                    else
                    {
                        frameSlider.Value = 0;
                        currentFrame      = 0;
                        animateFrames     = false;
                    }
                };
            }

            var nextButton = panel.GetOrNull <ButtonWidget>("BUTTON_NEXT");

            if (nextButton != null)
            {
                nextButton.Key     = new Hotkey(Keycode.RIGHT, Modifiers.None);
                nextButton.OnClick = () =>
                {
                    if (!isVideoLoaded)
                    {
                        nextButton.OnClick = SelectNextFrame;
                    }
                };

                nextButton.IsVisible = () => !isVideoLoaded;
            }

            var prevButton = panel.GetOrNull <ButtonWidget>("BUTTON_PREV");

            if (prevButton != null)
            {
                prevButton.Key     = new Hotkey(Keycode.LEFT, Modifiers.None);
                prevButton.OnClick = () =>
                {
                    if (!isVideoLoaded)
                    {
                        SelectPreviousFrame();
                    }
                };

                prevButton.IsVisible = () => !isVideoLoaded;
            }

            if (logicArgs.ContainsKey("SupportedFormats"))
            {
                allowedExtensions = FieldLoader.GetValue <string[]>("SupportedFormats", logicArgs["SupportedFormats"].Value);
            }
            else
            {
                allowedExtensions = new string[0];
            }

            acceptablePackages = modData.ModFiles.MountedPackages.Where(p =>
                                                                        p.Contents.Any(c => allowedExtensions.Contains(Path.GetExtension(c).ToLowerInvariant())));

            assetList = panel.Get <ScrollPanelWidget>("ASSET_LIST");
            template  = panel.Get <ScrollItemWidget>("ASSET_TEMPLATE");
            PopulateAssetList();

            var closeButton = panel.GetOrNull <ButtonWidget>("CLOSE_BUTTON");

            if (closeButton != null)
            {
                closeButton.OnClick = () =>
                {
                    if (isVideoLoaded)
                    {
                        player.Stop();
                    }
                    Ui.CloseWindow();
                    onExit();
                }
            }
            ;
        }

        void SelectNextFrame()
        {
            currentFrame++;
            if (currentFrame >= currentSprites.Length)
            {
                currentFrame = 0;
            }
        }

        void SelectPreviousFrame()
        {
            currentFrame--;
            if (currentFrame < 0)
            {
                currentFrame = currentSprites.Length - 1;
            }
        }

        Dictionary <string, bool> assetVisByName = new Dictionary <string, bool>();

        bool FilterAsset(string filename)
        {
            var filter = filenameInput.Text;

            if (string.IsNullOrWhiteSpace(filter))
            {
                return(true);
            }

            if (filename.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0)
            {
                return(true);
            }

            return(false);
        }

        void ApplyFilter(string filename)
        {
            assetVisByName.Clear();
            assetList.Layout.AdjustChildren();
            assetList.ScrollToTop();

            // Select the first visible
            var firstVisible = assetVisByName.FirstOrDefault(kvp => kvp.Value);

            if (firstVisible.Key != null)
            {
                LoadAsset(firstVisible.Key);
            }
        }

        void AddAsset(ScrollPanelWidget list, string filepath, ScrollItemWidget template)
        {
            var filename = Path.GetFileName(filepath);
            var item     = ScrollItemWidget.Setup(template,
                                                  () => currentFilename == filename,
                                                  () => { LoadAsset(filename); });

            item.Get <LabelWidget>("TITLE").GetText = () => filepath;
            item.IsVisible = () =>
            {
                bool visible;
                if (assetVisByName.TryGetValue(filepath, out visible))
                {
                    return(visible);
                }

                visible = FilterAsset(filepath);
                assetVisByName.Add(filepath, visible);
                return(visible);
            };

            list.AddChild(item);
        }

        bool LoadAsset(string filename)
        {
            if (isVideoLoaded)
            {
                player.Stop();
                player        = null;
                isVideoLoaded = false;
            }

            if (string.IsNullOrEmpty(filename))
            {
                return(false);
            }

            if (!modData.DefaultFileSystem.Exists(filename))
            {
                return(false);
            }

            errorLabelWidget.Visible = false;

            try
            {
                if (Path.GetExtension(filename.ToLowerInvariant()) == ".vqa")
                {
                    player          = panel.Get <VqaPlayerWidget>("PLAYER");
                    currentFilename = filename;
                    player.Load(filename);
                    player.DrawOverlay       = false;
                    isVideoLoaded            = true;
                    frameSlider.MaximumValue = (float)player.Video.Frames - 1;
                    frameSlider.Ticks        = 0;
                    return(true);
                }

                currentFilename          = filename;
                currentSprites           = world.Map.Rules.Sequences.SpriteCache[filename];
                currentFrame             = 0;
                frameSlider.MaximumValue = (float)currentSprites.Length - 1;
                frameSlider.Ticks        = currentSprites.Length;
            }
            catch (Exception ex)
            {
                if (errorLabelWidget != null)
                {
                    errorLabelWidget.Text = WidgetUtils.TruncateText(errorLabelWidget.Text.Replace("{filename}", filename),
                                                                     errorLabelWidget.Bounds.Width, errorFont);

                    currentSprites           = new Sprite[0];
                    errorLabelWidget.Visible = true;
                }

                Log.AddChannel("assetbrowser", "assetbrowser.log");
                Log.Write("assetbrowser", "Error reading {0}:{3} {1}{3}{2}", filename, ex.Message, ex.StackTrace, Environment.NewLine);

                return(false);
            }

            return(true);
        }

        bool ShowSourceDropdown(DropDownButtonWidget dropdown)
        {
            Func <IReadOnlyPackage, ScrollItemWidget, ScrollItemWidget> setupItem = (source, itemTemplate) =>
            {
                var item = ScrollItemWidget.Setup(itemTemplate,
                                                  () => assetSource == source,
                                                  () => { assetSource = source; PopulateAssetList(); });
                item.Get <LabelWidget>("LABEL").GetText = () => source != null?Platform.UnresolvePath(source.Name) : "All Packages";

                return(item);
            };

            var sources = new[] { (IReadOnlyPackage)null }.Concat(acceptablePackages);

            dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 280, sources, setupItem);
            return(true);
        }

        void PopulateAssetList()
        {
            assetList.RemoveChildren();
            availableShps.Clear();

            var files = assetSource != null ? assetSource.Contents : modData.ModFiles.MountedPackages.SelectMany(f => f.Contents).Distinct();

            foreach (var file in files.OrderBy(s => s))
            {
                if (allowedExtensions.Any(ext => file.EndsWith(ext, true, CultureInfo.InvariantCulture)))
                {
                    AddAsset(assetList, file, template);
                    availableShps.Add(file);
                }
            }
        }

        bool ShowPaletteDropdown(DropDownButtonWidget dropdown, World world)
        {
            Func <string, ScrollItemWidget, ScrollItemWidget> setupItem = (name, itemTemplate) =>
            {
                var item = ScrollItemWidget.Setup(itemTemplate,
                                                  () => currentPalette == name,
                                                  () => currentPalette = name);
                item.Get <LabelWidget>("LABEL").GetText = () => name;

                return(item);
            };

            var palettes = world.WorldActor.TraitsImplementing <IProvidesAssetBrowserPalettes>()
                           .SelectMany(p => p.PaletteNames);

            dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 280, palettes, setupItem);
            return(true);
        }
    }
Пример #26
0
        internal static void ProcessOrder(OrderManager orderManager, World world, int clientId, Order order)
        {
            switch (order.OrderString)
            {
            // Server message
            case "Message":
                TextNotificationsManager.AddSystemLine(order.TargetString);
                break;

            // Client side translated server message
            case "LocalizedMessage":
            {
                if (string.IsNullOrEmpty(order.TargetString))
                {
                    break;
                }

                var yaml = MiniYaml.FromString(order.TargetString);
                foreach (var node in yaml)
                {
                    var localizedMessage = new LocalizedMessage(node.Value);
                    TextNotificationsManager.AddSystemLine(localizedMessage.Translate(Game.ModData));
                }

                break;
            }

            case "DisableChatEntry":
            {
                // Order must originate from the server
                if (clientId != 0)
                {
                    break;
                }

                // Server may send MaxValue to indicate that it is disabled until further notice
                if (order.ExtraData == uint.MaxValue)
                {
                    TextNotificationsManager.ChatDisabledUntil = uint.MaxValue;
                }
                else
                {
                    TextNotificationsManager.ChatDisabledUntil = Game.RunTime + order.ExtraData;
                }

                break;
            }

            case "Chat":
            {
                var client = orderManager.LobbyInfo.ClientWithIndex(clientId);
                if (client == null)
                {
                    break;
                }

                // Cut chat messages to the hard limit to avoid exploits
                var message = order.TargetString;
                if (message.Length > ChatMessageMaxLength)
                {
                    message = order.TargetString.Substring(0, ChatMessageMaxLength);
                }

                // ExtraData 0 means this is a normal chat order, everything else is team chat
                if (order.ExtraData == 0)
                {
                    var p      = world?.FindPlayerByClient(client);
                    var suffix = (p != null && p.WinState == WinState.Lost) ? " (Dead)" : "";
                    suffix = client.IsObserver ? " (Spectator)" : suffix;

                    if (orderManager.LocalClient != null && client != orderManager.LocalClient && client.Team > 0 && client.Team == orderManager.LocalClient.Team)
                    {
                        suffix += " (Ally)";
                    }

                    TextNotificationsManager.AddChatLine(client.Name + suffix, message, client.Color);
                    break;
                }

                // We are still in the lobby
                if (world == null)
                {
                    var prefix = order.ExtraData == uint.MaxValue ? "[Spectators] " : "[Team] ";
                    if (orderManager.LocalClient != null && client.Team == orderManager.LocalClient.Team)
                    {
                        TextNotificationsManager.AddChatLine(prefix + client.Name, message, client.Color);
                    }

                    break;
                }

                var player = world.FindPlayerByClient(client);
                var localClientIsObserver = world.IsReplay || (orderManager.LocalClient != null && orderManager.LocalClient.IsObserver) ||
                                            (world.LocalPlayer != null && world.LocalPlayer.WinState != WinState.Undefined);

                // ExtraData gives us the team number, uint.MaxValue means Spectators
                if (order.ExtraData == uint.MaxValue && localClientIsObserver)
                {
                    // Validate before adding the line
                    if (client.IsObserver || (player != null && player.WinState != WinState.Undefined))
                    {
                        TextNotificationsManager.AddChatLine("[Spectators] " + client.Name, message, client.Color);
                    }

                    break;
                }

                var valid      = client.Team == order.ExtraData && player != null && player.WinState == WinState.Undefined;
                var isSameTeam = orderManager.LocalClient != null && order.ExtraData == orderManager.LocalClient.Team &&
                                 world.LocalPlayer != null && world.LocalPlayer.WinState == WinState.Undefined;

                if (valid && (isSameTeam || world.IsReplay))
                {
                    TextNotificationsManager.AddChatLine("[Team" + (world.IsReplay ? " " + order.ExtraData : "") + "] " + client.Name, message, client.Color);
                }

                break;
            }

            case "StartGame":
            {
                if (Game.ModData.MapCache[orderManager.LobbyInfo.GlobalSettings.Map].Status != MapStatus.Available)
                {
                    Game.Disconnect();
                    Game.LoadShellMap();

                    // TODO: After adding a startup error dialog, notify the replay load failure.
                    break;
                }

                if (!string.IsNullOrEmpty(order.TargetString))
                {
                    var data = MiniYaml.FromString(order.TargetString);
                    var saveLastOrdersFrame = data.FirstOrDefault(n => n.Key == "SaveLastOrdersFrame");
                    if (saveLastOrdersFrame != null)
                    {
                        orderManager.GameSaveLastFrame =
                            FieldLoader.GetValue <int>("saveLastOrdersFrame", saveLastOrdersFrame.Value.Value);
                    }

                    var saveSyncFrame = data.FirstOrDefault(n => n.Key == "SaveSyncFrame");
                    if (saveSyncFrame != null)
                    {
                        orderManager.GameSaveLastSyncFrame =
                            FieldLoader.GetValue <int>("SaveSyncFrame", saveSyncFrame.Value.Value);
                    }
                }
                else
                {
                    TextNotificationsManager.AddSystemLine("The game has started.");
                }

                Game.StartGame(orderManager.LobbyInfo.GlobalSettings.Map, WorldType.Regular);
                break;
            }

            case "SaveTraitData":
            {
                var data       = MiniYaml.FromString(order.TargetString)[0];
                var traitIndex = int.Parse(data.Key);

                world?.AddGameSaveTraitData(traitIndex, data.Value);

                break;
            }

            case "GameSaved":
                if (!orderManager.World.IsReplay)
                {
                    TextNotificationsManager.AddSystemLine("Game saved");
                }

                foreach (var nsr in orderManager.World.WorldActor.TraitsImplementing <INotifyGameSaved>())
                {
                    nsr.GameSaved(orderManager.World);
                }
                break;

            case "PauseGame":
            {
                var client = orderManager.LobbyInfo.ClientWithIndex(clientId);
                if (client != null)
                {
                    var pause = order.TargetString == "Pause";

                    // Prevent injected unpause orders from restarting a finished game
                    if (orderManager.World.PauseStateLocked && !pause)
                    {
                        break;
                    }

                    if (orderManager.World.Paused != pause && world != null && world.LobbyInfo.NonBotClients.Count() > 1)
                    {
                        var pausetext = $"The game is {(pause ? "paused" : "un-paused")} by {client.Name}";
                        TextNotificationsManager.AddSystemLine(pausetext);
                    }

                    orderManager.World.Paused          = pause;
                    orderManager.World.PredictedPaused = pause;
                }

                break;
            }

            case "HandshakeRequest":
            {
                // Switch to the server's mod if we need and are able to
                var mod     = Game.ModData.Manifest;
                var request = HandshakeRequest.Deserialize(order.TargetString);

                var externalKey = ExternalMod.MakeKey(request.Mod, request.Version);
                if ((request.Mod != mod.Id || request.Version != mod.Metadata.Version) &&
                    Game.ExternalMods.TryGetValue(externalKey, out var external))
                {
                    // The ConnectionFailedLogic will prompt the user to switch mods
                    CurrentServerSettings.ServerExternalMod = external;
                    orderManager.Connection.Dispose();
                    break;
                }

                Game.Settings.Player.Name = Settings.SanitizedPlayerName(Game.Settings.Player.Name);
                Game.Settings.Save();

                // Otherwise send the handshake with our current settings and let the server reject us
                var info = new Session.Client()
                {
                    Name           = Game.Settings.Player.Name,
                    PreferredColor = Game.Settings.Player.Color,
                    Color          = Game.Settings.Player.Color,
                    Faction        = "Random",
                    SpawnPoint     = 0,
                    Team           = 0,
                    State          = Session.ClientState.Invalid
                };

                var localProfile = Game.LocalPlayerProfile;
                var response     = new HandshakeResponse()
                {
                    Client         = info,
                    Mod            = mod.Id,
                    Version        = mod.Metadata.Version,
                    Password       = CurrentServerSettings.Password,
                    Fingerprint    = localProfile.Fingerprint,
                    OrdersProtocol = ProtocolVersion.Orders
                };

                if (request.AuthToken != null && response.Fingerprint != null)
                {
                    response.AuthSignature = localProfile.Sign(request.AuthToken);
                }

                orderManager.IssueOrder(new Order("HandshakeResponse", null, false)
                    {
                        Type         = OrderType.Handshake,
                        IsImmediate  = true,
                        TargetString = response.Serialize()
                    });

                break;
            }

            case "ServerError":
            {
                orderManager.ServerError          = order.TargetString;
                orderManager.AuthenticationFailed = false;
                break;
            }

            case "AuthenticationError":
            {
                // The ConnectionFailedLogic will prompt the user for the password
                orderManager.ServerError          = order.TargetString;
                orderManager.AuthenticationFailed = true;
                break;
            }

            case "SyncInfo":
            {
                orderManager.LobbyInfo = Session.Deserialize(order.TargetString);
                Game.SyncLobbyInfo();
                break;
            }

            case "SyncLobbyClients":
            {
                var clients = new List <Session.Client>();
                var nodes   = MiniYaml.FromString(order.TargetString);
                foreach (var node in nodes)
                {
                    var strings = node.Key.Split('@');
                    if (strings[0] == "Client")
                    {
                        clients.Add(Session.Client.Deserialize(node.Value));
                    }
                }

                orderManager.LobbyInfo.Clients = clients;
                Game.SyncLobbyInfo();
                break;
            }

            case "SyncLobbySlots":
            {
                var slots = new Dictionary <string, Session.Slot>();
                var nodes = MiniYaml.FromString(order.TargetString);
                foreach (var node in nodes)
                {
                    var strings = node.Key.Split('@');
                    if (strings[0] == "Slot")
                    {
                        var slot = Session.Slot.Deserialize(node.Value);
                        slots.Add(slot.PlayerReference, slot);
                    }
                }

                orderManager.LobbyInfo.Slots = slots;
                Game.SyncLobbyInfo();
                break;
            }

            case "SyncLobbyGlobalSettings":
            {
                var nodes = MiniYaml.FromString(order.TargetString);
                foreach (var node in nodes)
                {
                    var strings = node.Key.Split('@');
                    if (strings[0] == "GlobalSettings")
                    {
                        orderManager.LobbyInfo.GlobalSettings = Session.Global.Deserialize(node.Value);
                    }
                }

                Game.SyncLobbyInfo();
                break;
            }

            case "SyncConnectionQuality":
            {
                var nodes = MiniYaml.FromString(order.TargetString);
                foreach (var node in nodes)
                {
                    var strings = node.Key.Split('@');
                    if (strings[0] == "ConnectionQuality")
                    {
                        var client = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.Index == int.Parse(strings[1]));
                        if (client != null)
                        {
                            client.ConnectionQuality = FieldLoader.GetValue <Session.ConnectionQuality>("ConnectionQuality", node.Value.Value);
                        }
                    }
                }

                break;
            }

            default:
            {
                if (world == null)
                {
                    break;
                }

                if (order.GroupedActors == null)
                {
                    ResolveOrder(order, world, orderManager, clientId);
                }
                else
                {
                    foreach (var subject in order.GroupedActors)
                    {
                        ResolveOrder(Order.FromGroupedOrder(order, subject), world, orderManager, clientId);
                    }
                }

                break;
            }
            }
        }
Пример #27
0
        public bool InterpretCommand(S server, Connection conn, Session.Client client, string cmd)
        {
            if (server == null || conn == null || client == null || !ValidateCommand(server, conn, client, cmd))
            {
                return(false);
            }

            var dict = new Dictionary <string, Func <string, bool> >
            {
                { "state",
                  s =>
                  {
                      var state = Session.ClientState.Invalid;
                      if (!Enum <Session.ClientState> .TryParse(s, false, out state))
                      {
                          server.SendOrderTo(conn, "Message", "Malformed state command");
                          return(true);
                      }

                      client.State = state;

                      Log.Write("server", "Player @{0} is {1}",
                                conn.Socket.RemoteEndPoint, client.State);

                      server.SyncLobbyClients();

                      CheckAutoStart(server);

                      return(true);
                  } },
                { "startgame",
                  s =>
                  {
                      if (!client.IsAdmin)
                      {
                          server.SendOrderTo(conn, "Message", "Only the host can start the game.");
                          return(true);
                      }

                      if (server.LobbyInfo.Slots.Any(sl => sl.Value.Required &&
                                                     server.LobbyInfo.ClientInSlot(sl.Key) == null))
                      {
                          server.SendOrderTo(conn, "Message", "Unable to start the game until required slots are full.");
                          return(true);
                      }

                      if (!server.LobbyInfo.GlobalSettings.EnableSingleplayer &&
                          server.LobbyInfo.Clients.Where(c => c.Bot == null && c.Slot != null).Count() == 1)
                      {
                          server.SendOrderTo(conn, "Message", server.TwoHumansRequiredText);
                          return(true);
                      }

                      server.StartGame();
                      return(true);
                  } },
                { "slot",
                  s =>
                  {
                      if (!server.LobbyInfo.Slots.ContainsKey(s))
                      {
                          Log.Write("server", "Invalid slot: {0}", s);
                          return(false);
                      }

                      var slot = server.LobbyInfo.Slots[s];

                      if (slot.Closed || server.LobbyInfo.ClientInSlot(s) != null)
                      {
                          return(false);
                      }

                      // If the previous slot had a locked spawn then we must not carry that to the new slot
                      var oldSlot = client.Slot != null ? server.LobbyInfo.Slots[client.Slot] : null;
                      if (oldSlot != null && oldSlot.LockSpawn)
                      {
                          client.SpawnPoint = 0;
                      }

                      client.Slot = s;
                      S.SyncClientToPlayerReference(client, server.Map.Players.Players[s]);

                      if (!slot.LockColor)
                      {
                          client.PreferredColor = client.Color = SanitizePlayerColor(server, client.Color, client.Index, conn);
                      }

                      server.SyncLobbyClients();
                      CheckAutoStart(server);

                      return(true);
                  } },
                { "allow_spectators",
                  s =>
                  {
                      if (bool.TryParse(s, out server.LobbyInfo.GlobalSettings.AllowSpectators))
                      {
                          server.SyncLobbyGlobalSettings();
                          return(true);
                      }
                      else
                      {
                          server.SendOrderTo(conn, "Message", "Malformed allow_spectate command");
                          return(true);
                      }
                  } },
                { "spectate",
                  s =>
                  {
                      if (server.LobbyInfo.GlobalSettings.AllowSpectators || client.IsAdmin)
                      {
                          client.Slot       = null;
                          client.SpawnPoint = 0;
                          client.Color      = HSLColor.FromRGB(255, 255, 255);
                          server.SyncLobbyClients();
                          CheckAutoStart(server);
                          return(true);
                      }
                      else
                      {
                          return(false);
                      }
                  } },
                { "slot_close",
                  s =>
                  {
                      if (!ValidateSlotCommand(server, conn, client, s, true))
                      {
                          return(false);
                      }

                      // kick any player that's in the slot
                      var occupant = server.LobbyInfo.ClientInSlot(s);
                      if (occupant != null)
                      {
                          if (occupant.Bot != null)
                          {
                              server.LobbyInfo.Clients.Remove(occupant);
                              server.SyncLobbyClients();
                              var ping = server.LobbyInfo.PingFromClient(occupant);
                              if (ping != null)
                              {
                                  server.LobbyInfo.ClientPings.Remove(ping);
                                  server.SyncClientPing();
                              }
                          }
                          else
                          {
                              var occupantConn = server.Conns.FirstOrDefault(c => c.PlayerIndex == occupant.Index);
                              if (occupantConn != null)
                              {
                                  server.SendOrderTo(occupantConn, "ServerError", "Your slot was closed by the host.");
                                  server.DropClient(occupantConn);
                              }
                          }
                      }

                      server.LobbyInfo.Slots[s].Closed = true;
                      server.SyncLobbySlots();
                      return(true);
                  } },
                { "slot_open",
                  s =>
                  {
                      if (!ValidateSlotCommand(server, conn, client, s, true))
                      {
                          return(false);
                      }

                      var slot = server.LobbyInfo.Slots[s];
                      slot.Closed = false;
                      server.SyncLobbySlots();

                      // Slot may have a bot in it
                      var occupant = server.LobbyInfo.ClientInSlot(s);
                      if (occupant != null && occupant.Bot != null)
                      {
                          server.LobbyInfo.Clients.Remove(occupant);
                          var ping = server.LobbyInfo.PingFromClient(occupant);
                          if (ping != null)
                          {
                              server.LobbyInfo.ClientPings.Remove(ping);
                              server.SyncClientPing();
                          }
                      }

                      server.SyncLobbyClients();
                      return(true);
                  } },
                { "slot_bot",
                  s =>
                  {
                      var parts = s.Split(' ');

                      if (parts.Length < 3)
                      {
                          server.SendOrderTo(conn, "Message", "Malformed slot_bot command");
                          return(true);
                      }

                      if (!ValidateSlotCommand(server, conn, client, parts[0], true))
                      {
                          return(false);
                      }

                      var slot = server.LobbyInfo.Slots[parts[0]];
                      var bot  = server.LobbyInfo.ClientInSlot(parts[0]);
                      int controllerClientIndex;
                      if (!Exts.TryParseIntegerInvariant(parts[1], out controllerClientIndex))
                      {
                          Log.Write("server", "Invalid bot controller client index: {0}", parts[1]);
                          return(false);
                      }

                      var botType = parts.Skip(2).JoinWith(" ");

                      // Invalid slot
                      if (bot != null && bot.Bot == null)
                      {
                          server.SendOrderTo(conn, "Message", "Can't add bots to a slot with another client.");
                          return(true);
                      }

                      slot.Closed = false;
                      if (bot == null)
                      {
                          // Create a new bot
                          bot = new Session.Client()
                          {
                              Index      = server.ChooseFreePlayerIndex(),
                              Name       = botType,
                              Bot        = botType,
                              Slot       = parts[0],
                              Faction    = "Random",
                              SpawnPoint = 0,
                              Team       = 0,
                              State      = Session.ClientState.NotReady,
                              BotControllerClientIndex = controllerClientIndex
                          };

                          // Pick a random color for the bot
                          var validator     = server.ModData.Manifest.Get <ColorValidator>();
                          var tileset       = server.Map.Rules.TileSet;
                          var terrainColors = tileset.TerrainInfo.Where(ti => ti.RestrictPlayerColor).Select(ti => ti.Color);
                          var playerColors  = server.LobbyInfo.Clients.Select(c => c.Color.RGB)
                                              .Concat(server.Map.Players.Players.Values.Select(p => p.Color.RGB));
                          bot.Color = bot.PreferredColor = validator.RandomValidColor(server.Random, terrainColors, playerColors);

                          server.LobbyInfo.Clients.Add(bot);
                      }
                      else
                      {
                          // Change the type of the existing bot
                          bot.Name = botType;
                          bot.Bot  = botType;
                      }

                      S.SyncClientToPlayerReference(bot, server.Map.Players.Players[parts[0]]);
                      server.SyncLobbyClients();
                      server.SyncLobbySlots();
                      return(true);
                  } },
                { "map",
                  s =>
                  {
                      if (!client.IsAdmin)
                      {
                          server.SendOrderTo(conn, "Message", "Only the host can change the map.");
                          return(true);
                      }

                      var lastMap = server.LobbyInfo.GlobalSettings.Map;
                      Action <MapPreview> selectMap = map =>
                      {
                          // Make sure the map hasn't changed in the meantime
                          if (server.LobbyInfo.GlobalSettings.Map != lastMap)
                          {
                              return;
                          }

                          server.LobbyInfo.GlobalSettings.Map = map.Uid;

                          var oldSlots = server.LobbyInfo.Slots.Keys.ToArray();
                          server.Map = server.ModData.MapCache[server.LobbyInfo.GlobalSettings.Map];

                          server.LobbyInfo.Slots = server.Map.Players.Players
                                                   .Select(p => MakeSlotFromPlayerReference(p.Value))
                                                   .Where(ss => ss != null)
                                                   .ToDictionary(ss => ss.PlayerReference, ss => ss);

                          LoadMapSettings(server, server.LobbyInfo.GlobalSettings, server.Map.Rules);

                          // Reset client states
                          foreach (var c in server.LobbyInfo.Clients)
                          {
                              c.State = Session.ClientState.Invalid;
                          }

                          // Reassign players into new slots based on their old slots:
                          //  - Observers remain as observers
                          //  - Players who now lack a slot are made observers
                          //  - Bots who now lack a slot are dropped
                          //  - Bots who are not defined in the map rules are dropped
                          var botNames = server.Map.Rules.Actors["player"].TraitInfos <IBotInfo>().Select(t => t.Name);
                          var slots    = server.LobbyInfo.Slots.Keys.ToArray();
                          var i        = 0;
                          foreach (var os in oldSlots)
                          {
                              var c = server.LobbyInfo.ClientInSlot(os);
                              if (c == null)
                              {
                                  continue;
                              }

                              c.SpawnPoint = 0;
                              c.Slot       = i < slots.Length ? slots[i++] : null;
                              if (c.Slot != null)
                              {
                                  // Remove Bot from slot if slot forbids bots
                                  if (c.Bot != null && (!server.Map.Players.Players[c.Slot].AllowBots || !botNames.Contains(c.Bot)))
                                  {
                                      server.LobbyInfo.Clients.Remove(c);
                                  }
                                  S.SyncClientToPlayerReference(c, server.Map.Players.Players[c.Slot]);
                              }
                              else if (c.Bot != null)
                              {
                                  server.LobbyInfo.Clients.Remove(c);
                              }
                          }

                          // Validate if color is allowed and get an alternative if it isn't
                          foreach (var c in server.LobbyInfo.Clients)
                          {
                              if (c.Slot == null || (c.Slot != null && !server.LobbyInfo.Slots[c.Slot].LockColor))
                              {
                                  c.Color = c.PreferredColor = SanitizePlayerColor(server, c.Color, c.Index, conn);
                              }
                          }

                          server.SyncLobbyInfo();

                          server.SendMessage("{0} changed the map to {1}.".F(client.Name, server.Map.Title));

                          if (server.Map.DefinesUnsafeCustomRules)
                          {
                              server.SendMessage("This map contains custom rules. Game experience may change.");
                          }

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

                          var briefing = MissionBriefingOrDefault(server);
                          if (briefing != null)
                          {
                              server.SendMessage(briefing);
                          }
                      };

                      Action queryFailed = () =>
                                           server.SendOrderTo(conn, "Message", "Map was not found on server.");

                      var m = server.ModData.MapCache[s];
                      if (m.Status == MapStatus.Available || m.Status == MapStatus.DownloadAvailable)
                      {
                          selectMap(m);
                      }
                      else if (server.Settings.QueryMapRepository)
                      {
                          server.SendOrderTo(conn, "Message", "Searching for map on the Resource Center...");
                          server.ModData.MapCache.QueryRemoteMapDetails(new[] { s }, selectMap, queryFailed);
                      }
                      else
                      {
                          queryFailed();
                      }

                      return(true);
                  } },
                { "option",
                  s =>
                  {
                      if (!client.IsAdmin)
                      {
                          server.SendOrderTo(conn, "Message", "Only the host can change the configuration.");
                          return(true);
                      }

                      var allOptions = server.Map.Rules.Actors["player"].TraitInfos <ILobbyOptions>()
                                       .Concat(server.Map.Rules.Actors["world"].TraitInfos <ILobbyOptions>())
                                       .SelectMany(t => t.LobbyOptions(server.Map.Rules));

                      // Overwrite keys with duplicate ids
                      var options = new Dictionary <string, LobbyOption>();
                      foreach (var o in allOptions)
                      {
                          options[o.Id] = o;
                      }

                      var         split = s.Split(' ');
                      LobbyOption option;
                      if (split.Length < 2 || !options.TryGetValue(split[0], out option) ||
                          !option.Values.ContainsKey(split[1]))
                      {
                          server.SendOrderTo(conn, "Message", "Invalid configuration command.");
                          return(true);
                      }

                      if (option.Locked)
                      {
                          server.SendOrderTo(conn, "Message", "{0} cannot be changed.".F(option.Name));
                          return(true);
                      }

                      var oo = server.LobbyInfo.GlobalSettings.LobbyOptions[option.Id];
                      if (oo.Value == split[1])
                      {
                          return(true);
                      }

                      oo.Value = oo.PreferredValue = split[1];

                      if (option.Id == "gamespeed")
                      {
                          var speed = server.ModData.Manifest.Get <GameSpeeds>().Speeds[oo.Value];
                          server.LobbyInfo.GlobalSettings.Timestep     = speed.Timestep;
                          server.LobbyInfo.GlobalSettings.OrderLatency = speed.OrderLatency;
                      }

                      server.SyncLobbyGlobalSettings();
                      server.SendMessage(option.ValueChangedMessage(client.Name, split[1]));

                      return(true);
                  } },
                { "assignteams",
                  s =>
                  {
                      if (!client.IsAdmin)
                      {
                          server.SendOrderTo(conn, "Message", "Only the host can set that option.");
                          return(true);
                      }

                      int teamCount;
                      if (!Exts.TryParseIntegerInvariant(s, out teamCount))
                      {
                          server.SendOrderTo(conn, "Message", "Number of teams could not be parsed: {0}".F(s));
                          return(true);
                      }

                      var maxTeams = (server.LobbyInfo.Clients.Count(c => c.Slot != null) + 1) / 2;
                      teamCount = teamCount.Clamp(0, maxTeams);
                      var clients = server.LobbyInfo.Slots
                                    .Select(slot => server.LobbyInfo.ClientInSlot(slot.Key))
                                    .Where(c => c != null && !server.LobbyInfo.Slots[c.Slot].LockTeam);

                      var assigned    = 0;
                      var clientCount = clients.Count();
                      foreach (var player in clients)
                      {
                          // Free for all
                          if (teamCount == 0)
                          {
                              player.Team = 0;
                          }

                          // Humans vs Bots
                          else if (teamCount == 1)
                          {
                              player.Team = player.Bot == null ? 1 : 2;
                          }
                          else
                          {
                              player.Team = assigned++ *teamCount / clientCount + 1;
                          }
                      }

                      server.SyncLobbyClients();
                      return(true);
                  } },
                { "kick",
                  s =>
                  {
                      if (!client.IsAdmin)
                      {
                          server.SendOrderTo(conn, "Message", "Only the host can kick players.");
                          return(true);
                      }

                      var split = s.Split(' ');
                      if (split.Length < 2)
                      {
                          server.SendOrderTo(conn, "Message", "Malformed kick command");
                          return(true);
                      }

                      int kickClientID;
                      Exts.TryParseIntegerInvariant(split[0], out kickClientID);

                      var kickConn = server.Conns.SingleOrDefault(c => server.GetClient(c) != null && server.GetClient(c).Index == kickClientID);
                      if (kickConn == null)
                      {
                          server.SendOrderTo(conn, "Message", "No-one in that slot.");
                          return(true);
                      }

                      var kickClient = server.GetClient(kickConn);

                      Log.Write("server", "Kicking client {0}.", kickClientID);
                      server.SendMessage("{0} kicked {1} from the server.".F(client.Name, kickClient.Name));
                      server.SendOrderTo(kickConn, "ServerError", "You have been kicked from the server.");
                      server.DropClient(kickConn);

                      bool tempBan;
                      bool.TryParse(split[1], out tempBan);

                      if (tempBan)
                      {
                          Log.Write("server", "Temporarily banning client {0} ({1}).", kickClientID, kickClient.IpAddress);
                          server.SendMessage("{0} temporarily banned {1} from the server.".F(client.Name, kickClient.Name));
                          server.TempBans.Add(kickClient.IpAddress);
                      }

                      server.SyncLobbyClients();
                      server.SyncLobbySlots();

                      return(true);
                  } },
                { "name",
                  s =>
                  {
                      var sanitizedName = Settings.SanitizedPlayerName(s);
                      if (sanitizedName == client.Name)
                      {
                          return(true);
                      }

                      Log.Write("server", "Player@{0} is now known as {1}.", conn.Socket.RemoteEndPoint, sanitizedName);
                      server.SendMessage("{0} is now known as {1}.".F(client.Name, sanitizedName));
                      client.Name = sanitizedName;
                      server.SyncLobbyClients();
                      return(true);
                  } },
                { "faction",
                  s =>
                  {
                      var parts        = s.Split(' ');
                      var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0]));

                      // Only the host can change other client's info
                      if (targetClient.Index != client.Index && !client.IsAdmin)
                      {
                          return(true);
                      }

                      // Map has disabled faction changes
                      if (server.LobbyInfo.Slots[targetClient.Slot].LockFaction)
                      {
                          return(true);
                      }

                      var factions = server.Map.Rules.Actors["world"].TraitInfos <FactionInfo>()
                                     .Where(f => f.Selectable).Select(f => f.InternalName);

                      if (!factions.Contains(parts[1]))
                      {
                          server.SendOrderTo(conn, "Message", "Invalid faction selected: {0}".F(parts[1]));
                          server.SendOrderTo(conn, "Message", "Supported values: {0}".F(factions.JoinWith(", ")));
                          return(true);
                      }

                      targetClient.Faction = parts[1];
                      server.SyncLobbyClients();
                      return(true);
                  } },
                { "team",
                  s =>
                  {
                      var parts        = s.Split(' ');
                      var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0]));

                      // Only the host can change other client's info
                      if (targetClient.Index != client.Index && !client.IsAdmin)
                      {
                          return(true);
                      }

                      // Map has disabled team changes
                      if (server.LobbyInfo.Slots[targetClient.Slot].LockTeam)
                      {
                          return(true);
                      }

                      int team;
                      if (!Exts.TryParseIntegerInvariant(parts[1], out team))
                      {
                          Log.Write("server", "Invalid team: {0}", s);
                          return(false);
                      }

                      targetClient.Team = team;
                      server.SyncLobbyClients();
                      return(true);
                  } },
                { "spawn",
                  s =>
                  {
                      var parts        = s.Split(' ');
                      var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0]));

                      // Only the host can change other client's info
                      if (targetClient.Index != client.Index && !client.IsAdmin)
                      {
                          return(true);
                      }

                      // Spectators don't need a spawnpoint
                      if (targetClient.Slot == null)
                      {
                          return(true);
                      }

                      // Map has disabled spawn changes
                      if (server.LobbyInfo.Slots[targetClient.Slot].LockSpawn)
                      {
                          return(true);
                      }

                      int spawnPoint;
                      if (!Exts.TryParseIntegerInvariant(parts[1], out spawnPoint) ||
                          spawnPoint <0 || spawnPoint> server.Map.SpawnPoints.Length)
                      {
                          Log.Write("server", "Invalid spawn point: {0}", parts[1]);
                          return(true);
                      }

                      if (server.LobbyInfo.Clients.Where(cc => cc != client).Any(cc => (cc.SpawnPoint == spawnPoint) && (cc.SpawnPoint != 0)))
                      {
                          server.SendOrderTo(conn, "Message", "You cannot occupy the same spawn point as another player.");
                          return(true);
                      }

                      // Check if any other slot has locked the requested spawn
                      if (spawnPoint > 0)
                      {
                          var spawnLockedByAnotherSlot = server.LobbyInfo.Slots.Where(ss => ss.Value.LockSpawn).Any(ss =>
                            {
                                var pr = PlayerReferenceForSlot(server, ss.Value);
                                return(pr != null && pr.Spawn == spawnPoint);
                            });

                          if (spawnLockedByAnotherSlot)
                          {
                              server.SendOrderTo(conn, "Message", "The spawn point is locked to another player slot.");
                              return(true);
                          }
                      }

                      targetClient.SpawnPoint = spawnPoint;
                      server.SyncLobbyClients();
                      return(true);
                  } },
                { "color",
                  s =>
                  {
                      var parts        = s.Split(' ');
                      var targetClient = server.LobbyInfo.ClientWithIndex(Exts.ParseIntegerInvariant(parts[0]));

                      // Only the host can change other client's info
                      if (targetClient.Index != client.Index && !client.IsAdmin)
                      {
                          return(true);
                      }

                      // Spectator or map has disabled color changes
                      if (targetClient.Slot == null || server.LobbyInfo.Slots[targetClient.Slot].LockColor)
                      {
                          return(true);
                      }

                      // Validate if color is allowed and get an alternative it isn't
                      var newColor = FieldLoader.GetValue <HSLColor>("(value)", parts[1]);
                      targetClient.Color = SanitizePlayerColor(server, newColor, targetClient.Index, conn);

                      // Only update player's preferred color if new color is valid
                      if (newColor == targetClient.Color)
                      {
                          targetClient.PreferredColor = targetClient.Color;
                      }

                      server.SyncLobbyClients();
                      return(true);
                  } },
                { "sync_lobby",
                  s =>
                  {
                      if (!client.IsAdmin)
                      {
                          server.SendOrderTo(conn, "Message", "Only the host can set lobby info");
                          return(true);
                      }

                      var lobbyInfo = Session.Deserialize(s);
                      if (lobbyInfo == null)
                      {
                          server.SendOrderTo(conn, "Message", "Invalid Lobby Info Sent");
                          return(true);
                      }

                      server.LobbyInfo = lobbyInfo;

                      server.SyncLobbyInfo();
                      return(true);
                  } }
            };

            var cmdName  = cmd.Split(' ').First();
            var cmdValue = cmd.Split(' ').Skip(1).JoinWith(" ");

            Func <string, bool> a;

            if (!dict.TryGetValue(cmdName, out a))
            {
                return(false);
            }

            return(a(cmdValue));
        }
Пример #28
0
        void IUtilityCommand.Run(Utility utility, string[] args)
        {
            // HACK: The engine code assumes that Game.modData is set.
            Game.ModData = utility.ModData;

            var version = utility.ModData.Manifest.Metadata.Version;

            if (args.Length > 1)
            {
                version = args[1];
            }

            Console.WriteLine(
                "This documentation is aimed at modders. It displays a template for weapon definitions " +
                "as well as its contained types (warheads and projectiles) with default values and developer commentary. " +
                "Please do not edit it directly, but add new `[Desc(\"String\")]` tags to the source code. This file has been " +
                "automatically generated for version {0} of OpenRA.", version);
            Console.WriteLine();

            var doc = new StringBuilder();

            var currentNamespace = "";

            var objectCreator = utility.ModData.ObjectCreator;
            var weaponInfo    = objectCreator.GetTypesImplementing <WeaponInfo>();
            var warheads      = objectCreator.GetTypesImplementing <IWarhead>().OrderBy(t => t.Namespace);
            var projectiles   = objectCreator.GetTypesImplementing <IProjectileInfo>().OrderBy(t => t.Namespace);

            var weaponTypes = Enumerable.Concat(weaponInfo, Enumerable.Concat(projectiles, warheads));

            foreach (var t in weaponTypes)
            {
                // skip helpers like TraitInfo<T>
                if (t.ContainsGenericParameters || t.IsAbstract)
                {
                    continue;
                }

                if (currentNamespace != t.Namespace)
                {
                    currentNamespace = t.Namespace;
                    doc.AppendLine();
                    doc.AppendLine("## {0}".F(currentNamespace));
                }

                var traitName = t.Name.EndsWith("Info") ? t.Name.Substring(0, t.Name.Length - 4) : t.Name;
                doc.AppendLine();
                doc.AppendLine("### {0}".F(traitName));

                var traitDescLines = t.GetCustomAttributes <DescAttribute>(false).SelectMany(d => d.Lines);
                foreach (var line in traitDescLines)
                {
                    doc.AppendLine(line);
                }

                var infos = FieldLoader.GetTypeLoadInfo(t);
                if (!infos.Any())
                {
                    continue;
                }

                doc.AppendLine("<table>");
                doc.AppendLine("<tr><th>Property</th><th>Default Value</th><th>Type</th><th>Description</th></tr>");

                var liveTraitInfo = t == typeof(WeaponInfo) ? null : objectCreator.CreateBasic(t);
                foreach (var info in infos)
                {
                    var fieldDescLines = info.Field.GetCustomAttributes <DescAttribute>(true).SelectMany(d => d.Lines);
                    var fieldType      = Util.FriendlyTypeName(info.Field.FieldType);
                    var defaultValue   = liveTraitInfo == null ? "" : FieldSaver.SaveField(liveTraitInfo, info.Field.Name).Value.Value;
                    doc.Append("<tr><td>{0}</td><td>{1}</td><td>{2}</td>".F(info.YamlName, defaultValue, fieldType));
                    doc.Append("<td>");

                    foreach (var line in fieldDescLines)
                    {
                        doc.Append(line + " ");
                    }

                    doc.AppendLine("</td></tr>");
                }

                doc.AppendLine("</table>");
            }

            Console.Write(doc.ToString());
        }
        static void ExtractFromISCab(string path, MiniYaml actionYaml, List <string> extractedFiles, Action <string> updateMessage)
        {
            var sourcePath = Path.Combine(path, actionYaml.Value);

            // Try as an absolute path
            if (!File.Exists(sourcePath))
            {
                sourcePath = Platform.ResolvePath(actionYaml.Value);
            }

            var volumeNode = actionYaml.Nodes.FirstOrDefault(n => n.Key == "Volumes");

            if (volumeNode == null)
            {
                throw new InvalidDataException("extract-iscab entry doesn't define a Volumes node");
            }

            var extractNode = actionYaml.Nodes.FirstOrDefault(n => n.Key == "Extract");

            if (extractNode == null)
            {
                throw new InvalidDataException("extract-iscab entry doesn't define an Extract node");
            }

            var volumes = new Dictionary <int, Stream>();

            try
            {
                foreach (var node in volumeNode.Value.Nodes)
                {
                    var volume = FieldLoader.GetValue <int>("(key)", node.Key);
                    var stream = File.OpenRead(Path.Combine(path, node.Value.Value));
                    volumes.Add(volume, stream);
                }

                using (var source = File.OpenRead(sourcePath))
                {
                    var reader = new InstallShieldCABCompression(source, volumes);
                    foreach (var node in extractNode.Value.Nodes)
                    {
                        var targetPath = Platform.ResolvePath(node.Key);

                        if (File.Exists(targetPath))
                        {
                            Log.Write("install", "Skipping installed file " + targetPath);
                            continue;
                        }

                        extractedFiles.Add(targetPath);
                        Directory.CreateDirectory(Path.GetDirectoryName(targetPath));
                        using (var target = File.OpenWrite(targetPath))
                        {
                            Log.Write("install", "Extracting {0} -> {1}".F(sourcePath, targetPath));
                            var          displayFilename = Path.GetFileName(Path.GetFileName(targetPath));
                            Action <int> onProgress      = percent => updateMessage("Extracting {0} ({1}%)".F(displayFilename, percent));
                            reader.ExtractFile(node.Value.Value, target, onProgress);
                        }
                    }
                }
            }
            finally
            {
                foreach (var kv in volumes)
                {
                    kv.Value.Dispose();
                }
            }
        }
Пример #30
0
 public static T Get <T>(string key)
 {
     return(FieldLoader.GetValue <T>(key, data[key]));
 }