Decompiled source of XandIMod v1.0.2

RepoXandIMod.dll

Decompiled 2 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using BepInEx;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Photon.Pun;
using UnityEngine;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("XandImmersion")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+cbe3960eb2e020714dd18782bb9665520294abed")]
[assembly: AssemblyProduct("RepoXandIMod")]
[assembly: AssemblyTitle("RepoXandIMod")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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;
		}
	}
}
[Serializable]
public class ArielSound
{
	public AudioSource Source;

	public List<AudioClip> Sounds = new List<AudioClip>();

	private AudioLowPassLogic LowPassLogic;

	private bool HasLowPassLogic;

	public AudioType Type;

	[Range(0f, 1f)]
	public float Volume = 0.5f;

	[Range(0f, 1f)]
	public float VolumeRandom = 0.1f;

	[Range(0f, 5f)]
	public float Pitch = 1f;

	[Range(0f, 2f)]
	public float PitchRandom = 0.1f;

	[Range(0f, 1f)]
	public float SpatialBlend = 1f;

	[Range(0f, 5f)]
	public float Doppler = 1f;

	[Range(0f, 1f)]
	public float ReverbMix = 1f;

	[Range(0f, 5f)]
	public float FalloffMultiplier = 1f;

	[Space]
	[Range(0f, 1f)]
	public float OffscreenVolume = 1f;

	[Range(0f, 1f)]
	public float OffscreenFalloff = 1f;

	[Space]
	public List<Collider> LowPassIgnoreColliders = new List<Collider>();

	private AudioClip LoopClip;

	internal float LoopVolume;

	internal float LoopVolumeCurrent;

	internal float LoopVolumeFinal;

	internal float LoopPitch;

	internal float LoopFalloff;

	internal float LoopFalloffFinal;

	private float LoopOffScreenTime = 0.25f;

	private float LoopOffScreenTimer;

	private bool LoopOffScreen;

	private float LoopOffScreenVolume;

	private float LoopOffScreenFalloff;

	internal float StartTimeOverride = 999999f;

	private bool AudioInfoFetched;

	public AudioSource Play(AudioSource audioSource, float volumeMultiplier = 1f, float falloffMultiplier = 1f, float offscreenVolumeMultiplier = 1f, float offscreenFalloffMultiplier = 1f)
	{
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a1: Expected I4, but got Unknown
		//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
		int index = 0;
		if (Sounds.Count == 0)
		{
			return null;
		}
		AudioClip val = Sounds[index];
		float pitch = Pitch + Random.Range(0f - PitchRandom, PitchRandom);
		if (!Object.op_Implicit((Object)(object)audioSource))
		{
			GameObject audioDefault = AudioManager.instance.AudioDefault;
			AudioType type = Type;
			AudioType val2 = type;
			switch (val2 - 1)
			{
			case 0:
				audioDefault = AudioManager.instance.AudioHighFalloff;
				break;
			case 1:
				audioDefault = AudioManager.instance.AudioFootstep;
				break;
			case 2:
				audioDefault = AudioManager.instance.AudioMaterialImpact;
				break;
			case 3:
				audioDefault = AudioManager.instance.AudioCutscene;
				break;
			case 4:
				audioDefault = AudioManager.instance.AudioAmbienceBreaker;
				break;
			case 5:
				audioDefault = AudioManager.instance.AudioLowFalloff;
				break;
			case 6:
				audioDefault = AudioManager.instance.AudioGlobal;
				break;
			case 7:
				audioDefault = AudioManager.instance.AudioHigherFalloff;
				break;
			case 8:
				audioDefault = AudioManager.instance.AudioAttack;
				break;
			case 9:
				audioDefault = AudioManager.instance.AudioPersistent;
				break;
			}
		}
		else if (!((Behaviour)audioSource).enabled)
		{
			return null;
		}
		audioSource.minDistance *= FalloffMultiplier;
		audioSource.minDistance *= falloffMultiplier;
		audioSource.maxDistance *= FalloffMultiplier;
		audioSource.maxDistance *= falloffMultiplier;
		audioSource.clip = Sounds[index];
		audioSource.volume = (Volume + Random.Range(0f - VolumeRandom, VolumeRandom)) * volumeMultiplier;
		if (SpatialBlend > 0f && (OffscreenVolume * offscreenVolumeMultiplier < 1f || OffscreenFalloff * offscreenFalloffMultiplier < 1f) && !SemiFunc.OnScreen(((Component)audioSource).transform.position, 0.1f, 0.1f))
		{
			audioSource.volume *= OffscreenVolume * offscreenVolumeMultiplier;
			audioSource.minDistance *= OffscreenFalloff * offscreenFalloffMultiplier;
			audioSource.maxDistance *= OffscreenFalloff * offscreenFalloffMultiplier;
		}
		audioSource.spatialBlend = SpatialBlend;
		audioSource.reverbZoneMix = ReverbMix;
		audioSource.dopplerLevel = Doppler;
		audioSource.pitch = pitch;
		audioSource.loop = false;
		audioSource.volume = 2f;
		if (SpatialBlend > 0f)
		{
			StartLowPass(audioSource);
		}
		audioSource.Play();
		return audioSource;
	}

