Пример #1
0
        public static void StopMultiplayer()
        {
            if (Multiplayer.session != null)
            {
                Multiplayer.session.Stop();
                Multiplayer.session = null;
                Prefs.Apply();
            }

            Multiplayer.game = null;

            TickPatch.ClearSkipping();
            TickPatch.Timer       = 0;
            TickPatch.tickUntil   = 0;
            TickPatch.accumulator = 0;

            Find.WindowStack?.WindowOfType <ServerBrowser>()?.Cleanup(true);

            foreach (var entry in Sync.bufferedChanges)
            {
                entry.Value.Clear();
            }

            ClearCaches();

            if (Multiplayer.arbiterInstance)
            {
                Multiplayer.arbiterInstance = false;
                Application.Quit();
            }
        }
Пример #2
0
        static void DrawSkippingWindow()
        {
            if (Multiplayer.Client == null || TickPatch.skipTo < 0)
            {
                return;
            }

            string text        = $"{"MpSimulating".Translate()}{MpUtil.FixedEllipsis()}";
            float  textWidth   = Text.CalcSize(text).x;
            float  windowWidth = Math.Max(240f, textWidth + 40f);
            Rect   rect        = new Rect(0, 0, windowWidth, 75f).CenterOn(new Rect(0, 0, UI.screenWidth, UI.screenHeight));

            if (Multiplayer.IsReplay && !TickPatch.disableSkipCancel && Event.current.type == EventType.KeyUp && Event.current.keyCode == KeyCode.Escape)
            {
                TickPatch.ClearSkipping();
                Event.current.Use();
            }

            Find.WindowStack.ImmediateWindow(SkippingWindowId, rect, WindowLayer.Super, () =>
            {
                Text.Anchor = TextAnchor.MiddleCenter;
                Text.Font   = GameFont.Small;
                Widgets.Label(rect.AtZero(), text);
                Text.Anchor = TextAnchor.UpperLeft;
            }, absorbInputAroundWindow: true);
        }
Пример #3
0
        public static void LoadReplay(FileInfo file, bool toEnd = false, Action after = null, Action cancel = null, string simTextKey = null)
        {
            var session = Multiplayer.session = new MultiplayerSession();

            session.client       = new ReplayConnection();
            session.client.State = ConnectionStateEnum.ClientPlaying;
            session.replay       = true;

            var replay = ForLoading(file);

            replay.LoadInfo();

            var sectionIndex = toEnd ? (replay.info.sections.Count - 1) : 0;

            replay.LoadCurrentData(sectionIndex);

            // todo ensure everything is read correctly

            session.myFactionId      = replay.info.playerFaction;
            session.replayTimerStart = replay.info.sections[sectionIndex].start;

            int tickUntil = replay.info.sections[sectionIndex].end;

            session.replayTimerEnd = tickUntil;
            TickPatch.tickUntil    = tickUntil;

            TickPatch.SkipTo(toEnd ? tickUntil : session.replayTimerStart, onFinish: after, onCancel: cancel, simTextKey: simTextKey);

            ClientJoiningState.ReloadGame(OnMainThread.cachedMapData.Keys.ToList());
        }
Пример #4
0
 static void HandleSimulatingEvents()
 {
     if (TickPatch.simulating.canEsc && Event.current.type == EventType.KeyUp && Event.current.keyCode == KeyCode.Escape)
     {
         TickPatch.ClearSimulating();
         Event.current.Use();
     }
 }
