You get an error when calling a meeting caused by null reference in TOHE.ReportDeadBodyPatch.AfterReportTasks and TOHE.ReportDeadBodyPatch.Prefix
Error
Here is the error message and dump.
Error Message In Meeting
Error In Dump
[Info : TOHE] [00:47:39][ReportDeadBody]D1GQ => null
[Error : TOHE] [00:47:39][ReportDeadBodyPatch]System.NullReferenceException: Object reference not set to an instance of an object.
at TOHE.ReportDeadBodyPatch.AfterReportTasks(PlayerControl player, PlayerInfo target)
at TOHE.ReportDeadBodyPatch.Prefix(PlayerControl __instance, PlayerInfo target)
Possible Fix
I just added a few null checks to fix the errors, but I don't know if I broke anything process so y'all will have to overview it.
Fix 1 For TOHE.ReportDeadBodyPatch.AfterReportTasks
public static void AfterReportTasks(PlayerControl player, GameData.PlayerInfo target)
{
//=============================================
// Hereinafter, it is assumed that the button is confirmed to be pressed
//=============================================
Main.LastVotedPlayerInfo = null;
Main.GuesserGuessed.Clear();
Main.AllKillers.Clear();
foreach (var playerStates in Main.PlayerStates.Values.ToArray())
{
if (target == null) return;
playerStates.RoleClass?.OnReportDeadBody(player, target?.Object);
}
// Alchemist & Bloodlust
Alchemist.OnReportDeadBodyGlobal();
if (Aware.IsEnable) Aware.OnReportDeadBody();
if (target != null) Sleuth.OnReportDeadBody(player, target?.Object);
foreach (var pc in Main.AllPlayerControls)
{
if (target == null) return;
if (!Doppelganger.CheckDoppelVictim(pc.PlayerId) && !Murderer.CheckMurdererVictim(target.PlayerId))
{
// Update skins again, since players have different skins
// And can be easily distinguished from each other
if (Camouflage.IsCamouflage && Options.KPDCamouflageMode.GetValue() is 2 or 3)
{
Camouflage.RpcSetSkin(pc);
}
// Check shapeshift and revert skin to default
if (Main.CheckShapeshift.ContainsKey(pc.PlayerId))
{
Camouflage.RpcSetSkin(pc, RevertToDefault: true);
}
}
Logger.Info($"Player {pc?.Data?.PlayerName}: Id {pc.PlayerId} - is alive: {pc.IsAlive()}", "CheckIsAlive");
}
// Set meeting time
MeetingTimeManager.OnReportDeadBody();
// Clear all Notice players
NameNotifyManager.Reset();
// Update Notify Roles for Meeting
Utils.DoNotifyRoles(isForMeeting: true, NoCache: true, CamouflageIsForMeeting: true);
// Sync all settings on meeting start
_ = new LateTask(Utils.SyncAllSettings, 3f, "Sync all settings after report");
}
Fix 2 For TOHE.ReportDeadBodyPatch.Prefix
class ReportDeadBodyPatch
{
public static Dictionary<byte, bool> CanReport;
public static Dictionary<byte, List<GameData.PlayerInfo>> WaitReport = [];
public static bool Prefix(PlayerControl __instance, [HarmonyArgument(0)] GameData.PlayerInfo target)
{
if (GameStates.IsMeeting || GameStates.IsHideNSeek) return false;
if (target != null && EAC.RpcReportDeadBodyCheck(__instance, target))
{
Logger.Fatal("Eac patched the report body rpc", "ReportDeadBodyPatch");
return false;
}
if (Options.DisableMeeting.GetBool()) return false;
if (Options.CurrentGameMode == CustomGameMode.FFA) return false;
if (!CanReport[__instance.PlayerId])
{
if (target == null) return true;
WaitReport[__instance.PlayerId].Add(target);
Logger.Warn($"{__instance.GetNameWithRole().RemoveHtmlTags()} : Reporting is prohibited and will wait until it becomes possible", "ReportDeadBody");
return false;
}
Logger.Info($"{__instance.GetNameWithRole().RemoveHtmlTags()} => {target?.Object?.GetNameWithRole().RemoveHtmlTags() ?? "null"}", "ReportDeadBody");
foreach (var kvp in Main.PlayerStates)
{
var pc = Utils.GetPlayerById(kvp.Key);
kvp.Value.LastRoom = pc.GetPlainShipRoom();
}
if (!AmongUsClient.Instance.AmHost) return true;
try
{
// If the player is dead, the meeting is canceled
if (__instance.Data.IsDead) return false;
//=============================================
//Below, check if this meeting is allowed
//=============================================
var killer = target?.Object?.GetRealKiller();
var killerRole = killer?.GetCustomRole();
if (target == null) //Meeting
{
var playerRoleClass = __instance.GetRoleClass();
if (playerRoleClass.OnCheckStartMeeting(__instance) == false)
{
Logger.Info($"Player has role class: {playerRoleClass} - the start of the meeting has been cancelled", "ReportDeadBody");
return false;
}
}
if (target != null) // Report dead body
{
// Guessed player cannot report
if (Main.PlayerStates[target.PlayerId].deathReason == PlayerState.DeathReason.Gambled) return false;
// Check report bead body
foreach (var player in Main.PlayerStates.Values.ToArray())
{
var playerRoleClass = player.RoleClass;
if (player == null || playerRoleClass == null) continue;
if (playerRoleClass.OnCheckReportDeadBody(__instance, target, killer) == false)
{
Logger.Info($"Player has role class: {playerRoleClass} - is canceled the report", "ReportDeadBody");
return false;
}
}
// if Bait is killed, check the setting condition
if (!(target.Object.Is(CustomRoles.Bait) && Bait.BaitCanBeReportedUnderAllConditions.GetBool()))
{
// Comms Camouflage
if (Options.DisableReportWhenCC.GetBool() && Utils.IsActive(SystemTypes.Comms) && Camouflage.IsActive) return false;
}
//Check unreportable bodies
if (Main.UnreportableBodies.Contains(target.PlayerId))
{
__instance.Notify(Utils.ColorString(__instance.GetRoleColor(), GetString("BodyCannotBeReported")));
return false;
}
if (target.Object.Is(CustomRoles.Unreportable)) return false;
// 胆小鬼不敢报告
var tpc = Utils.GetPlayerById(target.PlayerId);
if (__instance.Is(CustomRoles.Oblivious))
{
if (!tpc.Is(CustomRoles.Bait) || (tpc.Is(CustomRoles.Bait) && Oblivious.ObliviousBaitImmune.GetBool())) /* && (target?.Object != null)*/
{
return false;
}
}
var tar = Utils.GetPlayerById(target.PlayerId);
if (__instance.Is(CustomRoles.Unlucky) && (target?.Object == null || !target.Object.Is(CustomRoles.Bait)))
{
Unlucky.SuicideRand(__instance, Unlucky.StateSuicide.ReportDeadBody);
if (Unlucky.UnluckCheck[__instance.PlayerId]) return false;
}
}
if (Options.SyncButtonMode.GetBool() && target == null)
{
Logger.Info($"Option: {Options.SyncedButtonCount.GetInt()}, has button count: {Options.UsedButtonCount}", "ReportDeadBody");
if (Options.SyncedButtonCount.GetFloat() <= Options.UsedButtonCount)
{
Logger.Info("The button has been canceled because the maximum number of available buttons has been exceeded", "ReportDeadBody");
return false;
}
else Options.UsedButtonCount++;
if (Options.SyncedButtonCount.GetFloat() == Options.UsedButtonCount)
{
Logger.Info("The maximum number of meeting buttons has been reached", "ReportDeadBody");
}
}
AfterReportTasks(__instance, target);
}
catch (Exception e)
{
Logger.Exception(e, "ReportDeadBodyPatch");
Logger.SendInGame("Error: " + e.ToString());
// If there is an error in ReportDeadBodyPatch, update the player nicknames anyway
MeetingTimeManager.OnReportDeadBody();
NameNotifyManager.Reset();
Utils.DoNotifyRoles(isForMeeting: true, NoCache: true, CamouflageIsForMeeting: true);
_ = new LateTask(Utils.SyncAllSettings, 3f, "Sync all settings after report");
}
return true;
}
public static void AfterReportTasks(PlayerControl player, GameData.PlayerInfo target)
{
//=============================================
// Hereinafter, it is assumed that the button is confirmed to be pressed
//=============================================
Main.LastVotedPlayerInfo = null;
Main.GuesserGuessed.Clear();
Main.AllKillers.Clear();
foreach (var playerStates in Main.PlayerStates.Values.ToArray())
{
if (target == null) return;
playerStates.RoleClass?.OnReportDeadBody(player, target?.Object);
}
// Alchemist & Bloodlust
Alchemist.OnReportDeadBodyGlobal();
if (Aware.IsEnable) Aware.OnReportDeadBody();
if (target != null) Sleuth.OnReportDeadBody(player, target?.Object);
foreach (var pc in Main.AllPlayerControls)
{
if (target == null) return;
if (!Doppelganger.CheckDoppelVictim(pc.PlayerId) && !Murderer.CheckMurdererVictim(target.PlayerId))
{
// Update skins again, since players have different skins
// And can be easily distinguished from each other
if (Camouflage.IsCamouflage && Options.KPDCamouflageMode.GetValue() is 2 or 3)
{
Camouflage.RpcSetSkin(pc);
}
// Check shapeshift and revert skin to default
if (Main.CheckShapeshift.ContainsKey(pc.PlayerId))
{
Camouflage.RpcSetSkin(pc, RevertToDefault: true);
}
}
Logger.Info($"Player {pc?.Data?.PlayerName}: Id {pc.PlayerId} - is alive: {pc.IsAlive()}", "CheckIsAlive");
}
// Set meeting time
MeetingTimeManager.OnReportDeadBody();
// Clear all Notice players
NameNotifyManager.Reset();
// Update Notify Roles for Meeting
Utils.DoNotifyRoles(isForMeeting: true, NoCache: true, CamouflageIsForMeeting: true);
// Sync all settings on meeting start
_ = new LateTask(Utils.SyncAllSettings, 3f, "Sync all settings after report");
}
public static async void ChangeLocalNameAndRevert(string name, int time)
{
//async Taskじゃ警告出るから仕方ないよね。
var revertName = PlayerControl.LocalPlayer.name;
PlayerControl.LocalPlayer.RpcSetNameEx(name);
await Task.Delay(time);
PlayerControl.LocalPlayer.RpcSetNameEx(revertName);
}
}
Overview
You get an error when calling a meeting caused by null reference in
TOHE.ReportDeadBodyPatch.AfterReportTasks
andTOHE.ReportDeadBodyPatch.Prefix
Error
Here is the error message and dump.
Error Message In Meeting
Error In Dump
Possible Fix
I just added a few null checks to fix the errors, but I don't know if I broke anything process so y'all will have to overview it.
Fix 1 For
TOHE.ReportDeadBodyPatch.AfterReportTasks
Fix 2 For
TOHE.ReportDeadBodyPatch.Prefix