	public void Stop()
	{
		Source.Stop();
	}

	private void StartLowPass(AudioSource source)
	{
		LowPassLogic = ((Component)source).GetComponent<AudioLowPassLogic>();
		if (Object.op_Implicit((Object)(object)LowPassLogic))
		{
			if (LowPassIgnoreColliders.Count > 0)
			{
				LowPassLogic.LowPassIgnoreColliders.AddRange(LowPassIgnoreColliders);
			}
			LowPassLogic.Setup();
			HasLowPassLogic = true;
		}
	}

	public void PlayLoop(bool playing, float fadeInSpeed, float fadeOutSpeed, float pitchMultiplier = 1f)
	{
		if (!AudioInfoFetched)
		{
			LoopClip = Sounds[Random.Range(0, Sounds.Count)];
			Source.clip = LoopClip;
		}
		if (!playing)
		{
			if (Source.isPlaying)
			{
				LoopVolumeCurrent -= fadeOutSpeed * Time.deltaTime;
				LoopVolumeCurrent = Mathf.Clamp(LoopVolumeCurrent, 0f, LoopVolume);
				LoopOffScreenLogic();
				Source.pitch = LoopPitch * pitchMultiplier;
				if (HasLowPassLogic)
				{
					LowPassLogic.Volume = LoopVolumeFinal;
				}
				else
				{
					Source.volume = LoopVolumeFinal;
				}
				if (LoopVolumeFinal <= 0f)
				{
					Source.Stop();
				}
			}
		}
		else if (!Source.isPlaying)
		{
			LoopVolume = Volume + Random.Range(0f - VolumeRandom, VolumeRandom);
			LoopPitch = Pitch + Random.Range(0f - PitchRandom, PitchRandom);
			LoopVolumeCurrent = 0f;
			LoopVolumeFinal = LoopVolumeCurrent;
			Source.volume = LoopVolumeCurrent;
			Source.pitch = LoopPitch * pitchMultiplier;
			Source.spatialBlend = SpatialBlend;
			Source.reverbZoneMix = ReverbMix;
			Source.dopplerLevel = Doppler;
			AudioSource source = Source;
			source.minDistance *= FalloffMultiplier;
			AudioSource source2 = Source;
			source2.maxDistance *= FalloffMultiplier;
			LoopFalloff = Source.maxDistance;
			Source.time = Random.Range(0f, Source.clip.length);
			if (StartTimeOverride != 999999f)
			{
				Source.time = StartTimeOverride;
			}
			Source.loop = true;
			StartLowPass(Source);
			Source.Play();
		}
		else
		{
			LoopVolumeCurrent += fadeInSpeed * Time.deltaTime;
			LoopVolumeCurrent = Mathf.Clamp(LoopVolumeCurrent, 0f, LoopVolume);
			LoopOffScreenLogic();
			Source.pitch = LoopPitch * pitchMultiplier;
			if (HasLowPassLogic)
			{
				LowPassLogic.Volume = LoopVolumeFinal;
			}
			else
			{
				Source.volume = LoopVolumeFinal;
			}
		}
	}