Пример #5
0
        public override void DoWindowContents(Rect inRect)
        {
            Text.Font = GameFont.Small;

            Text.Anchor = TextAnchor.UpperCenter;
            Widgets.Label(new Rect(0, 0, inRect.width, 40), $"{"MpDesynced".Translate()}\n{text}");
            Text.Anchor = TextAnchor.UpperLeft;

            float buttonWidth = 120 * 4 + 10 * 3;
            var   buttonRect  = new Rect((inRect.width - buttonWidth) / 2, 40, buttonWidth, 35);

            GUI.BeginGroup(buttonRect);

            float x = 0;

            if (Widgets.ButtonText(new Rect(x, 0, 120, 35), "MpTryResync".Translate()))
            {
                Multiplayer.session.resyncing = true;

                TickPatch.SkipTo(
                    toTickUntil: true,
                    onFinish: () =>
                {
                    Multiplayer.session.resyncing = false;
                    Multiplayer.Client.Send(Packets.Client_WorldReady);
                },
                    cancelButtonKey: "Quit",
                    onCancel: GenScene.GoToMainMenu
                    );

                Multiplayer.session.desynced = false;

                ClientJoiningState.ReloadGame(OnMainThread.cachedMapData.Keys.ToList(), false);
            }
            x += 120 + 10;

            if (Widgets.ButtonText(new Rect(x, 0, 120, 35), "Save".Translate()))
            {
                Find.WindowStack.Add(new Dialog_SaveReplay());
            }
            x += 120 + 10;

            if (Widgets.ButtonText(new Rect(x, 0, 120, 35), "MpChatButton".Translate()))
            {
                Find.WindowStack.Add(new ChatWindow()
                {
                    closeOnClickedOutside = true, absorbInputAroundWindow = true
                });
            }
            x += 120 + 10;

            if (Widgets.ButtonText(new Rect(x, 0, 120, 35), "Quit".Translate()))
            {
                MainMenuPatch.AskQuitToMainMenu();
            }

            GUI.EndGroup();
        }
Пример #6
0
        public void HandleWorldData(ByteReader data)
        {
            connection.State = ConnectionStateEnum.ClientPlaying;
            Log.Message("Game data size: " + data.Length);

            int factionId = data.ReadInt32();

            Multiplayer.session.myFactionId = factionId;

            int tickUntil = data.ReadInt32();

            byte[] worldData = GZipStream.UncompressBuffer(data.ReadPrefixedBytes());
            OnMainThread.cachedGameData = worldData;

            List <int> mapsToLoad = new List <int>();

            int mapCmdsCount = data.ReadInt32();

            for (int i = 0; i < mapCmdsCount; i++)
            {
                int mapId = data.ReadInt32();

                int mapCmdsLen = data.ReadInt32();
                List <ScheduledCommand> mapCmds = new List <ScheduledCommand>(mapCmdsLen);
                for (int j = 0; j < mapCmdsLen; j++)
                {
                    mapCmds.Add(ScheduledCommand.Deserialize(new ByteReader(data.ReadPrefixedBytes())));
                }

                OnMainThread.cachedMapCmds[mapId] = mapCmds;
            }

            int mapDataCount = data.ReadInt32();

            for (int i = 0; i < mapDataCount; i++)
            {
                int    mapId      = data.ReadInt32();
                byte[] rawMapData = data.ReadPrefixedBytes();

                byte[] mapData = GZipStream.UncompressBuffer(rawMapData);
                OnMainThread.cachedMapData[mapId] = mapData;
                mapsToLoad.Add(mapId);
            }

            Multiplayer.session.localCmdId = data.ReadInt32();

            TickPatch.tickUntil = tickUntil;

            TickPatch.SkipTo(
                toTickUntil: true,
                onFinish: () => Multiplayer.Client.Send(Packets.Client_WorldReady),
                cancelButtonKey: "Quit",
                onCancel: GenScene.GoToMainMenu
                );

            ReloadGame(mapsToLoad);
        }
