Files
EndlessHostRoles/Modules/CustomNetObject.cs
T
2024-06-21 21:37:35 +02:00

298 lines
17 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using EHR.Roles.Crewmate;
using Hazel;
using InnerNet;
using UnityEngine;
// Credit: https://github.com/Rabek009/MoreGamemodes/blob/e054eb498094dfca0a365fc6b6fea8d17f9974d7/Modules/CustomObjects
// Huge thanks to Rabek009 for this code!
namespace EHR
{
internal class CustomNetObject
{
public static readonly Dictionary<int, CustomNetObject> AllObjects = [];
protected readonly int Id = Enumerable.Range(0, int.MaxValue).First(id => !AllObjects.ContainsKey(id));
private PlayerControl PC;
protected void RpcChangeSprite(string sprite)
{
PC.RpcSetName(sprite);
}
public void TP(Vector2 position)
{
PC.NetTransform.RpcSnapTo(position);
}
public void Despawn()
{
PC.Despawn();
LateTask.New(() => AllObjects.Remove(Id), 0.001f, log: false);
}
protected void Hide(PlayerControl player)
{
if (player.AmOwner)
{
PC.Visible = false;
return;
}
MessageWriter writer = MessageWriter.Get();
writer.StartMessage(6);
writer.Write(AmongUsClient.Instance.GameId);
writer.WritePacked(player.GetClientId());
writer.StartMessage(5);
writer.WritePacked(PC.NetId);
writer.EndMessage();
writer.EndMessage();
AmongUsClient.Instance.SendOrDisconnect(writer);
writer.Recycle();
}
protected virtual void OnFixedUpdate()
{
}
protected void CreateNetObject(string sprite, Vector2 position)
{
PC = Object.Instantiate(AmongUsClient.Instance.PlayerPrefab, Vector2.zero, Quaternion.identity);
PC.PlayerId = 255;
PC.isNew = false;
PC.notRealPlayer = true;
AmongUsClient.Instance.NetIdCnt += 1U;
MessageWriter msg = MessageWriter.Get();
msg.StartMessage(5);
msg.Write(AmongUsClient.Instance.GameId);
AmongUsClient.Instance.WriteSpawnMessage(PC, -2, SpawnFlags.None, msg);
msg.EndMessage();
msg.StartMessage(6);
msg.Write(AmongUsClient.Instance.GameId);
msg.WritePacked(int.MaxValue);
for (uint i = 1; i <= 3; ++i)
{
msg.StartMessage(4);
msg.WritePacked(2U);
msg.WritePacked(-2);
msg.Write((byte)SpawnFlags.None);
msg.WritePacked(1);
msg.WritePacked(AmongUsClient.Instance.NetIdCnt - i);
msg.StartMessage(1);
msg.EndMessage();
msg.EndMessage();
}
msg.EndMessage();
AmongUsClient.Instance.SendOrDisconnect(msg);
msg.Recycle();
if (PlayerControl.AllPlayerControls.Contains(PC))
PlayerControl.AllPlayerControls.Remove(PC);
LateTask.New(() =>
{
PC.RpcSetName(sprite);
PC.NetTransform.RpcSnapTo(position);
}, 0.1f, log: false);
PC.cosmetics.currentBodySprite.BodySprite.color = Color.clear;
PC.cosmetics.colorBlindText.color = Color.clear;
AllObjects.Add(Id, this);
foreach (var pc in Main.AllPlayerControls)
{
if (pc.AmOwner) continue;
LateTask.New(() =>
{
CustomRpcSender sender = CustomRpcSender.Create("SetFakeData");
MessageWriter writer = sender.stream;
sender.StartMessage(pc.GetClientId());
writer.StartMessage(1);
{
writer.WritePacked(PC.NetId);
writer.Write(pc.PlayerId);
}
writer.EndMessage();
sender.StartRpc(PC.NetId, (byte)RpcCalls.MurderPlayer)
.WriteNetObject(PC)
.Write((int)MurderResultFlags.FailedError)
.EndRpc();
writer.StartMessage(1);
{
writer.WritePacked(PC.NetId);
writer.Write((byte)255);
}
writer.EndMessage();
sender.EndMessage();
sender.SendMessage();
}, 0.1f, log: false);
}
}
public static CustomNetObject Get(int id) => AllObjects.GetValueOrDefault(id);
public static void FixedUpdate() => AllObjects.Values.Do(x => x.OnFixedUpdate());
}
internal sealed class Explosion : CustomNetObject
{
private readonly float Duration;
private readonly float Size;
private int Frame;
private float Timer;
public Explosion(float size, float duration, Vector2 position)
{
Size = size;
Duration = duration;
Timer = -0.1f;
Frame = 0;
CreateNetObject($"<size={Size}><line-height=72%><font=\"VCR SDF\"><br><#0000>███<#ff0000>█<#0000>███<br><#ff0000>█<#0000>█<#ff0000>███<#0000>█<#ff0000>█<br>█<#ff8000>██<#ffff00>█<#ff8000>██<#ffff00>█<br>██<#ff8000>█<#ffff00>█<#ff8000>█<#ffff00>██<br><#ff8000>█<#ffff80>██<#ffff00>█<#ffff80>██<#ff8000>█<br><#0000>█<#ff8000>█<#ffff80>███<#ff8000>█<#0000>█<br>██<#ff8000>███<#0000>██", position);
}
protected override void OnFixedUpdate()
{
Timer += Time.deltaTime;
if (Timer >= Duration / 5f && Frame == 0)
{
RpcChangeSprite($"<size={Size}><line-height=72%><font=\"VCR SDF\"><br><#0000>█<#ff0000>█<#0000>█<#ff0000>█<#0000>█<#ff0000>█<#0000>█<br><#ff0000>█<#ff8000>█<#ff0000>█<#ff8000>█<#ff0000>█<#ff8000>█<#ff0000>█<br><#ff8000>██<#ffff00>█<#ff8000>█<#ffff00>█<#ff8000>██<br><#ffff00>███████<br><#ff8000>█<#ffff00>█████<#ff8000>█<br>██<#ffff00>█<#ff8000>█<#ffff00>█<#ff8000>██<br><#ff0000>█<#0000>█<#ff8000>█<#ff0000>█<#ff8000>█<#0000>█<#ff0000>█");
Frame = 1;
}
if (Timer >= Duration / 5f * 2f && Frame == 1)
{
RpcChangeSprite($"<size={Size}><line-height=72%><font=\"VCR SDF\"><br><#0000>█<#c0c0c0>█<#ff0000>█<#000000>█<#ff0000>█<#c0c0c0>█<#0000>█<br><#c0c0c0>█<#808080>█<#ff0000>█<#ff8000>█<#ff0000>█<#c0c0c0>██<br><#ff0000>██<#ff8000>█<#ffff00>█<#ff8000>█<#ff0000>██<br><#c0c0c0>█<#ff8000>█<#ffff00>█<#ffff80>█<#ffff00>█<#ff8000>█<#808080>█<br><#ff0000>██<#ff8000>█<#ffff00>█<#ff8000>█<#ff0000>██<br><#c0c0c0>█<#808080>█<#ff0000>█<#ff8000>█<#ff0000>█<#000000>█<#c0c0c0>█<br><#0000>█<#c0c0c0>█<#ff0000>█<#c0c0c0>█<#ff0000>█<#c0c0c0>█<#0000>█");
Frame = 2;
}
if (Timer >= Duration / 5f * 3f && Frame == 2)
{
RpcChangeSprite($"<size={Size}><line-height=72%><font=\"VCR SDF\"><br><#ff0000>█<#ff8000>█<#0000>█<#808080>█<#0000>█<#ff8000>█<#ff0000>█<br><#ff8000>█<#0000>█<#ffff00>█<#c0c0c0>█<#ffff00>█<#0000>█<#ff8000>█<br><#0000>█<#ffff00>█<#c0c0c0>███<#ffff00>█<#0000>█<br><#808080>█<#c0c0c0>█████<#808080>█<br><#0000>█<#ffff00>█<#c0c0c0>███<#ffff00>█<#0000>█<br><#ff8000>█<#0000>█<#ffff00>█<#c0c0c0>█<#ffff00>█<#0000>█<#ff8000>█<br><#ff0000>█<#ff8000>█<#0000>█<#808080>█<#0000>█<#ff8000>█<#ff0000>█");
Frame = 3;
}
if (Timer >= Duration / 5f * 4f && Frame == 3)
{
RpcChangeSprite($"<size={Size}><line-height=72%><font=\"VCR SDF\"><br><#0000>█<#808080>█<#0000>██<#c0c0c0>█<#0000>█<#808080>█<br><#ffff00>█<#0000>██<#c0c0c0>█<#0000>█<#808080>█<#0000>█<br>█<#808080>█<#c0c0c0>████<#0000>█<br>█<#c0c0c0>██████<br>█<#0000>█<#c0c0c0>███<#808080>█<#0000>█<br>█<#c0c0c0>█<#0000>█<#c0c0c0>█<#0000>█<#c0c0c0>██<br><#808080>█<#0000>█<#c0c0c0>█<#0000>█<#808080>█<#0000>█<#ffff00>█");
Frame = 4;
}
if (Timer >= Duration && Frame == 4)
{
Despawn();
}
}
}
internal sealed class TrapArea : CustomNetObject
{
private readonly float Size;
private readonly float WaitDuration;
private int State;
private float Timer;
public TrapArea(float radius, float waitDuration, Vector2 position, IEnumerable<byte> visibleList)
{
Size = radius * 25f;
Timer = -0.1f;
WaitDuration = waitDuration;
State = 0;
CreateNetObject($"<size={Size}><font=\"VCR SDF\"><#c7c7c769>●", position);
Main.AllAlivePlayerControls.ExceptBy(visibleList, x => x.PlayerId).Do(Hide);
}
protected override void OnFixedUpdate()
{
Timer += Time.deltaTime;
if (Timer >= WaitDuration * 0.75f && State == 0)
{
RpcChangeSprite($"<size={Size}><font=\"VCR SDF\"><#fff70069>●");
State = 1;
}
if (Timer >= WaitDuration * 0.95f && State == 1)
{
RpcChangeSprite($"<size={Size}><font=\"VCR SDF\"><#ff000069>●");
State = 2;
}
}
}
internal sealed class TornadoObject : CustomNetObject
{
private readonly long SpawnTimeStamp;
private bool Gone;
public TornadoObject(Vector2 position, IEnumerable<byte> visibleList)
{
SpawnTimeStamp = Utils.TimeStamp;
CreateNetObject("<size=100%><font=\"VCR SDF\"><line-height=72%><alpha=#00>\u2588<alpha=#00>\u2588<#bababa>\u2588<#bababa>\u2588<#bababa>\u2588<#bababa>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<#bababa>\u2588<#bababa>\u2588<#8c8c8c>\u2588<#8c8c8c>\u2588<#bababa>\u2588<#bababa>\u2588<alpha=#00>\u2588<br><#bababa>\u2588<#bababa>\u2588<#8c8c8c>\u2588<#8c8c8c>\u2588<#8c8c8c>\u2588<#8c8c8c>\u2588<#bababa>\u2588<#bababa>\u2588<br><#bababa>\u2588<#8c8c8c>\u2588<#8c8c8c>\u2588<#636363>\u2588<#636363>\u2588<#8c8c8c>\u2588<#8c8c8c>\u2588<#bababa>\u2588<br><#bababa>\u2588<#8c8c8c>\u2588<#8c8c8c>\u2588<#636363>\u2588<#636363>\u2588<#8c8c8c>\u2588<#8c8c8c>\u2588<#bababa>\u2588<br><#bababa>\u2588<#bababa>\u2588<#8c8c8c>\u2588<#8c8c8c>\u2588<#8c8c8c>\u2588<#8c8c8c>\u2588<#bababa>\u2588<#bababa>\u2588<br><alpha=#00>\u2588<#bababa>\u2588<#bababa>\u2588<#8c8c8c>\u2588<#8c8c8c>\u2588<#bababa>\u2588<#bababa>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<alpha=#00>\u2588<#bababa>\u2588<#bababa>\u2588<#bababa>\u2588<#bababa>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br></color></line-height></font></size>", position);
Main.AllAlivePlayerControls.ExceptBy(visibleList, x => x.PlayerId).Do(Hide);
}
protected override void OnFixedUpdate()
{
try
{
if (Gone) return;
if (SpawnTimeStamp + Tornado.TornadoDuration.GetInt() < Utils.TimeStamp)
{
Gone = true;
Despawn();
}
}
catch (NullReferenceException)
{
try
{
Despawn();
}
finally
{
Gone = true;
}
}
}
}
internal sealed class PlayerDetector : CustomNetObject
{
public PlayerDetector(Vector2 position, List<byte> visibleList, out int id)
{
CreateNetObject("<size=100%><font=\"VCR SDF\"><line-height=72%><alpha=#00>\u2588<alpha=#00>\u2588<#33e6b0>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#33e6b0>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<#33e6b0>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#33e6b0>\u2588<alpha=#00>\u2588<br><#33e6b0>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#33e6b0>\u2588<#33e6b0>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#33e6b0>\u2588<br><#33e6b0>\u2588<alpha=#00>\u2588<#33e6b0>\u2588<#000000>\u2588<#000000>\u2588<#33e6b0>\u2588<alpha=#00>\u2588<#33e6b0>\u2588<br><#33e6b0>\u2588<alpha=#00>\u2588<#33e6b0>\u2588<#000000>\u2588<#000000>\u2588<#33e6b0>\u2588<alpha=#00>\u2588<#33e6b0>\u2588<br><#33e6b0>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#33e6b0>\u2588<#33e6b0>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#33e6b0>\u2588<br><alpha=#00>\u2588<#33e6b0>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#33e6b0>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<alpha=#00>\u2588<#33e6b0>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#33e6b0>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br></color></line-height></font></size>", position);
Main.AllAlivePlayerControls.ExceptBy(visibleList, x => x.PlayerId).Do(Hide);
id = Id;
}
}
internal sealed class AdventurerItem : CustomNetObject
{
public readonly Adventurer.Resource Resource;
internal AdventurerItem(Vector2 position, Adventurer.Resource resource, IEnumerable<byte> visibleList)
{
Resource = resource;
var data = Adventurer.ResourceDisplayData[resource];
CreateNetObject($"<size=300%><font=\"VCR SDF\"><line-height=72%>{Utils.ColorString(data.Color, data.Icon.ToString())}</line-height></font></size>", position);
Main.AllAlivePlayerControls.ExceptBy(visibleList, x => x.PlayerId).Do(Hide);
}
}
internal sealed class Toilet : CustomNetObject
{
internal Toilet(Vector2 position, IEnumerable<PlayerControl> hideList)
{
CreateNetObject("<size=100%><font=\"VCR SDF\"><line-height=72%><alpha=#00>\u2588<#e6e6e6>\u2588<#e6e6e6>\u2588<#e6e6e6>\u2588<#e6e6e6>\u2588<#e6e6e6>\u2588<#e6e6e6>\u2588<#e6e6e6>\u2588<#e6e6e6>\u2588<alpha=#00>\u2588<br><#e6e6e6>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#e6e6e6>\u2588<br><#e6e6e6>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#e6e6e6>\u2588<br><alpha=#00>\u2588<#e6e6e6>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#e6e6e6>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<#e6e6e6>\u2588<#e6e6e6>\u2588<#d3d4ce>\u2588<#dedede>\u2588<#dedede>\u2588<#d3d4ce>\u2588<#e6e6e6>\u2588<#e6e6e6>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<#bfbfbf>\u2588<#454545>\u2588<#333333>\u2588<#333333>\u2588<#333333>\u2588<#333333>\u2588<#333333>\u2588<#333333>\u2588<#bfbfbf>\u2588<br><alpha=#00>\u2588<#bfbfbf>\u2588<#bfbfbf>\u2588<#454545>\u2588<#454545>\u2588<#454545>\u2588<#454545>\u2588<#454545>\u2588<#454545>\u2588<#bfbfbf>\u2588<br><alpha=#00>\u2588<alpha=#00>\u2588<#bfbfbf>\u2588<#bfbfbf>\u2588<#bfbfbf>\u2588<#bfbfbf>\u2588<#bfbfbf>\u2588<#bfbfbf>\u2588<#bfbfbf>\u2588<#bfbfbf>\u2588<br><alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#dedede>\u2588<#dedede>\u2588<#dedede>\u2588<#dedede>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#dedede>\u2588<#dedede>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br></color></line-height></font></size>", position);
hideList.Do(Hide);
}
}
internal sealed class BlackHole : CustomNetObject
{
internal BlackHole(Vector2 position)
{
CreateNetObject("<size=100%><font=\"VCR SDF\"><line-height=72%><alpha=#00>\u2588<alpha=#00>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<alpha=#00>\u2588<br><#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<br><#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<br><#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<br><#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<br><alpha=#00>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<alpha=#00>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br></color></line-height></font></size>", position);
}
}
}