	private void LoopOffScreenLogic()
	{
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		LoopVolumeFinal = LoopVolumeCurrent;
		if (!(SpatialBlend > 0f) || (!(OffscreenVolume < 1f) && !(OffscreenFalloff < 1f)))
		{
			return;
		}
		if (LoopOffScreenTimer <= 0f)
		{
			LoopOffScreenTimer = LoopOffScreenTime;
			LoopOffScreen = !SemiFunc.OnScreen(((Component)Source).transform.position, 0.1f, 0.1f);
		}
		else
		{
			LoopOffScreenTimer -= Time.deltaTime;
		}
		if (OffscreenVolume < 1f)
		{
			if (LoopOffScreen)
			{
				LoopOffScreenVolume = Mathf.Lerp(LoopOffScreenVolume, OffscreenVolume, 15f * Time.deltaTime);
			}
			else
			{
				LoopOffScreenVolume = Mathf.Lerp(LoopOffScreenVolume, 1f, 15f * Time.deltaTime);
			}
			LoopVolumeFinal *= LoopOffScreenVolume;
		}
		if (OffscreenFalloff < 1f)
		{
			if (LoopOffScreen)
			{
				LoopFalloffFinal = Mathf.Lerp(LoopFalloffFinal, LoopFalloff * OffscreenFalloff, 15f * Time.deltaTime);
			}
			else
			{
				LoopFalloffFinal = Mathf.Lerp(LoopFalloffFinal, LoopFalloff, 15f * Time.deltaTime);
			}
			if (HasLowPassLogic)
			{
				LowPassLogic.Falloff = LoopFalloffFinal;
			}
			else
			{
				Source.maxDistance = LoopFalloffFinal;
			}
		}
	}

	public static void CopySound(Sound from, Sound to)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		to.Source = from.Source;
		to.Sounds = from.Sounds;
		to.Type = from.Type;
		to.Volume = from.Volume;
		to.VolumeRandom = from.VolumeRandom;
		to.Pitch = from.Pitch;
		to.PitchRandom = from.PitchRandom;
		to.SpatialBlend = from.SpatialBlend;
		to.ReverbMix = from.ReverbMix;
		to.Doppler = from.Doppler;
	}
}
public static class SettingsLoader
{
	public static Root Load(string filePath)
	{
		string text = File.ReadAllText(filePath);
		return JsonConvert.DeserializeObject<Root>(text);
	}
}
public class Assets
{
	public List<Valuable> valuables { get; set; }
}
public class Keys
{
	public string diagen { get; set; }

	public string ariel { get; set; }
}
public class Root
{
	public Keys keys { get; set; }

	public Assets assets { get; set; }
}
public class Valuable
{
	public string asset { get; set; }

	public string name { get; set; }

	[JsonProperty("use_stt")]
	public bool useSTT { get; set; }

	public string personality { get; set; }

	[JsonProperty("talkingTime")]
	public float talkingTime { get; set; }

	[JsonProperty("ariel_speaker")]
	public string arielSpeaker { get; set; }

	public Valuable(string asset, string name, bool useSTT, string personality, float talkingTime, string arielSpeaker)
	{
		this.asset = asset;
		this.name = name;
		this.useSTT = useSTT;
		this.personality = personality;
		this.talkingTime = talkingTime;
		this.arielSpeaker = arielSpeaker;
	}
}
public class ValuableInteraction : MonoBehaviourPunCallbacks
{
	public class Message
	{
		public string message;

		public AudioClip? audio;

		public bool played;

		public Message(string msg)
		{
			message = msg;
			audio = null;
			played = false;
		}
	}