Пример #7
0
        static bool Prefix()
        {
            if (Multiplayer.Client == null || !TimeControlsMarker.drawingTimeControls)
            {
                return(true);
            }

            if (TickPatch.Timer < TickPatch.tickUntil)
            {
                var replaySpeed = TickPatch.replayTimeSpeed;
                TickPatch.replayTimeSpeed = TimeSpeed.Normal;
                TickPatch.accumulator     = 1;

                TickPatch.Tick();

                TickPatch.accumulator     = 0;
                TickPatch.replayTimeSpeed = replaySpeed;
            }

            return(false);
        }
        static void DrawSkippingWindow()
        {
            if (Multiplayer.Client == null || !TickPatch.Skipping)
            {
                return;
            }

            string text         = $"{TickPatch.skippingTextKey.Translate()}{MpUtil.FixedEllipsis()}";
            float  textWidth    = Text.CalcSize(text).x;
            float  windowWidth  = Math.Max(240f, textWidth + 40f);
            float  windowHeight = TickPatch.cancelSkip != null ? 100f : 75f;
            Rect   rect         = new Rect(0, 0, windowWidth, windowHeight).CenterOn(new Rect(0, 0, UI.screenWidth, UI.screenHeight));

            if (TickPatch.canESCSkip && Event.current.type == EventType.KeyUp && Event.current.keyCode == KeyCode.Escape)
            {
                TickPatch.ClearSkipping();
                Event.current.Use();
            }

            Find.WindowStack.ImmediateWindow(SkippingWindowId, rect, WindowLayer.Super, () =>
            {
                var textRect = rect.AtZero();
                if (TickPatch.cancelSkip != null)
                {
                    textRect.yMin   += 5f;
                    textRect.height -= 50f;
                }

                Text.Anchor = TextAnchor.MiddleCenter;
                Text.Font   = GameFont.Small;
                Widgets.Label(textRect, text);
                Text.Anchor = TextAnchor.UpperLeft;

                if (TickPatch.cancelSkip != null && Widgets.ButtonText(new Rect(0, textRect.yMax, 100f, 35f).CenteredOnXIn(textRect), TickPatch.skipCancelButtonKey.Translate()))
                {
                    TickPatch.cancelSkip();
                }
            }, absorbInputAroundWindow: true);
        }
