using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Flashcard.Config;
using Flashcard.Networking;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using MyceliumNetworking;
using Photon.Pun;
using PlayEveryWare.VideoEncoding;
using Steamworks;
using Unity.Collections;
using UnityEngine;
using Zorro.Core.Serizalization;
using Zorro.PhotonUtility;
using Zorro.Recorder;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace Flashcard
{
[BepInPlugin("me.loaforc.Flashcard", "Flashcard", "0.3.4")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class FlashcardPlugin : BaseUnityPlugin
{
internal static uint networkID = 102873u;
public static FlashcardPlugin Instance { get; private set; } = null;
internal static ManualLogSource Logger { get; private set; } = null;
internal static Harmony Harmony { get; private set; } = null;
internal static FlashcardConfig config { get; private set; } = null;
private void Awake()
{
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Expected O, but got Unknown
Logger = ((BaseUnityPlugin)this).Logger;
Instance = this;
Logger.LogInfo((object)"Initing Config.");
config = new FlashcardConfig(((BaseUnityPlugin)this).Config);
Logger.LogInfo((object)"Running Harmony Patches");
Harmony = new Harmony("me.loaforc.Flashcard");
Type[] typesFromAssembly = AccessTools.GetTypesFromAssembly(Assembly.GetExecutingAssembly());
foreach (Type type in typesFromAssembly)
{
if (((MemberInfo)type).GetCustomAttribute<HarmonyPatch>() != null)
{
try
{
Harmony.CreateClassProcessor(type).Patch();
}
catch (Exception arg)
{
Logger.LogError((object)$"Failed to apply {type.Name}: {arg}");
}
}
}
if (config.RECORDING_CLIP_FRAMERATE.Value != RecordingConstants.VIDEO_FRAME_RATE)
{
Logger.LogWarning((object)$"ClipFramerate is not supported by the game's new video encoder, recording at {RecordingConstants.VIDEO_FRAME_RATE} fps");
}
Logger.LogInfo((object)"Setting up FlashcardVideoUploader");
new FlashcardVideoUploader();
Logger.LogInfo((object)"me.loaforc.Flashcard:0.3.4 has loaded!");
LogVerbose("Awake", "Flashcard loaded with verbose logging!");
}
internal static void LogVerbose(string origin, string message)
{
if (config.DEBUGGING_VERBOSE_LOGGING.Value)
{
Logger.LogInfo((object)("[" + origin + "] " + message));
}
}
}
}
namespace Flashcard.Patches
{
[HarmonyPatch(typeof(LibVEInitializer), "GetNewVeConfig")]
internal static class EncoderConfigPatch
{
[HarmonyPostfix]
private static void UpdateBitrate(ref ve_config __result)
{
uint? num = ParseQuality(FlashcardPlugin.config.RECORDING_CLIP_QUALITY.Value);
if (num.HasValue)
{
__result.target_bitrate = num.Value;
FlashcardPlugin.LogVerbose("Encoder", $"Target bitrate set to {num.Value} kbit/s");
}
}
private static uint? ParseQuality(string value)
{
string text = value.Trim().ToLowerInvariant();
if (text == "")
{
return null;
}
uint num = 1u;
if (text.EndsWith("m"))
{
num = 1000u;
text = text.Substring(0, text.Length - 1);
}
else if (text.EndsWith("k"))
{
text = text.Substring(0, text.Length - 1);
}
if (uint.TryParse(text, out var result) && result != 0)
{
return result * num;
}
FlashcardPlugin.Logger.LogError((object)("Invalid clip quality: " + value));
return null;
}
}
[HarmonyPatch(typeof(PhotonSendVideoHandler))]
internal class PhotonSendVideoHandlerPatch
{
[HarmonyPrefix]
[HarmonyPatch("SendVideoThroughPhoton")]
internal static void ReallyReallyForceVideoSharingOverSteamNetwork(PhotonSendVideoHandler __instance, ref bool isReRequest)
{
isReRequest = false;
__instance.m_UseSteamNetwork = true;
}
[HarmonyPrefix]
[HarmonyPatch("RecieveClipChunk")]
internal static void LogRecieveClipChunk(SendVideoChunkPackage package)
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
FlashcardPlugin.LogVerbose("RecieveClipChunk", $"Recieved a chunk of a video! Chunk '{package.ChunkIndex}' for clip '{package.ClipID}'");
}
[HarmonyPostfix]
[HarmonyPatch("SendVideoChunks")]
internal static void FlashcardSendVideoChunks(ref IEnumerator __result, List<byte[]> videoChunks, ClipID clipID, VideoHandle videoID, ContentBuffer contentBuffer, bool isReRequest)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
__result = FlashcardVideoUploader.Instance.SendVideoChunks(videoChunks, clipID, videoID, contentBuffer, isReRequest);
}
}
[HarmonyPatch(typeof(RecordingsHandler))]
internal static class RecordingHandlerPatch
{
[HarmonyPatch("StartRecording")]
[HarmonyPostfix]
private static void LogStartRecording()
{
FlashcardPlugin.LogVerbose("RecordingHandlerPatch", "RecordingsHandler.StartRecording!!!");
}
}
[HarmonyPatch(typeof(SurfaceNetworkHandler))]
internal static class SurfaceNetworkHandlerPatch
{
[HarmonyPostfix]
[HarmonyPatch("InitSurface")]
internal static void SpawnOnStartRun(SurfaceNetworkHandler __instance)
{
if (PhotonNetwork.IsMasterClient)
{
SpawnExtraCamera(__instance);
}
}
[HarmonyPostfix]
[HarmonyPatch("OnSlept")]
internal static void SpawnOnNewDay(SurfaceNetworkHandler __instance)
{
if (PhotonNetwork.IsMasterClient && Object.FindObjectsOfType<VideoCamera>().Length < 2)
{
SpawnExtraCamera(__instance);
}
}
private static void SpawnExtraCamera(SurfaceNetworkHandler handler)
{
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00b1: Expected O, but got Unknown
//IL_0073: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
//IL_0088: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
if (PhotonNetwork.IsMasterClient && !(FlashcardPlugin.config.UPGRADES_EXTRA_CAMERA.Value == "disabled"))
{
FlashcardPlugin.Logger.LogInfo((object)"Spawning extra camera!");
Vector3 val = default(Vector3);
((Vector3)(ref val))..ctor(-14.842f, 2.418f, 8.776f);
Quaternion val2 = Quaternion.Euler(0f, -67.18f, 0f);
PickupSpawner videoCameraSpawner = handler.m_VideoCameraSpawner;
if ((Object)(object)videoCameraSpawner != (Object)null)
{
val = ((Component)videoCameraSpawner).transform.position - ((Component)videoCameraSpawner).transform.right * 0.4f;
val2 = ((Component)videoCameraSpawner).transform.rotation;
}
PickupHandler.CreatePickup((byte)1, new ItemInstanceData(Guid.NewGuid()), val, val2);
}
}
}
[HarmonyPatch(typeof(VideoCamera))]
public class VideoCameraPatch
{
[HarmonyTranspiler]
[HarmonyPatch("ConfigItem")]
private static IEnumerable<CodeInstruction> UpdateFilmAmount(IEnumerable<CodeInstruction> instructions)
{
FieldInfo objB = AccessTools.Field(typeof(VideoInfoEntry), "timeLeft");
FieldInfo objB2 = AccessTools.Field(typeof(VideoInfoEntry), "maxTime");
List<CodeInstruction> list = new List<CodeInstruction>(instructions);
int num = 0;
for (int i = 0; i + 1 < list.Count; i++)
{
if (list[i].opcode == OpCodes.Ldc_R4 && list[i].operand is float num2 && num2 == 90f && list[i + 1].opcode == OpCodes.Stfld && (object.Equals(list[i + 1].operand, objB) || object.Equals(list[i + 1].operand, objB2)))
{
list[i].operand = FlashcardPlugin.config.RECORDING_CLIP_LENGTH.Value;
num++;
}
}
if (num != 2)
{
FlashcardPlugin.Logger.LogWarning((object)$"ClipLength: expected 2 film length values in VideoCamera.ConfigItem, replaced {num}");
}
return list;
}
}
}
namespace Flashcard.Networking
{
internal class FlashcardVideoUploader
{
internal static FlashcardVideoUploader Instance;
private uint NetworkID => FlashcardPlugin.networkID;
internal FlashcardVideoUploader()
{
MyceliumNetwork.RegisterNetworkObject((object)this, NetworkID, 0);
Instance = this;
}
internal IEnumerator SendVideoChunks(List<byte[]> videoChunks, ClipID clipID, VideoHandle videoID, ContentBuffer contentBuffer, bool isReRequest)
{
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
FlashcardPlugin.LogVerbose("Uploading", $"Sending Video Chunks! VideoID: {clipID.id}");
for (ushort chunkIndex = 0; chunkIndex < videoChunks.Count; chunkIndex++)
{
SendVideoChunkPackage val = new SendVideoChunkPackage
{
ChunkCount = (ushort)videoChunks.Count,
VideoChunkData = videoChunks[chunkIndex],
ChunkIndex = chunkIndex,
VideoHandle = videoID,
ClipID = clipID
};
BinarySerializer val2 = null;
if (chunkIndex == 0)
{
val2 = new BinarySerializer(512, (Allocator)4);
contentBuffer.Serialize(val2);
val.ContentEventData = val2.buffer;
}
BinarySerializer val3 = ((CustomCommandPackage<CustomCommandType>)(object)val).Serialize();
byte[] array;
try
{
array = val3.buffer.ToArray();
}
finally
{
((IDisposable)val3)?.Dispose();
}
if (val2 != null)
{
val2.Dispose();
}
CSteamID[] players = MyceliumNetwork.Players;
foreach (CSteamID val4 in players)
{
if (val4 != SteamUser.GetSteamID())
{
MyceliumNetwork.RPCTarget(NetworkID, "RPC_RecieveChunk", val4, (ReliableType)1, new object[1] { array });
}
}
FlashcardPlugin.LogVerbose("Uploading", $"Uploaded a chunk! VideoID: {clipID.id}, chunkIndex: {chunkIndex}");
yield return (object)new WaitForSeconds(FlashcardPlugin.config.UPLOADING_DELAY_BETWEEN_PACKETS.Value);
}
}
[CustomRPC]
private void RPC_RecieveChunk(byte[] data)
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Expected O, but got Unknown
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Expected O, but got Unknown
FlashcardPlugin.LogVerbose("Uploading", "Recieved Video Chunk! Deserializing and giving it back to PhotonSendVideoHandler.");
BinaryDeserializer val = new BinaryDeserializer(new NativeArray<byte>(data, (Allocator)2));
SendVideoChunkPackage val2 = new SendVideoChunkPackage();
((CustomCommandPackage<CustomCommandType>)(object)val2).DeserializeData(val);
val.Dispose();
RetrievableSingleton<PhotonSendVideoHandler>.Instance.RecieveClipChunk(val2);
}
}
}
namespace Flashcard.Config
{
internal class FlashcardConfig
{
internal ConfigEntry<string> UPGRADES_EXTRA_CAMERA;
internal ConfigEntry<float> RECORDING_CLIP_LENGTH;
internal ConfigEntry<int> RECORDING_CLIP_FRAMERATE;
internal ConfigEntry<string> RECORDING_CLIP_QUALITY;
internal ConfigEntry<float> UPLOADING_DELAY_BETWEEN_PACKETS;
internal ConfigEntry<bool> DEBUGGING_VERBOSE_LOGGING;
internal FlashcardConfig(ConfigFile cfgFile)
{
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: Expected O, but got Unknown
UPGRADES_EXTRA_CAMERA = cfgFile.Bind<string>("Upgrades", "ExtraCamera", "disabled", new ConfigDescription("Should allow the Extra Camera Upgrade?", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "disabled", "always" }), Array.Empty<object>()));
RECORDING_CLIP_LENGTH = cfgFile.Bind<float>("Recording", "ClipLength", 120f, "How many seconds should the camera be allowed to record?\nContentWarning's default is 90.");
RECORDING_CLIP_FRAMERATE = cfgFile.Bind<int>("Recording", "ClipFramerate", 24, "Not supported by the game's current video encoder; the game always records at 24 fps.");
RECORDING_CLIP_QUALITY = cfgFile.Bind<string>("Recording", "ClipQuality", "512k", "Target video bitrate, e.g. 512k or 1M. The game's default is 25k.\nHigher values look better but make clips bigger and slower to share.\nSet to empty to keep the game's default.");
UPLOADING_DELAY_BETWEEN_PACKETS = cfgFile.Bind<float>("Uploading", "DelayBetweenPackets", 0.5f, "The delay between the packets for video chunk data being sent.");
DEBUGGING_VERBOSE_LOGGING = cfgFile.Bind<bool>("Debugging", "VerboseLogging", false, "Whether flashcard should increase it's logs. Useful for debugging issues.");
}
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
}