	public struct DiagenResponse
	{
		public string StatusMessage;

		public readonly bool Error;

		public readonly string? ErrorMessage;

		public DiagenResponse(string errorMessage, bool isError)
		{
			StatusMessage = (isError ? errorMessage : "");
			Error = isError;
			ErrorMessage = (isError ? errorMessage : null);
		}

		public DiagenResponse(string statusMessage)
		{
			StatusMessage = statusMessage;
			Error = false;
			ErrorMessage = null;
		}
	}

	private struct DiagenRequestData
	{
		public string npc_name;

		public string player_name;

		public string core_description;

		public object llama_generation_params;

		public int history_length;

		public string[] history;
	}

	public struct ArielResponse
	{
		public AudioClip? audioClip;

		public readonly bool Error;

		public readonly string? StatusMessage;

		public ArielResponse(string statusMessage, bool isError = false)
		{
			audioClip = null;
			Error = isError;
			StatusMessage = statusMessage;
		}

		public ArielResponse(AudioClip audioClip, string statusMessage)
		{
			Error = false;
			this.audioClip = audioClip;
			StatusMessage = statusMessage;
		}
	}

	public struct ArielRequestData
	{
		public string sentence;

		public string audio_stream;

		public float temperature;

		public bool static_save;
	}

	private PhysGrabObject? physGrabObject;

	private AudioSource? audioSource;

	public ArielSound? voiceMessage;

	private PhotonView photonView;

	private Task? diagenTask = null;

	private Task? arielTask = null;

	private Root settings;

	private Valuable valuable;

	[Header("API Keys & Settings")]
	public string DiagenApiKey = "dd82386c-8ea9-4cd3-85b0-9dbad5216be7";

	public string ArielApiKey = "8a58d8c8-6a61-438b-8d95-6723b3d8aa1b";

	private int apiErrorCount = 0;

	public string ArielSpeaker = "Kid 3";

	public float talkingTime = 15f;

	public string Personality = "You are a weird Vodoo Doll that is super annoyed by the player that it is being disturbed.";

	private string Instruction = "You try to be as annoying as possible to the player.";

	public string PlayerName = "Player";

	public string NpcName = "Alan";

	private const int HistoryLength = 10;

	public List<Message> messages = new List<Message>();

	private bool isSpeakingSessionActive = false;

	private float currentSessionTimeRemaining = 0f;

	private int nextMessageToPlayIndex = 0;

	private void Start()
	{
		photonView = ((Component)this).GetComponent<PhotonView>();
		if ((Object)(object)photonView == (Object)null)
		{
			Debug.LogError((object)"ValuableInteraction is missing a PhotonView component. Please add one.");
			((Behaviour)this).enabled = false;
			return;
		}
		if ((Object)(object)((Component)this).GetComponent<AudioSource>() == (Object)null)
		{
			audioSource = ((Component)this).gameObject.AddComponent<AudioSource>();
		}
		else
		{
			audioSource = ((Component)this).GetComponent<AudioSource>();
		}
		string filePath = Path.Combine(Paths.PluginPath, "XandImmersion-RepoXandIMod", "settings.json");
		settings = SettingsLoader.Load(filePath);
		DiagenApiKey = settings.keys.diagen;
		ArielApiKey = settings.keys.ariel;
		valuable = settings.assets.valuables.FirstOrDefault((Valuable v) => ((Object)this).name.Contains(v.asset, StringComparison.OrdinalIgnoreCase));
		if (valuable == null)
		{
			valuable = new Valuable(((Object)this).name, NpcName, useSTT: true, Personality, talkingTime, ArielSpeaker);
		}
		physGrabObject = ((Component)this).GetComponent<PhysGrabObject>();
		if ((Object)(object)physGrabObject == (Object)null)
		{
			Debug.LogWarning((object)"PhysGrabObject not found on this GameObject.");
		}
		else
		{
			Debug.Log((object)"PhysGrabObject successfully accessed!");
		}
		Debug.Log((object)"Listing all components on this GameObject:");
		Component[] components = ((Component)this).GetComponents<Component>();
		foreach (Component val in components)
		{
			Debug.Log((object)(" - " + ((object)val).GetType().Name));
		}
		voiceMessage = new ArielSound();
	}

