Skip to content

Commit

Permalink
-Renamed Serialization and Deserialization methods
Browse files Browse the repository at this point in the history
-Changed MPUserDataBlock constructor to use string.empty
-Fixed Hashchecks to use strings, byte arrays were failing even when they were the same.
-Changed HasMPMods to HighestLevelOfMPMods, and added checks to client for when joining a vanilla host.
-Changes to kicked Error Messages
  • Loading branch information
Nagord committed Sep 3, 2022
1 parent 73c17e9 commit 300311e
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 22 deletions.
120 changes: 101 additions & 19 deletions PulsarModLoader/MPModChecks/MPModCheckManager.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
using ExitGames.Client.Photon;
using HarmonyLib;
using PulsarModLoader.Patches;
using PulsarModLoader.Utilities;
using Steamworks;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection.Emit;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;
using Hashtable = ExitGames.Client.Photon.Hashtable;
using Logger = PulsarModLoader.Utilities.Logger;
Expand All @@ -30,11 +33,11 @@ public void RefreshData()

private void UpdateLobbyModList() //Update Photon Lobby Listing with mod list
{
if (PhotonNetwork.isMasterClient && PhotonNetwork.inRoom)
if (PhotonNetwork.isMasterClient && PhotonNetwork.inRoom && PLNetworkManager.Instance != null)
{
Room room = PhotonNetwork.room;
Hashtable customProperties = room.CustomProperties;
customProperties["modList"] = GetModListForLobbyListing();
customProperties["modList"] = SerializeHashlessUserData();
room.SetCustomProperties(customProperties);
}
}
Expand All @@ -45,7 +48,7 @@ private void UpdateLobbyModList() //Update Photon Lobby Listing with mod list

private Dictionary<PhotonPlayer, MPUserDataBlock> NetworkedPeersModLists = new Dictionary<PhotonPlayer, MPUserDataBlock>();

private bool ServerHasMPMods = false;
private int HighestLevelOfMPMods = 0;

public MPUserDataBlock GetNetworkedPeerMods(PhotonPlayer Photonplayer)
{
Expand All @@ -69,14 +72,15 @@ public void RemoveNetworkedPeerMods(PhotonPlayer Photonplayer)

private List<PulsarMod> GetMPModList()
{
HighestLevelOfMPMods = 0;
List<PulsarMod> modList = new List<PulsarMod>();
foreach (PulsarMod mod in ModManager.Instance.GetAllMods())
{
if (mod.MPFunctionality != (int)MPFunction.HideFromServerList)
{
if (mod.MPFunctionality > (int)MPFunction.HostRequired)
if (mod.MPFunctionality >= (int)MPFunction.HostRequired && mod.MPFunctionality > HighestLevelOfMPMods)
{
ServerHasMPMods = true;
HighestLevelOfMPMods = (mod.MPFunctionality);
}
modList.Add(mod);
}
Expand Down Expand Up @@ -109,7 +113,7 @@ private void UpdateMyModList()
Logger.Info("Finished Building MyModList, time elapsted: " + stopwatch.ElapsedMilliseconds.ToString());
}

public byte[] GetModListForLobbyListing()
public byte[] SerializeHashlessUserData()
{
MemoryStream dataStream = new MemoryStream();
using (BinaryWriter writer = new BinaryWriter(dataStream))
Expand All @@ -130,7 +134,29 @@ public byte[] GetModListForLobbyListing()
return dataStream.ToArray();
}

public static MPUserDataBlock GetModListFromLobbyListingData(byte[] byteData)
public byte[] SerializeHashfullUserData()
{
MemoryStream dataStream = new MemoryStream();
using (BinaryWriter writer = new BinaryWriter(dataStream))
{
//Datastream storage structure:
writer.Write(Patches.GameVersion.PMLVersion); //--Header--
writer.Write(MyModList.Length); //string PMLVersion
for (int i = 0; i < MyModList.Length; i++) //int modcount
{ //
MPModDataBlock dataBlock = MyModList[i]; //--ModData--
writer.Write(dataBlock.ModName); //string mod name
writer.Write(dataBlock.HarmonyIdentifier); //string harmony ident
writer.Write(dataBlock.Version); //string mod version
writer.Write((byte)dataBlock.MPFunction); //byte MPFunction
writer.Write(dataBlock.ModID); //string ModID
writer.Write(dataBlock.Hash); //byte[] Hash
}
}
return dataStream.ToArray();
}

public static MPUserDataBlock DeserializeHashlessMPUserData(byte[] byteData)
{
MemoryStream memoryStream = new MemoryStream(byteData);
memoryStream.Position = 0;
Expand Down Expand Up @@ -158,6 +184,39 @@ public static MPUserDataBlock GetModListFromLobbyListingData(byte[] byteData)
Logger.Info($"Failed to read mod list from lobby listing data.\n{ex.Message}");
}
}
Logger.Info("Failed to read mod list from hashless data, returning null.");
return UserData;
}

