zochris / SCPSL-SpectatorDisabler

Prevents players from spectating and rushing to the last survivors once they respawn. Built on the EXILED framework for SCP: Secret Laboratory
Other
2 stars 1 forks source link

SCP-1576 is unable to communicate with dead players (tutorials) #58

Open zochris opened 7 months ago

zochris commented 7 months ago

What happened?

SCP-1576 the phonograph does not work, because it assumes dead players are spectators.

It would be nice if instead of talking to spectators SCP-1576 would enable communication with players in the tutorial role.


Implementation notes:

SCP:SL version

13.3.0

EXILED version

8.3.9

SpectatorDisabler version

3.0.1

Relevant log output

No response

Wilnath commented 3 months ago

I've done some digging on this today and yesterday and have arrived at a proof of concept for a fix.

Scp1576 seems to work by allowing alive players to listen to the VoiceChatChannel.Spectator channel, and allows traditional spectators to hear alive players (that they're not currently spectating, mind you) through the VoiceChatChannel.Scp1576 channel.

The following two patches to sending and receiving voice packets, retroactively changing their channels to fit.

Two observations from testing:

  1. Two tutorials speaking will hear each other, with directional sound aswell despite talking on the spectator channel. However, the proximity chat icon (speaker above a persons head) is gone, making it a bit more confusing as to who is talking
  2. This to an extent inadvertently fixes an issue where players alive on the surface could go close under the tower and talk to people who are dead, dead players will still be able to hear the player who is alive but be unable to speak back.
namespace SpectatorDisabler.Patches
{
    [HarmonyPatch(typeof(HumanVoiceModule), nameof(HumanVoiceModule.ValidateSend))]
    internal class HumanVoiceSendPatch
    {
        public static void Postfix(HumanVoiceModule __instance, ref VoiceChatChannel __result, VoiceChatChannel channel)
        {
            // This changes all proximity chat from tutorials to use spectator as a channel instead.
            // This sadly means the proximity icon when people talk is gone
            if (__instance.Owner.roleManager.CurrentRole.RoleTypeId == RoleTypeId.Tutorial && channel == VoiceChatChannel.Proximity)
            {
                __result = VoiceChatChannel.Spectator;
            }
        }
    }

    [HarmonyPatch(typeof(HumanVoiceModule), nameof(HumanVoiceModule.ValidateReceive))]
    internal class HumanVoiceRecievePatch 
    {
        public static void Postfix(HumanVoiceModule __instance, ref VoiceChatChannel __result, ReferenceHub speaker, VoiceChatChannel channel)
        {
            if (__instance.Owner.roleManager.CurrentRole.RoleTypeId == RoleTypeId.Tutorial)
            {
                // Allow hearing from spectators (other tutorials) and SCP1576
                if (channel == VoiceChatChannel.Spectator || channel == VoiceChatChannel.Scp1576)
                {
                    __result = channel;
                }
                return;
            }
        }
    }
}

While working as a proof of concept, I have a few concerns with this solution. For one, postfixes just feel dirtier than transpiling although I'm not really sure how to back this one up lol Second, patching a hotpath like this might come with performance ramifications that I've yet not encountered because I've only really tried this with one other person

I see you've already tried a fix in commit https://github.com/zochris/SCPSL-SpectatorDisabler/commit/d1115a96bd15a58551a7a57ca639285b563a0781. That touches the Spectator check in a class called Scp1576SpectatorWarningHandler, my assumption is that that is responsible for playing the audio cues that occur when one spectates and an alive player starts using Scp1576. Unfortunately in my testing despite that fix tutorials do not have an audio cue when someone uses 1576, making even this fix feel like someone joins your conversation abruptly. So why that patch doesn't work would still be really cool to figure out!

zochris commented 3 months ago

Thank you for looking into this! I'll test this and will see if I can translate that to a transpiler.

Wilnath commented 3 months ago

Update: I forgot to mention! Because this touches code in the game that is usually marked private (or something along those lines I think, this is way more complicated than I'm willing to deal with) getting the code above running means setting the project settings to run unsafe code. image I'm not sure if this affects transpilers, but I thought it was worth a mention incase it does end up being needed for some reason. Code above for example compiles but as soon as someone starts talking they get kicked from the server unless unsafe is on.