	private void Update()
	{
		if (PhotonNetwork.IsMasterClient)
		{
			MasterClientUpdate();
		}
		else if (isSpeakingSessionActive)
		{
			currentSessionTimeRemaining -= Time.deltaTime;
			if (currentSessionTimeRemaining < 0f)
			{
				currentSessionTimeRemaining = 0f;
			}
		}
	}

	private void MasterClientUpdate()
	{
		if (apiErrorCount > 10)
		{
			return;
		}
		int num = messages.Count((Message m) => !m.played);
		if (!isSpeakingSessionActive)
		{
			bool flag = false;
			PlayerAvatar[] array = Object.FindObjectsOfType<PlayerAvatar>();
			PlayerAvatar[] array2 = array;
			foreach (PlayerAvatar playerAvatar in array2)
			{
				if (PlayerIsInSight(playerAvatar) && PlayerIsTalking(playerAvatar))
				{
					flag = true;
					break;
				}
			}
			if (flag && ((Object)(object)audioSource == (Object)null || !audioSource.isPlaying) && num > 0)
			{
				photonView.RPC("StartSpeakingSessionRPC", (RpcTarget)0, new object[1] { valuable.talkingTime });
			}
		}
		else
		{
			currentSessionTimeRemaining -= Time.deltaTime;
			if (currentSessionTimeRemaining <= 0f && ((Object)(object)audioSource == (Object)null || !audioSource.isPlaying))
			{
				photonView.RPC("StopSpeakingSessionRPC", (RpcTarget)0, Array.Empty<object>());
			}
			else if ((Object)(object)audioSource == (Object)null || !audioSource.isPlaying)
			{
				int num2 = FindNextUnplayedMessageIndex(-1);
				if (num2 < messages.Count)
				{
					Message message = messages[num2];
					if ((Object)(object)message.audio != (Object)null && !message.played)
					{
						photonView.RPC("PlayMessageRPC", (RpcTarget)0, new object[1] { num2 });
					}
					else if ((Object)(object)message.audio == (Object)null && !message.played && (arielTask == null || arielTask.IsCompleted))
					{
						arielTask = HandleArielAsyncCall(num2, message.message);
					}
				}
			}
		}
		if (num <= 2 && (diagenTask == null || diagenTask.IsCompleted))
		{
			diagenTask = HandleDiagenInteractionAsync();
		}
		if (messages.Count <= 0 || (arielTask != null && !arielTask.IsCompleted))
		{
			return;
		}
		for (int j = 0; j < messages.Count; j++)
		{
			if ((Object)(object)messages[j].audio == (Object)null && !messages[j].played)
			{
				arielTask = HandleArielAsyncCall(j, messages[j].message);
				break;
			}
		}
	}

	private void AttemptPlayMessageAtIndex(int messageIndex)
	{
		if (messageIndex >= messages.Count || messageIndex < 0)
		{
			return;
		}
		Message message = messages[messageIndex];
		if (!((Object)(object)message.audio != (Object)null) || message.played)
		{
			return;
		}
		if (voiceMessage == null)
		{
			voiceMessage = new ArielSound();
		}
		if ((Object)(object)physGrabObject != (Object)null)
		{
			voiceMessage.Sounds = new List<AudioClip> { message.audio };
			Debug.Log((object)$"Time: [{Time.time}]AttemptPlayMessageAtIndex: Playing message {messageIndex} ('{message.message}') with physGrabObject context.");
			AudioSource val = voiceMessage.Play(audioSource);
			if ((Object)(object)val != (Object)null)
			{
				audioSource = val;
			}
		}
		else
		{
			Debug.LogWarning((object)$"AttemptPlayMessageAtIndex: physGrabObject is null for message {messageIndex}. Cannot determine play position.");
			audioSource.clip = message.audio;
			audioSource.Play();
		}
	}