Пример #9
0
        public void HandleWorldData(ByteReader data)
        {
            connection.State = ConnectionStateEnum.ClientPlaying;
            Log.Message("Game data size: " + data.Length);

            int factionId = data.ReadInt32();

            Multiplayer.session.myFactionId = factionId;

            int tickUntil = data.ReadInt32();

            var dataSnapshot = new GameDataSnapshot();

            byte[] worldData = GZipStream.UncompressBuffer(data.ReadPrefixedBytes());
            dataSnapshot.gameData = worldData;

            byte[] semiPersistentData = GZipStream.UncompressBuffer(data.ReadPrefixedBytes());
            dataSnapshot.semiPersistentData = semiPersistentData;

            List <int> mapsToLoad = new List <int>();

            int mapCmdsCount = data.ReadInt32();

            for (int i = 0; i < mapCmdsCount; i++)
            {
                int mapId = data.ReadInt32();

                int mapCmdsLen = data.ReadInt32();
                List <ScheduledCommand> mapCmds = new List <ScheduledCommand>(mapCmdsLen);
                for (int j = 0; j < mapCmdsLen; j++)
                {
                    mapCmds.Add(ScheduledCommand.Deserialize(new ByteReader(data.ReadPrefixedBytes())));
                }

                dataSnapshot.mapCmds[mapId] = mapCmds;
            }

            int mapDataCount = data.ReadInt32();

            for (int i = 0; i < mapDataCount; i++)
            {
                int    mapId      = data.ReadInt32();
                byte[] rawMapData = data.ReadPrefixedBytes();

                byte[] mapData = GZipStream.UncompressBuffer(rawMapData);
                dataSnapshot.mapData[mapId] = mapData;
                mapsToLoad.Add(mapId);
            }

            Session.dataSnapshot           = dataSnapshot;
            Multiplayer.session.localCmdId = data.ReadInt32();
            TickPatch.shouldPause          = data.ReadBool();
            TickPatch.tickUntil            = tickUntil;

            TickPatch.SetSimulation(
                toTickUntil: true,
                onFinish: () => Multiplayer.Client.Send(Packets.Client_WorldReady),
                cancelButtonKey: "Quit",
                onCancel: GenScene.GoToMainMenu // Calls StopMultiplayer through a patch
                );

            ReloadGame(mapsToLoad, true, false);
        }
        static void DrawTimelineWindow()
        {
            if (Multiplayer.Client == null)
            {
                return;
            }

            Rect rect = new Rect(0, 30f, UI.screenWidth - TimelineMargin * 2, TimelineHeight);

            Widgets.DrawBoxSolid(rect, new Color(0.6f, 0.6f, 0.6f, 0.8f));

            int timerStart = Multiplayer.session.replayTimerStart >= 0 ? Multiplayer.session.replayTimerStart : OnMainThread.cachedAtTime;
            int timerEnd   = Multiplayer.session.replayTimerEnd >= 0 ? Multiplayer.session.replayTimerEnd : TickPatch.tickUntil;
            int timeLen    = timerEnd - timerStart;

            Widgets.DrawLine(new Vector2(rect.xMin + 2f, rect.yMin), new Vector2(rect.xMin + 2f, rect.yMax), Color.white, 4f);
            Widgets.DrawLine(new Vector2(rect.xMax - 2f, rect.yMin), new Vector2(rect.xMax - 2f, rect.yMax), Color.white, 4f);

            float progress  = (TickPatch.Timer - timerStart) / (float)timeLen;
            float progressX = rect.xMin + progress * rect.width;

            Widgets.DrawLine(new Vector2(progressX, rect.yMin), new Vector2(progressX, rect.yMax), Color.green, 7f);

            float       mouseX     = Event.current.mousePosition.x;
            ReplayEvent mouseEvent = null;

            foreach (var ev in Multiplayer.session.events)
            {
                if (ev.time < timerStart || ev.time > timerEnd)
                {
                    continue;
                }

                var pointX = rect.xMin + (ev.time - timerStart) / (float)timeLen * rect.width;

                //GUI.DrawTexture(new Rect(pointX - 12f, rect.yMin - 24f, 24f, 24f), texture);
                Widgets.DrawLine(new Vector2(pointX, rect.yMin), new Vector2(pointX, rect.yMax), ev.color, 5f);

                if (Mouse.IsOver(rect) && Math.Abs(mouseX - pointX) < 10)
                {
                    mouseX     = pointX;
                    mouseEvent = ev;
                }
            }

            if (Mouse.IsOver(rect))
            {
                float mouseProgress = (mouseX - rect.xMin) / rect.width;
                int   mouseTimer    = timerStart + (int)(timeLen * mouseProgress);

                Widgets.DrawLine(new Vector2(mouseX, rect.yMin), new Vector2(mouseX, rect.yMax), Color.blue, 3f);

                if (Event.current.type == EventType.MouseUp)
                {
                    TickPatch.SkipTo(mouseTimer, canESC: true);

                    if (mouseTimer < TickPatch.Timer)
                    {
                        ClientJoiningState.ReloadGame(OnMainThread.cachedMapData.Keys.ToList(), false);
                    }
                }

                if (Event.current.isMouse)
                {
                    Event.current.Use();
                }

                string tooltip = $"Tick {mouseTimer}";
                if (mouseEvent != null)
                {
                    tooltip = $"{mouseEvent.name}\n{tooltip}";
                }

                TooltipHandler.TipRegion(rect, new TipSignal(tooltip, 215462143));
                // No delay between the mouseover and showing
                if (TooltipHandler.activeTips.TryGetValue(215462143, out ActiveTip tip))
                {
                    tip.firstTriggerTime = 0;
                }
            }

            if (TickPatch.Skipping)
            {
                float pct     = (TickPatch.skipTo - timerStart) / (float)timeLen;
                float skipToX = rect.xMin + rect.width * pct;
                Widgets.DrawLine(new Vector2(skipToX, rect.yMin), new Vector2(skipToX, rect.yMax), Color.yellow, 4f);
            }
        }
        static void DoButtons()
        {
            float       y         = 10f;
            const float btnHeight = 27f;
            const float btnWidth  = 80f;

            float x = UI.screenWidth - btnWidth - 10f;

            var session = Multiplayer.session;

            if (session != null && !Multiplayer.IsReplay)
            {
                var btnRect = new Rect(x, y, btnWidth, btnHeight);

                var chatColor = session.players.Any(p => p.status == PlayerStatus.Desynced) ? "#ff5555" : "#dddddd";
                var hasUnread = session.hasUnread ? "*" : "";
                var chatLabel = $"{"MpChatButton".Translate()} <color={chatColor}>({session.players.Count})</color>{hasUnread}";

                if (Widgets.ButtonText(btnRect, chatLabel))
                {
                    OpenChat();
                }

                if (!TickPatch.Skipping)
                {
                    IndicatorInfo(out Color color, out string text, out bool slow);

                    var indRect    = new Rect(btnRect.x - 25f - 5f + 6f / 2f, btnRect.y + 6f / 2f, 19f, 19f);
                    var biggerRect = new Rect(btnRect.x - 25f - 5f + 2f / 2f, btnRect.y + 2f / 2f, 23f, 23f);

                    if (slow && Widgets.ButtonInvisible(biggerRect))
                    {
                        TickPatch.SkipTo(toTickUntil: true, canESC: true);
                    }

                    Widgets.DrawRectFast(biggerRect, new Color(color.r * 0.6f, color.g * 0.6f, color.b * 0.6f));
                    Widgets.DrawRectFast(indRect, color);
                    TooltipHandler.TipRegion(indRect, new TipSignal(text, 31641624));
                }

                y += btnHeight;
            }

            if (Multiplayer.ShowDevInfo && Multiplayer.PacketLog != null)
            {
                if (Widgets.ButtonText(new Rect(x, y, btnWidth, btnHeight), $"Sync ({Multiplayer.PacketLog.nodes.Count})"))
                {
                    Find.WindowStack.Add(Multiplayer.PacketLog);
                }

                y += btnHeight;
            }

            if (Multiplayer.Client != null && Multiplayer.WorldComp.trading.Any())
            {
                if (Widgets.ButtonText(new Rect(x, y, btnWidth, btnHeight), "MpTradingButton".Translate()))
                {
                    Find.WindowStack.Add(new TradingWindow());
                }
                y += btnHeight;
            }

            if (Multiplayer.Client != null && Multiplayer.WorldComp.debugMode)
            {
                Text.Font   = GameFont.Tiny;
                Text.Anchor = TextAnchor.MiddleCenter;
                Widgets.Label(new Rect(x, y, btnWidth, 30f), $"Debug mode");
                Text.Anchor = TextAnchor.UpperLeft;
                Text.Font   = GameFont.Small;
            }
        }
