public static Profile JoinLocalDuck(InputProfile input) { int num = 1; foreach (Profile profile in DuckNetwork.profiles) { if (profile.connection == DuckNetwork.localConnection) { ++num; } } string name = Network.activeNetwork.core.GetLocalName(); if (num > 1) { name = name + "(" + num.ToString() + ")"; } //Invoke the private method. Hope its not too slow Profile profile1 = (Profile)createProfile.Invoke(null, new object[] { DuckNetwork.localConnection, name, -1, input, false, false, true }); if (profile1 == null) { return((Profile)null); } profile1.networkStatus = !Network.isClient ? DuckNetStatus.Connected : DuckNetStatus.Connecting; // Our new OnNetworkConnecting which should bloody work TeamSelect2Edits.OnNetworkConnecting(profile1); DuckNetwork.SendNewProfile(profile1, DuckNetwork.localConnection, false); return(profile1); }
// 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 OnMessage(NetMessage m) { if (m is NMJoinDuckNetwork) { // DevConsole.Log(DCSection.DuckNet, "|DGYELLOW|Join message", -1); if (DuckNetwork.status == DuckNetStatus.Disconnected) { return; } } if (m == null) { Main.codeNumber = 13371; } UIMatchmakingBox.pulseNetwork = true; if (DuckNetwork.GetProfiles(m.connection).Count == 0 && m.connection != Network.host) { Main.codeNumber = 13372; NetMessage msg = DuckNetwork.OnMessageFromNewClient(m); if (msg == null) { return; } Send.Message(msg, m.connection); } else { if (DuckNetwork.HandleCoreConnectionMessages(m) || DuckNetwork.status == DuckNetStatus.Disconnecting) { return; } Main.codeNumber = 13373; foreach (Profile profile in DuckNetwork.GetProfiles(m.connection)) { if (profile.networkStatus == DuckNetStatus.Disconnecting || profile.networkStatus == DuckNetStatus.Disconnected || profile.networkStatus == DuckNetStatus.Failure) { return; } } Main.codeNumber = m.typeIndex; if (Network.isServer) { if (m is NMLateJoinDuckNetwork) { if (!(Level.current is TeamSelect2)) { Send.Message(new NMGameInProgress(), NetMessagePriority.ReliableOrdered, m.connection); } else { NMLateJoinDuckNetwork lateJoinDuckNetwork = m as NMLateJoinDuckNetwork; // DevConsole.Log(DCSection.DuckNet, "|DGYELLOW|Late join attempt from " + lateJoinDuckNetwork.name, -1); // Profile profile = DuckNetwork.CreateProfile(m.connection, lateJoinDuckNetwork.name, (int)lateJoinDuckNetwork.duckIndex, (InputProfile)null, false, false, false); Profile profile = (Profile)createProfile.Invoke(null, new object[] { m.connection, lateJoinDuckNetwork.name, (int)lateJoinDuckNetwork.duckIndex, null, false, false, false }); if (profile != null) { profile.networkStatus = DuckNetStatus.Connected; TeamSelect2Edits.OnNetworkConnecting(profile); DuckNetwork.SendNewProfile(profile, m.connection, true); } else { Send.Message(new NMServerFull(), NetMessagePriority.ReliableOrdered, m.connection); } } } else if (m is NMJoinedDuckNetwork) { foreach (Profile profile in DuckNetwork.GetProfiles(m.connection)) { // DevConsole.Log(DCSection.DuckNet, "|LIME|" + profile.name + " Has joined the DuckNet", -1); Send.Message(new NMSwitchLevel("@TEAMSELECT", DuckNetwork.levelIndex, (ushort)0, false, 0U), m.connection); } } else if (m is NMClientLoadedLevel) { if ((m as NMClientLoadedLevel).levelIndex == DuckNetwork.levelIndex) { m.connection.wantsGhostData = (m as NMClientLoadedLevel).levelIndex; } else { ;// DevConsole.Log(DCSection.DuckNet, "|DGRED|" + m.connection.identifier + " LOADED WRONG LEVEL! (" + DuckNetwork.levelIndex + " VS " + (m as NMClientLoadedLevel).levelIndex + ")", -1); } } else if (m is NMSetTeam) { NMSetTeam nmSetTeam = m as NMSetTeam; if (nmSetTeam.duck < 0 || nmSetTeam.duck >= 8) { return; } Profile profile = DuckNetwork.profiles[nmSetTeam.duck]; if (profile.connection == null || profile.team == null) { return; } profile.team = Teams.all[nmSetTeam.team]; if (!DuckNetwork.OnTeamSwitch(profile)) { return; } Send.MessageToAllBut(new NMSetTeam(nmSetTeam.duck, nmSetTeam.team), NetMessagePriority.ReliableOrdered, m.connection); } else { if (!(m is NMSpecialHat)) { return; } NMSpecialHat nmSpecialHat = m as NMSpecialHat; Team t = Team.Deserialize(nmSpecialHat.GetData()); foreach (Profile profile in DuckNetwork.profiles) { if ((long)profile.steamID == (long)nmSpecialHat.link) { if (t != null) { Team.MapFacade(profile.steamID, t); } else { Team.ClearFacade(profile.steamID); } Send.MessageToAllBut(new NMSpecialHat(t, profile.steamID), NetMessagePriority.ReliableOrdered, m.connection); } } } } else if (m is NMSpecialHat) { NMSpecialHat nmSpecialHat = m as NMSpecialHat; Team t = Team.Deserialize(nmSpecialHat.GetData()); foreach (Profile profile in DuckNetwork.profiles) { if ((long)profile.steamID == (long)nmSpecialHat.link) { if (t != null) { Team.MapFacade(profile.steamID, t); } else { Team.ClearFacade(profile.steamID); } } } } else if (m is NMJoinDuckNetwork) { NMRemoteJoinDuckNetwork remoteJoinDuckNetwork = m as NMRemoteJoinDuckNetwork; if (remoteJoinDuckNetwork == null) { // DevConsole.Log(DCSection.DuckNet, "|LIME|Connection with host was established!", -1); NMJoinDuckNetwork nmJoinDuckNetwork = m as NMJoinDuckNetwork; _core.status = DuckNetStatus.Connected; if (DuckNetwork.profiles[nmJoinDuckNetwork.duckIndex].connection == DuckNetwork.localConnection) { DuckNetwork.profiles[nmJoinDuckNetwork.duckIndex].networkStatus = DuckNetStatus.Connected; } else { // Profile profile = DuckNetwork.CreateProfile(DuckNetwork.localConnection, Network.activeNetwork.core.GetLocalName(), (int)nmJoinDuckNetwork.duckIndex, UIMatchmakingBox.matchmakingProfiles.Count > 0 ? UIMatchmakingBox.matchmakingProfiles[0].inputProfile : InputProfile.DefaultPlayer1, Teams.core.extraTeams.Count > 0, false, false); Profile profile = (Profile)createProfile.Invoke(null, new object[] { DuckNetwork.localConnection, Network.activeNetwork.core.GetLocalName(), (int)nmJoinDuckNetwork.duckIndex, UIMatchmakingBox.matchmakingProfiles.Count > 0 ? UIMatchmakingBox.matchmakingProfiles[0].inputProfile : InputProfile.DefaultPlayer1, Teams.core.extraTeams.Count > 0, false, false }); _core.localDuckIndex = nmJoinDuckNetwork.duckIndex; profile.flippers = Profile.CalculateLocalFlippers(); profile.networkStatus = DuckNetStatus.WaitingForLoadingToBeFinished; } } else { NetworkConnection networkConnection = remoteJoinDuckNetwork.connection; Main.codeNumber = 133701; if (remoteJoinDuckNetwork.identifier == "SERVER") { Main.codeNumber = 133702; // Profile profile1 = DuckNetwork.CreateProfile(networkConnection, remoteJoinDuckNetwork.name, (int)remoteJoinDuckNetwork.duckIndex, (InputProfile)null, remoteJoinDuckNetwork.hasCustomHats, false, false); Profile profile1 = (Profile)createProfile.Invoke(null, new object[] { networkConnection, remoteJoinDuckNetwork.name, (int)remoteJoinDuckNetwork.duckIndex, null, remoteJoinDuckNetwork.hasCustomHats, false, false }); profile1.flippers = remoteJoinDuckNetwork.flippers; profile1.team = Teams.all[remoteJoinDuckNetwork.team]; if (_core.hostDuckIndex == -1) { _core.hostDuckIndex = remoteJoinDuckNetwork.duckIndex; } Main.codeNumber = 133703; bool flag = false; foreach (Profile profile2 in DuckNetwork.GetProfiles(networkConnection)) { if (profile2 != profile1) { profile1.networkStatus = profile2.networkStatus; flag = true; break; } } Main.codeNumber = 133704; if (flag) { return; } profile1.networkStatus = DuckNetStatus.WaitingForLoadingToBeFinished; } else { Main.codeNumber = 133705; bool flag = false; DuckNetStatus duckNetStatus = DuckNetStatus.NeedsNotificationWhenReadyForData; foreach (Profile profile in DuckNetwork.GetProfiles(networkConnection)) { if (profile.connection.identifier == remoteJoinDuckNetwork.identifier) { networkConnection = profile.connection; flag = true; duckNetStatus = profile.networkStatus; break; } } Main.codeNumber = 133706; if (!flag) { networkConnection = Network.activeNetwork.core.AttemptConnection(remoteJoinDuckNetwork.identifier); if (networkConnection == null) { DuckNetwork.RaiseError(new DuckNetErrorInfo() { error = DuckNetError.InvalidConnectionInformation, message = "Invalid connection information (" + remoteJoinDuckNetwork.identifier + ")" }); return; } } Main.codeNumber = 133707; // Profile profile1 = DuckNetwork.CreateProfile(networkConnection, remoteJoinDuckNetwork.name, remoteJoinDuckNetwork.duckIndex, (InputProfile)null, remoteJoinDuckNetwork.hasCustomHats, false, false); Profile profile1 = (Profile)createProfile.Invoke(null, new object[] { networkConnection, remoteJoinDuckNetwork.name, remoteJoinDuckNetwork.duckIndex, (InputProfile)null, remoteJoinDuckNetwork.hasCustomHats, false, false }); profile1.team = Teams.all[remoteJoinDuckNetwork.team]; profile1.networkStatus = duckNetStatus; profile1.flippers = remoteJoinDuckNetwork.flippers; } } } else if (m is NMEndOfDuckNetworkData) { Send.Message(new NMJoinedDuckNetwork(), m.connection); foreach (Profile profile in DuckNetwork.profiles) { if (profile.connection == DuckNetwork.localConnection) { Send.Message(new NMProfileInfo(profile.networkIndex, profile.stats.unloyalFans, profile.stats.loyalFans)); } } } else if (m is NMEndOfGhostData) { if ((m as NMEndOfGhostData).levelIndex == DuckNetwork.levelIndex) { // DevConsole.Log(DCSection.DuckNet, "|DGGREEN|Received Host Level Information (" + (m as NMEndOfGhostData).levelIndex + ").", -1); Level.current.TransferComplete(m.connection); DuckNetwork.SendToEveryone(new NMLevelDataReady(DuckNetwork.levelIndex)); foreach (Profile profile in DuckNetwork.GetProfiles(DuckNetwork.localConnection)) { profile.connection.loadingStatus = (m as NMEndOfGhostData).levelIndex; } } else { ;// DevConsole.Log(DCSection.DuckNet, "|DGRED|Recieved data for wrong level.", -1); } } else if (m is NMSetTeam) { NMSetTeam nmSetTeam = m as NMSetTeam; if (nmSetTeam.duck < 0 || nmSetTeam.duck >= 8) { return; } Profile profile = DuckNetwork.profiles[nmSetTeam.duck]; if (profile.connection == null || profile.team == null) { return; } profile.team = Teams.all[nmSetTeam.team]; } else { if (!(m is NMTeamSetDenied)) { return; } NMTeamSetDenied nmTeamSetDenied = m as NMTeamSetDenied; if (nmTeamSetDenied.duck < 0 || nmTeamSetDenied.duck >= 8) { return; } Profile profile = DuckNetwork.profiles[nmTeamSetDenied.duck]; if (profile.connection != DuckNetwork.localConnection || profile.team == null || Teams.all.IndexOf(profile.team) != nmTeamSetDenied.team) { return; } openTeamSwitchDialogue.Invoke(null, new[] { profile }); } } }
public static NetMessage OnMessageFromNewClient(NetMessage m) { if (Network.isServer) { if (m is NMRequestJoin) { if (DuckNetwork.inGame) { return((NetMessage) new NMGameInProgress()); } NMRequestJoin nmRequestJoin = m as NMRequestJoin; // DevConsole.Log(DCSection.DuckNet, "|DGYELLOW|Join attempt from " + nmRequestJoin.name, -1); NMVersionMismatch.Type code = DuckNetwork.CheckVersion(nmRequestJoin.id); if (code != NMVersionMismatch.Type.Match) { // DevConsole.Log(DCSection.DuckNet, "|DGYELLOW|" + nmRequestJoin.name + " had a version mismatch.", -1); // return (NetMessage)new NMVersionMismatch(code, DG.version); return((NetMessage) new NMVersionMismatch(code, Assembly.GetEntryAssembly().GetName().Version.ToString())); } Type methodtype = typeof(DuckNetwork); MethodInfo createProfile = methodtype.GetMethod("CreateProfile", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); // Profile profile = DuckNetwork.CreateProfile(m.connection, nmRequestJoin.name, -1, (InputProfile)null, nmRequestJoin.hasCustomHats, nmRequestJoin.wasInvited, false); Profile profile = (Profile)createProfile.Invoke(null, new object[] { m.connection, nmRequestJoin.name, -1, (InputProfile)null, nmRequestJoin.hasCustomHats, nmRequestJoin.wasInvited, false }); if (profile == null) { // DevConsole.Log(DCSection.DuckNet, "|DGYELLOW|" + nmRequestJoin.name + " could not join, server is full.", -1); return((NetMessage) new NMServerFull()); } profile.flippers = nmRequestJoin.flippers; profile.networkStatus = DuckNetStatus.WaitingForLoadingToBeFinished; _core.status = DuckNetStatus.Connected; TeamSelect2Edits.OnNetworkConnecting(profile); DuckNetwork.SendNewProfile(profile, m.connection, false); // More slots so we need bigger method to handle them Send.Message(new NMChangeSlotsEdits((byte)DuckNetwork.profiles[0].slotType, (byte)DuckNetwork.profiles[1].slotType, (byte)DuckNetwork.profiles[2].slotType, (byte)DuckNetwork.profiles[3].slotType, (byte)DuckNetwork.profiles[4].slotType, (byte)DuckNetwork.profiles[5].slotType, (byte)DuckNetwork.profiles[6].slotType, (byte)DuckNetwork.profiles[7].slotType), m.connection); TeamSelect2.SendMatchSettings(m.connection, true); return((NetMessage)null); } if (m is NMMessageIgnored) { return((NetMessage)null); } } else { if (m is NMRequestJoin) { // DevConsole.Log(DCSection.DuckNet, "|DGYELLOW|Another computer has requested a matchmaking connection.", -1); return((NetMessage) new NMGameInProgress()); } if (m is NMMessageIgnored) { return((NetMessage)null); } } return((NetMessage) new NMMessageIgnored()); }