	[PunRPC]
	private void StartSpeakingSessionRPC(float duration)
	{
		isSpeakingSessionActive = true;
		currentSessionTimeRemaining = duration;
		Debug.Log((object)$"RPC: Speaking session started by Master. Duration: {duration}");
	}

	[PunRPC]
	private void StopSpeakingSessionRPC()
	{
		isSpeakingSessionActive = false;
		currentSessionTimeRemaining = 0f;
		if ((Object)(object)audioSource != (Object)null && audioSource.isPlaying)
		{
			audioSource.Stop();
		}
		Debug.Log((object)"RPC: Speaking session stopped by Master.");
	}

	[PunRPC]
	private void AddNewMessagesRPC(string[] newDialogues)
	{
		bool flag = false;
		foreach (string dialogue in newDialogues)
		{
			if (!string.IsNullOrWhiteSpace(dialogue) && !messages.Any((Message m) => m.message == dialogue.Trim()))
			{
				messages.Add(new Message(dialogue.Trim()));
				flag = true;
			}
		}
		if (flag)
		{
			Debug.Log((object)$"RPC: Added {newDialogues.Length} new message(s). Total messages: {messages.Count}");
		}
	}

	[PunRPC]
	private async void PlayMessageRPC(int messageIndex)
	{
		if (messageIndex < 0 || messageIndex >= messages.Count)
		{
			Debug.LogError((object)$"PlayMessageRPC: Invalid index {messageIndex}. Total messages: {messages.Count}");
			return;
		}
		Message messageToPlay = messages[messageIndex];
		if (messageToPlay.played && !PhotonNetwork.IsMasterClient)
		{
			Debug.LogWarning((object)$"PlayMessageRPC: Client already marked message {messageIndex} as played. Will play again if audio source is free.");
		}
		if ((Object)(object)messageToPlay.audio == (Object)null)
		{
			Debug.Log((object)$"PlayMessageRPC: Message {messageIndex} ('{messageToPlay.message}') has no audio locally. Attempting to fetch.");
			AudioClip fetchedAudio = await CallAriel(messageToPlay.message);
			if (!((Object)(object)fetchedAudio != (Object)null))
			{
				Debug.LogError((object)$"PlayMessageRPC: Failed to fetch audio for message {messageIndex} ('{messageToPlay.message}'). Cannot play.");
				return;
			}
			messageToPlay.audio = fetchedAudio;
		}
		AttemptPlayMessageAtIndex(messageIndex);
		if (!messageToPlay.played)
		{
			messageToPlay.played = true;
			Debug.Log((object)$"RPC: Message {messageIndex} ('{messageToPlay.message}') is now being played and marked as played.");
		}
		else
		{
			Debug.Log((object)$"RPC: Message {messageIndex} ('{messageToPlay.message}') was already marked played, re-playing.");
		}
	}

	private async Task HandleDiagenInteractionAsync()
	{
		if (!PhotonNetwork.IsMasterClient)
		{
			return;
		}
		try
		{
			int originalMessageCount = messages.Count;
			if (await CallDiagen() && messages.Count > originalMessageCount)
			{
				List<string> newTexts = new List<string>();
				for (int i = originalMessageCount; i < messages.Count; i++)
				{
					newTexts.Add(messages[i].message);
				}
				PhotonView obj = photonView;
				object[] array = newTexts.ToArray();
				obj.RPC("AddNewMessagesRPC", (RpcTarget)3, array);
			}
		}
		catch (Exception ex)
		{
			Debug.LogError((object)$"Master HandleDiagenInteractionAsync Exception: {ex}");
		}
	}

