Esempio n. 1
0
        // This function is run before all mods are finished loading.
        protected override void OnPreInitialize()
        {
            // The order of these is important for some things, others not. I'll document what each one does eventually.

            // Load the embedded DLL which has unsafe code. Allows duck game to compile this source and still use unsafe code.
            AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

            // Get the profile core. Its not supposed to be accessed outside the main thread but I won't tell if you won't.
            ProfilesCore profilecore = typeof(Profiles).GetField("_core", BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public).GetValue(null) as ProfilesCore;

            // Normally generates 4 MPPlayer profiles, now does 8
            Injection.install(2, "InitDefaultProfiles", "InitDefaultProfiles");

            // Add our extra personas to the table
            PersonaEdits._personas();

            // Replace the get_defaultProfiles() with one that handles the extra 4 player teams
            InputProfileCoreEdits.defaultProfiles();

            // Duck Game would just check which profiles were past the first 4 and decide they were custom, changed to skip the first 8
            ProfilesCoreEdits.allCustomProfiles();

            // Generates the default Player1-Player8 Profiles now
            Injection.install(5, "Initialize", "Initialize");

            // Returns the first 8 profiles as defaults
            Injection.install(5, "IsDefault", "IsDefault");

            // Generates the extra 4 GenericControllers for the added players
            InputEdits.Initialize();

            // Invokes the new InitDefaultProfiles(). This may not be needed as it may get injected before it gets run the first time. I'll check
            InputEdits.InitDefaultProfiles();

            // Generates 8 Netduck profiles instead of the default 4
            Injection.install(1, "RecreateProfiles", "RecreateProfiles");

            // Allows the host to select between 2 and 8 players maximum for their lobby
            TeamSelect2Edits.OnlineSettings();

            // Add the extra 4 default teams that will be used for the extra players
            TeamsCoreEdits.Initialize();

            // Generate new profile boxes for the lobby level. Also tweaks the camera for it. Will make it not stretched at some point
            Injection.install(4, "UpdateModifierStatus", "UpdateModifierStatus");

            // DoInvite would call Host(4, LobbyType.FriendsOnly) so we change it to 8 max players
            Injection.install(4, "DoInvite", "DoInvite");

            // Would only purge the first 4 boxes by default. Now purges all 8
            Injection.install(4, "FillMatchmakingProfiles", "FillMatchmakingProfiles");

            // ClearTeam() would return if the index was >=4. We need it to be >=8 for the extra teams
            Injection.install(4, "ClearTeam", "ClearTeam");

            // Return the extra inputprofiles for the extra teams
            Injection.install(6, "ControllerNumber", "ControllerNumber");

            // Trying to detour ConfirmTeamSelection was proving a nightmare so I did this garbage solution.
            // A check at the bottom of ConfirmTeamSelection was returning incorrectly due to the extra teams and crashing
            // When I tried injecting my new method, it was never called for some reason. Not sure why, probably due to instancing
            // To deal with this I edited FilterTeam which gets called at the start of ConfirmTeamSelection and did a check where
            // if the _desiredteamselection was <= 7 then set it to 0. This meant the check that was crashing returned correctly
            // and as far as I can tell there aren't any noticeable side effects. Will find better method eventually.
            Injection.install(6, "FilterTeam", "FilterTeam");

            // Because inline removes TeamSelect2.OnNetworkConnecting, I have to inject the methods that called it to change them
            Injection.install(3, "JoinLocalDuck", "JoinLocalDuck");
            Injection.install(3, "OnMessageFromNewClient", "OnMessageFromNewClient");
            Injection.install(3, "OnMessage", "OnMessage");

            // New NMChangeSlot net message as the old one only handled 4 parameters and we need 8.
            Injection.install(3, "ChangeSlotSettings", "ChangeSlotSettings");

            // DuckNetwork.Update calls Host( 4, LobbyType.FriendsOnly ) on inviting someone. Since performance would be garbage reflecting all
            // the private variables, we detour host instead.
            Injection.install(3, "Host", "Host");

            // Only would clear custom data for the first 4 profiles so now it clears all 8
            Injection.install(3, "Join", "Join");

            // Adds our new netmessage to the list of netmessage types so that the game doesn't crash when it encounters it
            DuckNetworkEdits.UpdateNetmessageTypes();

            // netProfileIndex determines how many bits are used to store it. Since we need to store up to the value of seven, we need 3 bits
            // rather than the default 2. Best way I thought would be change it when the ducks get added but idk.
            Injection.install(8, "Add", "AddReplace");

            // Method to inject a call into LevelUpdateChange so that it calls our varient which then checks for rock scoreboard
            // then calls our patched Initialize.
            LevelEdits.UpdateLevelChange();

            // NMVoteToSkip checks whether the player index is greater than 3 and discards it if it is. We want it to be discarded when greater
            // than 7.
            NMVoteToSkipEdits.Activate();

            // Change the get method for determining if a room if on the right or left to Value % 2. Will return 1 if on the right.
            // We inject pure assembly so THIS WILL BREAK EVENTUALLY.
            ProfileBox2Edits.rightRoomCorrection();

            // Injection.install(0, "UpdateQuack", "injectionMethod1"); // Disables quack to check everything loaded right

            // Base
            base.OnPreInitialize();
        }
        public static void UpdateLevelChangeReplace()
        {
            Type type = typeof(Level);

            Assembly assembly        = Assembly.GetAssembly(type);
            Type     HUDtype         = assembly.GetType("DuckGame.HUD");
            dynamic  HUDClearCorners = HUDtype.GetMethod("ClearCorners", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);

            Type    ConnectionStatusUIType = assembly.GetType("DuckGame.ConnectionStatusUI");
            dynamic ConnectionStatusUIShow = ConnectionStatusUIType.GetMethod("Show", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
            dynamic ConnectionStatusUIHide = ConnectionStatusUIType.GetMethod("Hide", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);

            FieldInfo _readyForTransitionField = type.GetField("_readyForTransition", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
            dynamic   _readyForTransition      = _readyForTransitionField.GetValue(Level.current);

            if (Level.core.nextLevel != null)
            {
                FieldInfo _sentLevelChangeField = type.GetField("_sentLevelChange", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
                dynamic   _sentLevelChange      = _sentLevelChangeField.GetValue(Level.current);

                FieldInfo _networkStatusField = type.GetField("_networkStatus", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
                dynamic   _networkStatus      = _networkStatusField.GetValue(Level.current);

                if (Level.core.currentLevel is IHaveAVirtualTransition && Level.core.nextLevel is IHaveAVirtualTransition && !(Level.core.nextLevel is TeamSelect2))
                {
                    VirtualTransition.GoVirtual();
                }
                if (Network.isActive && Level.activeLevel != null && !_sentLevelChange)
                {
                    //                    DevConsole.Log(DCSection.GhostMan, "|DGYELLOW|Performing level swap (" + (object)DuckNetwork.levelIndex + ")", -1);
                    GhostManager.context.Clear();
                    foreach (Profile profile in Profiles.active)
                    {
                        if (profile.connection != null)
                        {
                            profile.connection.manager.Reset();
                        }
                    }
                    if (Level.core.currentLevel is TeamSelect2 && !(Level.core.nextLevel is TeamSelect2))
                    {
                        DuckNetwork.ClosePauseMenu();
                    }
                    if (!(Level.core.currentLevel is TeamSelect2) && Level.core.nextLevel is TeamSelect2)
                    {
                        DuckNetwork.ClosePauseMenu();
                    }
                    if (Network.isServer)
                    {
                        ++DuckNetwork.levelIndex;
                        DuckNetwork.compressedLevelData = (MemoryStream)null;
                        //                        DevConsole.Log(DCSection.GhostMan, "|DGYELLOW|Incrementing level index (" + (object)((int)DuckNetwork.levelIndex - 1) + "->" + (object)DuckNetwork.levelIndex + ")", -1);
                        uint   varChecksum      = 0;
                        bool   varNeedsChecksum = false;
                        string lev = "";
                        if (!(Level.core.currentLevel is TeamSelect2) && Level.core.nextLevel is TeamSelect2)
                        {
                            lev = "@TEAMSELECT";
                        }
                        else if (Level.core.nextLevel is GameLevel)
                        {
                            GameLevel nextLevel = Level.core.nextLevel as GameLevel;
                            if (nextLevel.customLevel)
                            {
                                varNeedsChecksum = true;
                                varChecksum      = nextLevel.checksum;
                                DuckNetwork.compressedLevelData = new MemoryStream(nextLevel.compressedData, 0, nextLevel.compressedData.Length, false, true);
                            }
                            lev = nextLevel.level;
                        }

                        else if (!(Level.core.nextLevel is TeamSelect2) && !(Level.core.nextLevel is GameLevel) && !(Level.core.nextLevel is RockScoreboard))
                        {
                            lev = "@ROCKINTRO"; // This need correcting at some point and probably will break things. Must get the internal type
                        }
                        else if (Level.core.nextLevel is RockScoreboard)
                        {
                            GhostManager.context.SetGhostIndex((NetIndex16)1);
                            lev = (Level.core.nextLevel as RockScoreboard).mode != ScoreBoardMode.ShowScores ? (!(Level.core.nextLevel as RockScoreboard).afterHighlights ? "@ROCKTHROW|SHOWWINNER" : "@ROCKTHROW|SHOWEND") : "@ROCKTHROW|SHOWSCORE";
                        }
                        if (lev != "")
                        {
                            foreach (Profile profile in DuckNetwork.profiles)
                            {
                                if (profile.connection != null)
                                {
                                    profile.connection.manager.ClearAllMessages();
                                    if (Level.core.nextLevel is GameLevel && (Level.core.nextLevel as GameLevel).level == "RANDOM")
                                    {
                                        Send.Message((NetMessage) new NMSwitchLevelRandom(lev, DuckNetwork.levelIndex, (ushort)(int)GhostManager.context.currentGhostIndex, (Level.core.nextLevel as GameLevel).seed), NetMessagePriority.ReliableOrdered, profile.connection);
                                    }
                                    else
                                    {
                                        Send.Message((NetMessage) new NMSwitchLevel(lev, DuckNetwork.levelIndex, (ushort)(int)GhostManager.context.currentGhostIndex, varNeedsChecksum, varChecksum), NetMessagePriority.ReliableOrdered, profile.connection);
                                    }
                                }
                            }
                        }
                    }
                    _sentLevelChange = true;
                }
                if (!VirtualTransition.active)
                {
                    Level.InitChanceGroups();
                    DamageManager.ClearHits();
                    Layer.ResetLayers();
                    HUDClearCorners.Invoke(null, null);
                    if (Level.core.currentLevel != null)
                    {
                        Level.core.currentLevel.Terminate();
                    }
                    Level.core.currentLevel = Level.core.nextLevel;
                    Level.core.nextLevel    = (Level)null;
                    Layer.lighting          = false;
                    SequenceItem.sequenceItems.Clear();
                    GC.Collect(1, GCCollectionMode.Optimized);
                    foreach (Profile profile in Profiles.active)
                    {
                        profile.duck = (Duck)null;
                    }
                    SFX.StopAllSounds();

                    if (Level.core.currentLevel is RockScoreboard)
                    {
                        LevelEdits.DoInitialize();
                    }
                    else
                    {
                        Level.core.currentLevel.DoInitialize();
                    }

                    if (MonoMain.pauseMenu != null)
                    {
                        Level.core.currentLevel.AddThing((Thing)MonoMain.pauseMenu);
                    }
                    if (Network.isActive && DuckNetwork.duckNetUIGroup != null && DuckNetwork.duckNetUIGroup.open)
                    {
                        Level.core.currentLevel.AddThing((Thing)DuckNetwork.duckNetUIGroup);
                    }
                    if (Recorder.globalRecording != null)
                    {
                        Recorder.globalRecording.UpdateAtlasFile();
                    }
                    _networkStatus = NetLevelStatus.WaitingForDataTransfer;
                    if (!(Level.core.currentLevel is IOnlyTransitionIn) && Level.core.currentLevel is IHaveAVirtualTransition && (!(Level.core.currentLevel is TeamSelect2) && VirtualTransition.isVirtual))
                    {
                        if (_readyForTransition)
                        {
                            VirtualTransition.GoUnVirtual();
                            DuckGame.Graphics.fade = 1f;
                        }
                        else
                        {
                            Level.current._waitingOnTransition = true;
                            if (Network.isActive)
                            {
                                ConnectionStatusUIShow.Invoke(null, null);
                            }
                        }
                    }
                }
            }
            if (!Level.current._waitingOnTransition || !_readyForTransition)
            {
                return;
            }
            Level.current._waitingOnTransition = false;
            VirtualTransition.GoUnVirtual();
            if (!Network.isActive)
            {
                return;
            }
            ConnectionStatusUIHide.Invoke(null, null);
        }