Beispiel #1
0
        public MultiplayerLogic(Widget widget, ModData modData, Action onStart, Action onExit, string directConnectHost, int directConnectPort)
        {
            // MultiplayerLogic is a superset of the ServerListLogic
            // but cannot be a direct subclass because it needs to pass object-level state to the constructor
            serverListLogic = new ServerListLogic(widget, modData, Join);

            this.onStart = onStart;
            this.onExit  = onExit;

            var directConnectButton = widget.Get <ButtonWidget>("DIRECTCONNECT_BUTTON");

            directConnectButton.OnClick = () =>
            {
                Ui.OpenWindow("DIRECTCONNECT_PANEL", new WidgetArgs
                {
                    { "openLobby", OpenLobby },
                    { "onExit", DoNothing },
                    { "directConnectHost", null },
                    { "directConnectPort", 0 },
                });
            };

            var createServerButton = widget.Get <ButtonWidget>("CREATE_BUTTON");

            createServerButton.OnClick = () =>
            {
                Ui.OpenWindow("MULTIPLAYER_CREATESERVER_PANEL", new WidgetArgs
                {
                    { "openLobby", OpenLobby },
                    { "onExit", DoNothing }
                });
            };

            var hasMaps = modData.MapCache.Any(p => !p.Visibility.HasFlag(MapVisibility.Shellmap));

            createServerButton.Disabled = !hasMaps;

            widget.Get <ButtonWidget>("BACK_BUTTON").OnClick = () => { Ui.CloseWindow(); onExit(); };

            if (directConnectHost != null)
            {
                // The connection window must be opened at the end of the tick for the widget hierarchy to
                // work out, but we also want to prevent the server browser from flashing visible for one tick.
                widget.Visible = false;
                Game.RunAfterTick(() =>
                {
                    Ui.OpenWindow("DIRECTCONNECT_PANEL", new WidgetArgs
                    {
                        { "openLobby", OpenLobby },
                        { "onExit", DoNothing },
                        { "directConnectHost", directConnectHost },
                        { "directConnectPort", directConnectPort },
                    });

                    widget.Visible = true;
                });
            }
        }
        internal LobbyLogic(Widget widget, ModData modData, WorldRenderer worldRenderer, OrderManager orderManager,
                            Action onExit, Action onStart, bool skirmishMode)
        {
            map                = MapCache.UnknownMap;
            lobby              = widget;
            this.modData       = modData;
            this.orderManager  = orderManager;
            this.worldRenderer = worldRenderer;
            this.onStart       = onStart;
            this.onExit        = onExit;
            this.skirmishMode  = skirmishMode;

            // TODO: This needs to be reworked to support per-map tech levels, bots, etc.
            this.modRules = modData.DefaultRules;
            shellmapWorld = worldRenderer.World;

            services = modData.Manifest.Get <WebServices>();

            orderManager.AddChatLine    += AddChatLine;
            Game.LobbyInfoChanged       += UpdateCurrentMap;
            Game.LobbyInfoChanged       += UpdatePlayerList;
            Game.BeforeGameStart        += OnGameStart;
            Game.ConnectionStateChanged += ConnectionStateChanged;

            var name = lobby.GetOrNull <LabelWidget>("SERVER_NAME");

            if (name != null)
            {
                name.GetText = () => orderManager.LobbyInfo.GlobalSettings.ServerName;
            }

            var mapContainer = Ui.LoadWidget("MAP_PREVIEW", lobby.Get("MAP_PREVIEW_ROOT"), new WidgetArgs
            {
                { "orderManager", orderManager },
                { "getMap", (Func <MapPreview>)(() => map) },
                { "onMouseDown", (Action <MapPreviewWidget, MapPreview, MouseInput>)((preview, mapPreview, mi) =>
                                                                                     LobbyUtils.SelectSpawnPoint(orderManager, preview, mapPreview, mi)) },
                { "getSpawnOccupants", (Func <MapPreview, Dictionary <CPos, SpawnOccupant> >)(mapPreview => LobbyUtils.GetSpawnOccupants(orderManager.LobbyInfo, mapPreview)) },
                { "showUnoccupiedSpawnpoints", true },
            });

            mapContainer.IsVisible = () => panel != PanelType.Servers;

            UpdateCurrentMap();

            var playerBin = Ui.LoadWidget("LOBBY_PLAYER_BIN", lobby.Get("TOP_PANELS_ROOT"), new WidgetArgs());

            playerBin.IsVisible = () => panel == PanelType.Players;

            players = playerBin.Get <ScrollPanelWidget>("LOBBY_PLAYERS");
            editablePlayerTemplate       = players.Get("TEMPLATE_EDITABLE_PLAYER");
            nonEditablePlayerTemplate    = players.Get("TEMPLATE_NONEDITABLE_PLAYER");
            emptySlotTemplate            = players.Get("TEMPLATE_EMPTY");
            editableSpectatorTemplate    = players.Get("TEMPLATE_EDITABLE_SPECTATOR");
            nonEditableSpectatorTemplate = players.Get("TEMPLATE_NONEDITABLE_SPECTATOR");
            newSpectatorTemplate         = players.Get("TEMPLATE_NEW_SPECTATOR");
            colorPreview       = lobby.Get <ColorPreviewManagerWidget>("COLOR_MANAGER");
            colorPreview.Color = Game.Settings.Player.Color;

            foreach (var f in modRules.Actors["world"].TraitInfos <FactionInfo>())
            {
                factions.Add(f.InternalName, new LobbyFaction {
                    Selectable = f.Selectable, Name = f.Name, Side = f.Side, Description = f.Description
                });
            }

            var         gameStarting          = false;
            Func <bool> configurationDisabled = () => !Game.IsHost || gameStarting ||
                                                panel == PanelType.Kick || panel == PanelType.ForceStart ||
                                                !map.RulesLoaded || map.InvalidCustomRules ||
                                                orderManager.LocalClient == null || orderManager.LocalClient.IsReady;

            var mapButton = lobby.GetOrNull <ButtonWidget>("CHANGEMAP_BUTTON");

            if (mapButton != null)
            {
                mapButton.IsVisible  = () => panel != PanelType.Servers;
                mapButton.IsDisabled = () => gameStarting || panel == PanelType.Kick || panel == PanelType.ForceStart ||
                                       orderManager.LocalClient == null || orderManager.LocalClient.IsReady;
                mapButton.OnClick = () =>
                {
                    var onSelect = new Action <string>(uid =>
                    {
                        // Don't select the same map again
                        if (uid == map.Uid)
                        {
                            return;
                        }

                        orderManager.IssueOrder(Order.Command("map " + uid));
                        Game.Settings.Server.Map = uid;
                        Game.Settings.Save();
                    });

                    Ui.OpenWindow("MAPCHOOSER_PANEL", new WidgetArgs()
                    {
                        { "initialMap", map.Uid },
                        { "initialTab", MapClassification.System },
                        { "onExit", DoNothing },
                        { "onSelect", Game.IsHost ? onSelect : null },
                        { "filter", MapVisibility.Lobby },
                    });
                };
            }

            var slotsButton = lobby.GetOrNull <DropDownButtonWidget>("SLOTS_DROPDOWNBUTTON");

            if (slotsButton != null)
            {
                slotsButton.IsVisible  = () => panel != PanelType.Servers;
                slotsButton.IsDisabled = () => configurationDisabled() || panel != PanelType.Players ||
                                         (orderManager.LobbyInfo.Slots.Values.All(s => !s.AllowBots) &&
                                          orderManager.LobbyInfo.Slots.Count(s => !s.Value.LockTeam && orderManager.LobbyInfo.ClientInSlot(s.Key) != null) == 0);

                slotsButton.OnMouseDown = _ =>
                {
                    var botTypes = map.Rules.Actors["player"].TraitInfos <IBotInfo>().Select(t => t.Type);
                    var options  = new Dictionary <string, IEnumerable <DropDownOption> >();

                    var botController = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.IsAdmin);
                    if (orderManager.LobbyInfo.Slots.Values.Any(s => s.AllowBots))
                    {
                        var botOptions = new List <DropDownOption>()
                        {
                            new DropDownOption()
                            {
                                Title      = "Add",
                                IsSelected = () => false,
                                OnClick    = () =>
                                {
                                    foreach (var slot in orderManager.LobbyInfo.Slots)
                                    {
                                        var bot = botTypes.Random(Game.CosmeticRandom);
                                        var c   = orderManager.LobbyInfo.ClientInSlot(slot.Key);
                                        if (slot.Value.AllowBots == true && (c == null || c.Bot != null))
                                        {
                                            orderManager.IssueOrder(Order.Command("slot_bot {0} {1} {2}".F(slot.Key, botController.Index, bot)));
                                        }
                                    }
                                }
                            }
                        };

                        if (orderManager.LobbyInfo.Clients.Any(c => c.Bot != null))
                        {
                            botOptions.Add(new DropDownOption()
                            {
                                Title      = "Remove",
                                IsSelected = () => false,
                                OnClick    = () =>
                                {
                                    foreach (var slot in orderManager.LobbyInfo.Slots)
                                    {
                                        var c = orderManager.LobbyInfo.ClientInSlot(slot.Key);
                                        if (c != null && c.Bot != null)
                                        {
                                            orderManager.IssueOrder(Order.Command("slot_open " + slot.Value.PlayerReference));
                                        }
                                    }
                                }
                            });
                        }

                        options.Add("Configure Bots", botOptions);
                    }

                    var teamCount = (orderManager.LobbyInfo.Slots.Count(s => !s.Value.LockTeam && orderManager.LobbyInfo.ClientInSlot(s.Key) != null) + 1) / 2;
                    if (teamCount >= 1)
                    {
                        var teamOptions = Enumerable.Range(2, teamCount - 1).Reverse().Select(d => new DropDownOption
                        {
                            Title      = "{0} Teams".F(d),
                            IsSelected = () => false,
                            OnClick    = () => orderManager.IssueOrder(Order.Command("assignteams {0}".F(d.ToString())))
                        }).ToList();

                        if (orderManager.LobbyInfo.Slots.Any(s => s.Value.AllowBots))
                        {
                            teamOptions.Add(new DropDownOption
                            {
                                Title      = "Humans vs Bots",
                                IsSelected = () => false,
                                OnClick    = () => orderManager.IssueOrder(Order.Command("assignteams 1"))
                            });
                        }

                        teamOptions.Add(new DropDownOption
                        {
                            Title      = "Free for all",
                            IsSelected = () => false,
                            OnClick    = () => orderManager.IssueOrder(Order.Command("assignteams 0"))
                        });

                        options.Add("Configure Teams", teamOptions);
                    }

                    Func <DropDownOption, ScrollItemWidget, ScrollItemWidget> setupItem = (option, template) =>
                    {
                        var item = ScrollItemWidget.Setup(template, option.IsSelected, option.OnClick);
                        item.Get <LabelWidget>("LABEL").GetText = () => option.Title;
                        return(item);
                    };
                    slotsButton.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 175, options, setupItem);
                };
            }

            var optionsBin = Ui.LoadWidget("LOBBY_OPTIONS_BIN", lobby.Get("TOP_PANELS_ROOT"), new WidgetArgs()
            {
                { "orderManager", orderManager },
                { "getMap", (Func <MapPreview>)(() => map) },
                { "configurationDisabled", configurationDisabled }
            });

            optionsBin.IsVisible = () => panel == PanelType.Options;

            var musicBin = Ui.LoadWidget("LOBBY_MUSIC_BIN", lobby.Get("TOP_PANELS_ROOT"), new WidgetArgs
            {
                { "onExit", DoNothing },
                { "world", worldRenderer.World }
            });

            musicBin.IsVisible = () => panel == PanelType.Music;

            ServerListLogic serverListLogic = null;

            if (!skirmishMode)
            {
                Action <GameServer> doNothingWithServer = _ => { };

                var serversBin = Ui.LoadWidget("LOBBY_SERVERS_BIN", lobby.Get("TOP_PANELS_ROOT"), new WidgetArgs
                {
                    { "onJoin", doNothingWithServer },
                });

                serverListLogic      = serversBin.LogicObjects.Select(l => l as ServerListLogic).FirstOrDefault(l => l != null);
                serversBin.IsVisible = () => panel == PanelType.Servers;
            }

            var tabContainer = skirmishMode ? lobby.Get("SKIRMISH_TABS") : lobby.Get("MULTIPLAYER_TABS");

            tabContainer.IsVisible = () => true;

            var optionsTab = tabContainer.Get <ButtonWidget>("OPTIONS_TAB");

            optionsTab.IsHighlighted = () => panel == PanelType.Options;
            optionsTab.IsDisabled    = OptionsTabDisabled;
            optionsTab.OnClick       = () => panel = PanelType.Options;
            optionsTab.GetText       = () => !map.RulesLoaded ? "Loading..." : optionsTab.Text;

            var playersTab = tabContainer.Get <ButtonWidget>("PLAYERS_TAB");

            playersTab.IsHighlighted = () => panel == PanelType.Players;
            playersTab.IsDisabled    = () => panel == PanelType.Kick || panel == PanelType.ForceStart;
            playersTab.OnClick       = () => panel = PanelType.Players;

            var musicTab = tabContainer.Get <ButtonWidget>("MUSIC_TAB");

            musicTab.IsHighlighted = () => panel == PanelType.Music;
            musicTab.IsDisabled    = () => panel == PanelType.Kick || panel == PanelType.ForceStart;
            musicTab.OnClick       = () => panel = PanelType.Music;

            var serversTab = tabContainer.GetOrNull <ButtonWidget>("SERVERS_TAB");

            if (serversTab != null)
            {
                serversTab.IsHighlighted = () => panel == PanelType.Servers;
                serversTab.IsDisabled    = () => panel == PanelType.Kick || panel == PanelType.ForceStart;
                serversTab.OnClick       = () =>
                {
                    // Refresh the list when switching to the servers tab
                    if (serverListLogic != null && panel != PanelType.Servers)
                    {
                        serverListLogic.RefreshServerList();
                    }

                    panel = PanelType.Servers;
                };
            }

            // Force start panel
            Action startGame = () =>
            {
                gameStarting = true;
                orderManager.IssueOrder(Order.Command("startgame"));
            };

            var startGameButton = lobby.GetOrNull <ButtonWidget>("START_GAME_BUTTON");

            if (startGameButton != null)
            {
                startGameButton.IsDisabled = () => configurationDisabled() || map.Status != MapStatus.Available ||
                                             orderManager.LobbyInfo.Slots.Any(sl => sl.Value.Required && orderManager.LobbyInfo.ClientInSlot(sl.Key) == null) ||
                                             (!orderManager.LobbyInfo.GlobalSettings.EnableSingleplayer && orderManager.LobbyInfo.NonBotPlayers.Count() < 2);

                startGameButton.OnClick = () =>
                {
                    // Bots and admins don't count
                    if (orderManager.LobbyInfo.Clients.Any(c => c.Slot != null && !c.IsAdmin && c.Bot == null && !c.IsReady))
                    {
                        panel = PanelType.ForceStart;
                    }
                    else
                    {
                        startGame();
                    }
                };
            }

            var forceStartBin = Ui.LoadWidget("FORCE_START_DIALOG", lobby.Get("TOP_PANELS_ROOT"), new WidgetArgs());

            forceStartBin.IsVisible = () => panel == PanelType.ForceStart;
            forceStartBin.Get("KICK_WARNING").IsVisible               = () => orderManager.LobbyInfo.Clients.Any(c => c.IsInvalid);
            forceStartBin.Get <ButtonWidget>("OK_BUTTON").OnClick     = startGame;
            forceStartBin.Get <ButtonWidget>("CANCEL_BUTTON").OnClick = () => panel = PanelType.Players;

            var disconnectButton = lobby.Get <ButtonWidget>("DISCONNECT_BUTTON");

            disconnectButton.OnClick = () => { Ui.CloseWindow(); onExit(); };

            if (skirmishMode)
            {
                disconnectButton.Text = "Back";
            }

            chatLabel = lobby.Get <LabelWidget>("LABEL_CHATTYPE");
            var chatTextField = lobby.Get <TextFieldWidget>("CHAT_TEXTFIELD");

            chatTextField.MaxLength = UnitOrders.ChatMessageMaxLength;

            chatTextField.TakeKeyboardFocus();
            chatTextField.OnEnterKey = () =>
            {
                if (chatTextField.Text.Length == 0)
                {
                    return(true);
                }

                // Always scroll to bottom when we've typed something
                lobbyChatPanel.ScrollToBottom();

                orderManager.IssueOrder(Order.Chat(teamChat, chatTextField.Text));
                chatTextField.Text = "";
                return(true);
            };

            chatTextField.OnTabKey = () =>
            {
                var previousText = chatTextField.Text;
                chatTextField.Text           = tabCompletion.Complete(chatTextField.Text);
                chatTextField.CursorPosition = chatTextField.Text.Length;

                if (chatTextField.Text == previousText)
                {
                    return(SwitchTeamChat());
                }
                else
                {
                    return(true);
                }
            };

            chatTextField.OnEscKey = () => { chatTextField.Text = ""; return(true); };

            lobbyChatPanel = lobby.Get <ScrollPanelWidget>("CHAT_DISPLAY");
            chatTemplate   = lobbyChatPanel.Get("CHAT_TEMPLATE");
            lobbyChatPanel.RemoveChildren();

            var settingsButton = lobby.GetOrNull <ButtonWidget>("SETTINGS_BUTTON");

            if (settingsButton != null)
            {
                settingsButton.OnClick = () => Ui.OpenWindow("SETTINGS_PANEL", new WidgetArgs
                {
                    { "onExit", DoNothing },
                    { "worldRenderer", worldRenderer }
                });
            }

            // Add a bot on the first lobbyinfo update
            if (skirmishMode)
            {
                addBotOnMapLoad = true;
            }
        }