	private async Task HandleArielAsyncCall(int index, string message)
	{
		if (PhotonNetwork.IsMasterClient && index >= 0 && index < messages.Count && (Object)(object)messages[index].audio == (Object)null)
		{
			AudioClip audioClip = await CallAriel(message);
			if ((Object)(object)audioClip != (Object)null)
			{
				messages[index].audio = audioClip;
				Debug.Log((object)$"Master HandleArielAsyncCall: Audio fetched for message index {index}.");
			}
		}
	}

	public async Task<AudioClip?> CallAriel(string sentence)
	{
		ArielResponse arielResponse = await TextToAudio(sentence, valuable.arielSpeaker, ArielApiKey);
		if (arielResponse.Error)
		{
			Debug.LogError((object)("CallAriel API Error: " + arielResponse.StatusMessage + " for sentence: " + sentence));
			if (PhotonNetwork.IsMasterClient)
			{
				apiErrorCount++;
			}
			return null;
		}
		return arielResponse.audioClip;
	}

	private int FindNextUnplayedMessageIndex(int searchStartIndex)
	{
		for (int i = searchStartIndex + 1; i < messages.Count; i++)
		{
			if (!messages[i].played && (Object)(object)messages[i].audio != (Object)null)
			{
				return i;
			}
			if ((Object)(object)messages[i].audio == (Object)null && !messages[i].played)
			{
				return messages.Count;
			}
		}
		return messages.Count;
	}