public static MPUserDataBlock DeserializeHashfullMPUserData(byte[] byteData)
{
MemoryStream memoryStream = new MemoryStream(byteData);
memoryStream.Position = 0;
MPUserDataBlock UserData = null;
using (BinaryReader reader = new BinaryReader(memoryStream))
{
try
{
string PMLVersion = reader.ReadString();
int ModCount = reader.ReadInt32();
MPModDataBlock[] ModList = new MPModDataBlock[ModCount];
for (int i = 0; i < ModCount; i++)
{
string modname = reader.ReadString();
string HarmonyIdent = reader.ReadString();
string ModVersion = reader.ReadString();
MPFunction MPFunction = (MPFunction)reader.ReadByte();
string ModID = reader.ReadString();
byte[] Hash = reader.ReadBytes(32);
ModList[i] = new MPModDataBlock(HarmonyIdent, modname, ModVersion, MPFunction, ModID, Hash);
}
UserData = new MPUserDataBlock(PMLVersion, ModList);
}
catch (Exception ex)
{
Logger.Info($"Failed to read mod list from lobby listing data.\n{ex.Message}");
}
}
Logger.Info("Failed to read mod list from lobby listing data, returning null.");
return UserData;
}
Expand All @@ -176,7 +235,7 @@ private static MPUserDataBlock GetHostModList(RoomInfo room)
{
if (room.CustomProperties.ContainsKey("modList"))
{
return GetModListFromLobbyListingData((byte[])room.CustomProperties["modList"]);
return DeserializeHashlessMPUserData((byte[])room.CustomProperties["modList"]);
}
return new MPUserDataBlock();
}
Expand All @@ -198,6 +257,20 @@ private static void KickClient(PhotonPlayer client)
public bool ClientClickJoinRoom(RoomInfo room)
{
MPUserDataBlock HostModData = GetHostModList(room);
if(HostModData.PMLVersion == string.Empty)
{
if(HighestLevelOfMPMods >= (int)MPFunction.HostRequired)
{
PLNetworkManager.Instance.MainMenu.AddActiveMenu(new PLErrorMessageMenu($"<color=red>FAILED TO JOIN CREW!</color>\nMods requiring host installation or higher have been installed locally"));

Logger.Info("Mods requiring host installation or higher have been installed locally");
return false;
}
else
{
return true;
}
}
MPModDataBlock[] HostModList = HostModData.ModData;

string HostModListString = GetModListAsString(HostModList);
Expand Down Expand Up @@ -302,7 +375,6 @@ public void HostOnClientJoined(PhotonPlayer Player)
string outdatedMods = string.Empty;
string incorrectHashMods = string.Empty;
Logger.Info($"Starting Serverside Mod check");
Logger.Info($"Checking if client is missing required mods");

int localLength = MyModList.Length;
int clientLength = ClientMods.Length;
Expand All @@ -329,11 +401,11 @@ public void HostOnClientJoined(PhotonPlayer Player)
{
outdatedMods += $"\nLocal: {MyModList[a].ModName} {MyModList[a].Version} Client: {ClientMods[b].ModName} {ClientMods[b].Version}";
}
else if (MyModList[a].Hash != ClientMods[b].Hash) //if mod versions match but hash doesn't, add as kick reason
else if (Encoding.ASCII.GetString(MyModList[a].Hash) != Encoding.ASCII.GetString(ClientMods[b].Hash)) //if mod versions match but hash doesn't, add as kick reason
{
incorrectHashMods += $"\n{ClientMods[b].ModName}";
missingMods += $"\n{ClientMods[b].ModName}";
Logger.Info("Client has bad hash for " + MyModList[a].ModName);
Logger.Info($"Client has bad hash for {MyModList[a].ModName}. Local: {Encoding.ASCII.GetString(MyModList[a].Hash)} Client: {Encoding.ASCII.GetString(ClientMods[b].Hash)}");
}
}
}
Expand Down Expand Up @@ -370,21 +442,22 @@ public void HostOnClientJoined(PhotonPlayer Player)
string message = string.Empty;
if (missingMods != string.Empty)
{
message += $"\n<color=yellow>YOU ARE MISSING THE FOLLOWING REQUIRED MODS</color>{missingMods}";
message += $"\n<color=yellow>You are missing the following required mods</color>{missingMods}";
}
if (clientMPLimitedMods != string.Empty)
{
message += $"\n<color=yellow>YOU CANNOT JOIN WITH THE FOLLOWING MODS INSTALLED</color>{clientMPLimitedMods}";
message += $"\n<color=yellow>You cannot join without the following mods installed</color>{clientMPLimitedMods}";
}
if (outdatedMods != string.Empty)
{
message += $"\n<color=yellow>THE FOLLOWING MOD VERSIONS DO NOT MATCH</color>{outdatedMods}";
message += $"\n<color=yellow>The following mod versions do not match</color>{outdatedMods}";
}
if (message != string.Empty)
{
PLNetworkManager.Instance.MainMenu.AddActiveMenu(new PLErrorMessageMenu($"<color=red>Failed to join crew!</color>{message}"));
ModMessageHelper.Instance.photonView.RPC("RecieveErrorMessage", Player, new object[] {$"<color=red>Failed to join crew!</color>{message}"});
KickClient(Player);

Logger.Info("Local mod list is not equal to Server mod list");
Logger.Info("Kicked client for failing mod check with the following message:" + message);
}
else
{
Expand All @@ -393,7 +466,7 @@ public void HostOnClientJoined(PhotonPlayer Player)
}
else //client wasn't found in mod list
{
if (ServerHasMPMods)
if (HighestLevelOfMPMods >= (int)MPFunction.All)
{
Utilities.Logger.Info("Didn't receive message or proper modlist. proceeding to kick PhotonPlayer");
string message = $"You have been disconnected for not having the mod loader installed";
Expand Down Expand Up @@ -439,7 +512,7 @@ static void Postfix(PhotonPlayer client)
}
}