Пример #12
0
        static void DrawTimelineWindow()
        {
            Rect rect = new Rect(0, 30f, UI.screenWidth - TimelineMargin * 2, TimelineHeight);

            Widgets.DrawBoxSolid(rect, new Color(0.6f, 0.6f, 0.6f, 0.8f));

            int timerStart = Multiplayer.session.replayTimerStart >= 0 ?
                             Multiplayer.session.replayTimerStart : Multiplayer.session.dataSnapshot.cachedAtTime;

            int timerEnd = Multiplayer.session.replayTimerEnd >= 0 ?
                           Multiplayer.session.replayTimerEnd : TickPatch.tickUntil;

            int timeLen = timerEnd - timerStart;

            MpUI.DrawRotatedLine(new Vector2(rect.xMin + 2f, rect.center.y), TimelineHeight, 20f, 90f, Color.white);
            MpUI.DrawRotatedLine(new Vector2(rect.xMax - 2f, rect.center.y), TimelineHeight, 20f, 90f, Color.white);

            float progress  = (TickPatch.Timer - timerStart) / (float)timeLen;
            float progressX = rect.xMin + progress * rect.width;

            MpUI.DrawRotatedLine(new Vector2((int)progressX, rect.center.y), TimelineHeight, 20f, 90f, Color.green);

            float       mouseX     = Event.current.mousePosition.x;
            ReplayEvent mouseEvent = null;

            foreach (var ev in Multiplayer.session.events)
            {
                if (ev.time < timerStart || ev.time > timerEnd)
                {
                    continue;
                }

                var pointX = rect.xMin + (ev.time - timerStart) / (float)timeLen * rect.width;

                //GUI.DrawTexture(new Rect(pointX - 12f, rect.yMin - 24f, 24f, 24f), texture);
                MpUI.DrawRotatedLine(new Vector2(pointX, rect.center.y), TimelineHeight, 20f, 90f, ev.color);

                if (Mouse.IsOver(rect) && Math.Abs(mouseX - pointX) < 10)
                {
                    mouseX     = pointX;
                    mouseEvent = ev;
                }
            }

            if (Mouse.IsOver(rect))
            {
                float mouseProgress = (mouseX - rect.xMin) / rect.width;
                int   mouseTimer    = timerStart + (int)(timeLen * mouseProgress);

                MpUI.DrawRotatedLine(new Vector2(mouseX, rect.center.y), TimelineHeight, 15f, 90f, Color.blue);

                if (Event.current.type == EventType.MouseUp)
                {
                    TickPatch.SetSimulation(mouseTimer, canESC: true);

                    if (mouseTimer < TickPatch.Timer)
                    {
                        ClientJoiningState.ReloadGame(Multiplayer.session.dataSnapshot.mapData.Keys.ToList(), false, Multiplayer.GameComp.asyncTime);
                    }
                }

                if (Event.current.isMouse)
                {
                    Event.current.Use();
                }

                string tooltip = $"Tick {mouseTimer}";
                if (mouseEvent != null)
                {
                    tooltip = $"{mouseEvent.name}\n{tooltip}";
                }

                const int TickTipId = 215462143;

                TooltipHandler.TipRegion(rect, new TipSignal(tooltip, TickTipId));
                // Remove delay between the mouseover and showing
                if (TooltipHandler.activeTips.TryGetValue(TickTipId, out ActiveTip tip))
                {
                    tip.firstTriggerTime = 0;
                }
            }

            if (TickPatch.Simulating)
            {
                float pct         = (TickPatch.simulating.target.Value - timerStart) / (float)timeLen;
                float simulateToX = rect.xMin + rect.width * pct;
                MpUI.DrawRotatedLine(new Vector2(simulateToX, rect.center.y), TimelineHeight, 15f, 90f, Color.yellow);
            }
        }