	private bool PlayerIsInSight(PlayerAvatar playerAvatar)
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		Vector3 position = ((Component)this).transform.position;
		if ((Object)(object)playerAvatar == (Object)null || (Object)(object)((Component)playerAvatar).transform == (Object)null)
		{
			Debug.LogError((object)"[Interaction] PlayerAvatar is null or its transform is null.");
			return false;
		}
		Vector3 position2 = ((Component)playerAvatar).transform.position;
		RaycastHit val = default(RaycastHit);
		bool flag = Physics.Linecast(position, position2, ref val);
		float num = Vector3.Distance(position, position2);
		return num <= 6f && flag;
	}

	private bool PlayerIsTalking(PlayerAvatar playerAvatar, float volumeThreshold = 0.001f)
	{
		if ((Object)(object)playerAvatar == (Object)null)
		{
			return false;
		}
		if ((Object)(object)playerAvatar.voiceChat == (Object)null)
		{
			return false;
		}
		return playerAvatar.voiceChat.isTalking && playerAvatar.voiceChat.clipLoudness > volumeThreshold;
	}

	public async Task<bool> CallDiagen()
	{
		CleanupHistory();
		DiagenResponse diagenResponse = await GenerateText(valuable.name, Instruction, valuable.personality, PlayerName, "Api-Key " + DiagenApiKey);
		if (diagenResponse.Error)
		{
			Debug.LogError((object)("Diagen API Error: " + diagenResponse.ErrorMessage));
			return false;
		}
		return true;
	}

	private void CleanupHistory()
	{
		if (messages.Count > 10)
		{
			int count = messages.Count - 10;
			messages.RemoveRange(0, count);
		}
	}

	public async Task<DiagenResponse> GenerateText(string npc_name, string instruction, string core_description, string player_name = "Player", string apiKey = "")
	{
		if (string.IsNullOrEmpty(apiKey))
		{
			Debug.LogError((object)"[PlayAriel] API Key is empty or null.");
			return new DiagenResponse("API Key is required.", isError: true);
		}
		string[] history = new string[0];
		int index = 0;
		foreach (Message msg2 in this.messages)
		{
			history = ((index % 2 != 0) ? new string[0] : new string[1] { msg2.message });
			index++;
		}
		DiagenRequestData requestData = new DiagenRequestData
		{
			npc_name = npc_name,
			player_name = player_name,
			core_description = core_description + " Answer in no more than 3 sentences.",
			llama_generation_params = new
			{
				max_tokens = 80,
				temperature = 1.243,
				stream = true
			},
			history_length = 10,
			history = history
		};
		string jsonBody = JsonConvert.SerializeObject((object)requestData);
		byte[] bodyRaw = Encoding.UTF8.GetBytes(jsonBody);
		string url = "https://diagen-api.xandimmersion.com/generate-stream";
		UnityWebRequest www = new UnityWebRequest(url, "POST");
		try
		{
			www.uploadHandler = (UploadHandler)new UploadHandlerRaw(bodyRaw);
			www.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
			www.SetRequestHeader("Content-Type", "application/json");
			www.SetRequestHeader("Authorization", apiKey);
			UnityWebRequestAsyncOperation operation = www.SendWebRequest();
			while (!((AsyncOperation)operation).isDone)
			{
				await Task.Yield();
			}
			if ((int)www.result == 1)
			{
				string responseText = www.downloadHandler.text;
				string[] messages = Regex.Replace(responseText, "\\s+", " ").Split(new char[3] { '.', '!', '?' }, StringSplitOptions.RemoveEmptyEntries);
				if (messages.Length == 0 && !string.IsNullOrEmpty(responseText))
				{
					messages = new string[1] { responseText };
				}
				string[] array = messages;
				foreach (string msg in array)
				{
					if (!string.IsNullOrWhiteSpace(msg))
					{
						this.messages.Add(new Message(msg.Trim()));
					}
				}
				return new DiagenResponse("Stream processed successfully.");
			}
			Debug.LogError((object)("[PlayAriel] Diagen API Error: " + www.error));
			Debug.LogError((object)$"[PlayAriel] Diagen API Response Code: {www.responseCode}");
			string errorDetails = www.error ?? "Unknown error";
			if (www.downloadHandler != null && !string.IsNullOrEmpty(www.downloadHandler.text))
			{
				errorDetails = errorDetails + ". Body: " + www.downloadHandler.text;
			}
			apiErrorCount++;
			Debug.LogError((object)("[PlayAriel] Full Diagen API Error Details: " + errorDetails));
			return new DiagenResponse($"Diagen API Error ({www.responseCode}): {www.error}", isError: true);
		}
		finally
		{
			((IDisposable)www)?.Dispose();
		}
	}

	public async Task<ArielResponse> TextToAudio(string sentence, string speaker, string apiKey = "")
	{
		string url = "https://ariel-api.xandimmersion.com/tts/" + Uri.EscapeDataString(speaker);
		ArielRequestData requestData = new ArielRequestData
		{
			sentence = sentence,
			audio_stream = "true",
			temperature = 0f,
			static_save = true
		};
		string jsonBody = JsonConvert.SerializeObject((object)requestData);
		byte[] bodyRaw = Encoding.UTF8.GetBytes(jsonBody);
		UnityWebRequest www = new UnityWebRequest(url, "POST");
		try
		{
			www.uploadHandler = (UploadHandler)new UploadHandlerRaw(bodyRaw);
			www.downloadHandler = (DownloadHandler)new DownloadHandlerAudioClip(www.uri, (AudioType)20);
			www.SetRequestHeader("Content-Type", "application/json");
			www.SetRequestHeader("Authorization", "Api-Key " + apiKey);
			UnityWebRequestAsyncOperation operation = www.SendWebRequest();
			while (!((AsyncOperation)operation).isDone)
			{
				await Task.Yield();
			}
			if ((int)www.result != 1)
			{
				apiErrorCount++;
				return new ArielResponse("Error While Sending: " + www.error, isError: true);
			}
			AudioClip audioClip = DownloadHandlerAudioClip.GetContent(www);
			if ((Object)(object)audioClip != (Object)null)
			{
				return new ArielResponse(audioClip, "AudioClip created succesfully.");
			}
			return new ArielResponse("AudioClip creation failed");
		}
		finally
		{
			((IDisposable)www)?.Dispose();
		}
	}
}
namespace RepoXandIMod
{
	[BepInPlugin("XandImmersion.RepoXandIMod", "RepoXandIMod", "1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class RepoXandIMod : BaseUnityPlugin
	{
		private void Awake()
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"RepoXandIMod loaded!");
		}
	}
}