[HarmonyPatch(typeof(PLServer), "VerifyClient")] //Client sends mod info as early as possible during connection,
[HarmonyPatch(typeof(PLServer), "VerifyClient")] //Client sends mod info as early as possible during connection
class ClientJoinPatch
{
static void Postfix(PhotonPlayer player, PhotonMessageInfo pmi)
Expand All @@ -451,12 +524,21 @@ static void Postfix(PhotonPlayer player, PhotonMessageInfo pmi)
Logger.Info("Sending 'RecieveConnectionMessage' RPC");
ModMessageHelper.Instance.photonView.RPC("ReceiveConnectionMessage", pmi.sender, new object[]
{
MPModCheckManager.Instance.GetModListForLobbyListing()
MPModCheckManager.Instance.SerializeHashfullUserData()
});
}
player.Verified = true;
}
}
}

[HarmonyPatch(typeof(PLServer), "RemovePlayer")]
class RemovePlayerPatch
{
static void Postfix(PhotonPlayer inPlayer)
{
Instance.RemoveNetworkedPeerMods(inPlayer);
}
}
}
}
2 changes: 1 addition & 1 deletion PulsarModLoader/MPModChecks/MPUserDataBlock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public MPUserDataBlock(string PMLVersion, MPModDataBlock[] ModData)

public MPUserDataBlock()
{
this.PMLVersion = "";
this.PMLVersion = string.Empty;
this.ModData = null;
}

Expand Down
2 changes: 1 addition & 1 deletion PulsarModLoader/ModMessage/ModMessageHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public void RecieveErrorMessage(string message)
[PunRPC]
public void ReceiveConnectionMessage(byte[] recievedData, PhotonMessageInfo pmi) //Pong
{
MPUserDataBlock userDataBlock = MPModCheckManager.GetModListFromLobbyListingData(recievedData);
MPUserDataBlock userDataBlock = MPModCheckManager.DeserializeHashfullMPUserData(recievedData);
Logger.Info($"recieved modlist and connection info from user with the following info:\nPMLVersion: {userDataBlock.PMLVersion}\nModlist:{MPModCheckManager.GetModListAsString(userDataBlock.ModData)}");
MPModCheckManager.Instance.AddNetworkedPeerMods(pmi.sender, userDataBlock);
}
Expand Down
2 changes: 1 addition & 1 deletion PulsarModLoader/Patches/PhotonProperties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ private static void Prefix(RoomOptions roomOptions)
});

//MPModCheck
roomOptions.CustomRoomProperties["modList"] = MPModChecks.MPModCheckManager.Instance.GetModListForLobbyListing();
roomOptions.CustomRoomProperties["modList"] = MPModChecks.MPModCheckManager.Instance.SerializeHashlessUserData();
}

public static void UpdatePlayerList()
Expand Down

0 comments on commit 300311e

Please sign in to comment.