Пример #13
0
        static void DoButtons()
        {
            float x = UI.screenWidth - btnWidth - btnMargin;
            float y = btnMargin;

            var session = Multiplayer.session;

            if (session != null && !Multiplayer.IsReplay)
            {
                var btnRect   = new Rect(x, y, btnWidth, btnHeight);
                var chatColor = session.players.Any(p => p.status == PlayerStatus.Desynced) ? "#ff5555" : "#dddddd";
                var hasUnread = session.hasUnread ? "*" : "";
                var chatLabel = $"{"MpChatButton".Translate()} <color={chatColor}>({session.players.Count})</color>{hasUnread}";

                TooltipHandler.TipRegion(btnRect, "MpChatHotkeyInfo".Translate() + " " + MultiplayerStatic.ToggleChatDef.MainKeyLabel);

                if (Widgets.ButtonText(btnRect, chatLabel))
                {
                    ChatWindow.OpenChat();
                }

                if (!TickPatch.Simulating)
                {
                    IndicatorInfo(out Color color, out string text, out bool slow);

                    var indRect    = new Rect(btnRect.x - 25f - 5f + 6f / 2f, btnRect.y + 6f / 2f, 19f, 19f);
                    var biggerRect = new Rect(btnRect.x - 25f - 5f + 2f / 2f, btnRect.y + 2f / 2f, 23f, 23f);

                    if (slow && Widgets.ButtonInvisible(biggerRect))
                    {
                        TickPatch.SetSimulation(toTickUntil: true, canESC: true);
                    }

                    Widgets.DrawRectFast(biggerRect, new Color(color.r * 0.6f, color.g * 0.6f, color.b * 0.6f));
                    Widgets.DrawRectFast(indRect, color);
                    TooltipHandler.TipRegion(indRect, new TipSignal(text, 31641624));
                }

                y += btnHeight;
            }

            if (Multiplayer.ShowDevInfo && Multiplayer.WriterLog != null)
            {
                if (Widgets.ButtonText(new Rect(x, y, btnWidth, btnHeight), $"Write ({Multiplayer.WriterLog.NodeCount})"))
                {
                    Find.WindowStack.Add(Multiplayer.WriterLog);
                }

                y += btnHeight;
                if (Widgets.ButtonText(new Rect(x, y, btnWidth, btnHeight), $"Read ({Multiplayer.ReaderLog.NodeCount})"))
                {
                    Find.WindowStack.Add(Multiplayer.ReaderLog);
                }

                y += btnHeight;
            }

            if (Multiplayer.Client != null && Multiplayer.GameComp.debugMode)
            {
                Text.Font   = GameFont.Tiny;
                Text.Anchor = TextAnchor.MiddleCenter;
                Widgets.Label(new Rect(x, y, btnWidth, 30f), $"Debug mode");
                Text.Anchor = TextAnchor.UpperLeft;
                Text.Font   = GameFont.Small;
            }
        }