1
0
forked from cgvr/DeltaVR

Merge branch 'SamWorkset'

This commit is contained in:
2026-01-03 13:46:54 +02:00
1858 changed files with 148220 additions and 9923 deletions

View File

@@ -0,0 +1,330 @@
using FMOD.Studio;
using FMODUnity;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEditor;
using UnityEngine;
using UnityEngine.SceneManagement;
using STOP_MODE = FMOD.Studio.STOP_MODE;
public class AudioManager : MonoBehaviour
{
//VCAs (VCA buses) are mainly used for volume control
//Regular routing buses routing are for the remaining logic, for example, within the FMOD itself to put FMOD events inside the Mixer (Mixer Routing).
//Regular routing buses are used when we make some attenuation based on parameters and write the logic in code for Unity.
private VCA masterVCA;
private VCA musicVCA;
private VCA sfxVCA;
private VCA uiVCA;
private VCA ambienceVCA;
[SerializeField]
[Header("Volume")]
[Range(0, 1)]
public float MasterVolume = 0.5f;
[Range(0, 1)]
public float MusicVolume = 0.5f;
[Range(0, 1)]
public float AmbienceVolume = 0.5f;
[Range(0, 1)]
public float SFXVolume = 0.5f;
[Range(0, 1)]
public float UIVolume = 0.5f;
[Range(0, 1)]
private Bus masterBus;
private Bus ambientBus;
private Bus musicBus;
private Bus sfxBus;
private Bus uiBus;
const string sid = "00000000-0000-0000-0000-000000000000";
static readonly Guid nullGuid = new Guid(sid);
private List<EventInstance> eventInstances = new();
class TimelineInfo
{
public FMOD.StringWrapper LastMarker = new();
}
TimelineInfo timelineInfo;
GCHandle timelineHandle;
EVENT_CALLBACK beatCallback;
private static AudioManager _instance { get; set; }
// public static AudioManager instance;
private static EventInstance musicEventInstance;
// public access for the Singleton
// and lazy instantiation if not exists
public static AudioManager Instance
{
get
{
// if exists directly return
if (_instance) return _instance;
// otherwise search it in the scene
_instance = FindObjectOfType<AudioManager>();
// found it?
if (_instance) return _instance;
// otherwise create and initialize it
CreateInstance();
return _instance;
}
}
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
private static void CreateInstance()
{
// skip if already exists
if (_instance) return;
if (SceneManager.GetActiveScene().name == "BankLoader") return;
InitializeInstance(new GameObject(nameof(AudioManager)).AddComponent<AudioManager>());
}
private static void InitializeInstance(AudioManager instance)
{
_instance = instance;
DontDestroyOnLoad(_instance.gameObject);
_instance.eventInstances = new List<EventInstance>();
_instance.masterBus = RuntimeManager.GetBus("bus:/");
_instance.musicBus = RuntimeManager.GetBus("bus:/Music");
_instance.ambientBus = RuntimeManager.GetBus("bus:/Ambiences");
_instance.sfxBus = RuntimeManager.GetBus("bus:/SFX");
_instance.uiBus = RuntimeManager.GetBus("bus:/UI");
_instance.masterVCA = RuntimeManager.GetVCA("vca:/Master");
_instance.musicVCA = RuntimeManager.GetVCA("vca:/Music");
_instance.ambienceVCA = RuntimeManager.GetVCA("vca:/Ambiences");
_instance.sfxVCA = RuntimeManager.GetVCA("vca:/SFX");
_instance.uiVCA = RuntimeManager.GetVCA("vca:/UI");
_instance.masterVCA.setVolume(_instance.MasterVolume);
_instance.musicVCA.setVolume(_instance.MusicVolume);
_instance.ambienceVCA.setVolume(_instance.AmbienceVolume);
_instance.sfxVCA.setVolume(_instance.SFXVolume);
_instance.uiVCA.setVolume(_instance.UIVolume);
}
public void SetMasterVCA(float value)
{
MasterVolume = value;
masterVCA.setVolume(MasterVolume);
}
public void SetMusicVCA(float value)
{
MusicVolume = value;
musicVCA.setVolume(MusicVolume);
}
public void SetAmbientVCA(float value)
{
AmbienceVolume = value;
ambienceVCA.setVolume(AmbienceVolume);
}
public void SetSFXVCA(float value)
{
SFXVolume = value;
sfxVCA.setVolume(SFXVolume);
}
public void SetUIVCA(float value)
{
UIVolume = value;
uiVCA.setVolume(UIVolume);
}
private void Awake()
{
if (_instance && _instance != this)
{
Destroy(gameObject);
return;
}
InitializeInstance(this);
}
public EventInstance CreateInstance(EventReference eventReference)
{
EventInstance eventInstance = RuntimeManager.CreateInstance(eventReference);
eventInstances.Add(eventInstance);
return eventInstance;
}
public static bool IsEventReferenceValid(EventReference eventReference)
{
return eventReference.Guid != nullGuid;
}
public static void PlayOneShot(EventReference eventReference)
{
if (eventReference.Guid != nullGuid)
RuntimeManager.PlayOneShot(eventReference);
else
{
Debug.LogWarning("EventReference is null, ignoring...");
}
}
public void PlayOneShot3D(EventReference sound, Vector3 position)
{
if (!IsEventReferenceValid(sound))
{
Debug.LogWarning("Tried to play invalid FMOD event (3D)");
return;
}
RuntimeManager.PlayOneShot(sound, position);
}
public EventInstance PlayAttachedInstance(EventReference sound, GameObject go)
{
if (!IsEventReferenceValid(sound))
{
Debug.LogWarning("Tried to play invalid FMOD event (attached)");
return default;
}
EventInstance instance = RuntimeManager.CreateInstance(sound);
RuntimeManager.AttachInstanceToGameObject(instance, go);
instance.start();
// instance.release();
eventInstances.Add(instance);
return instance;
}
public void StopInstance(EventInstance instance, STOP_MODE mode = STOP_MODE.ALLOWFADEOUT)
{
if (!instance.isValid()) return;
instance.stop(mode);
instance.release();
}
public void SetParameter(EventInstance instance, string parameterName, float value)
{
if (!instance.isValid()) return;
instance.setParameterByName(parameterName, value);
}
public void SetGlobalParameter(string parameterName, float value)
{
RuntimeManager.StudioSystem.setParameterByName(parameterName, value);
}
public void GetGlobalParameter(string parameterName, out float value)
{
RuntimeManager.StudioSystem.getParameterByName(parameterName, out value);
}
//=====//
//Some functions for initialising music, perhaps there will be a need in the future...
//=====//
public void InitializeMusic(EventReference musicEventReference)
{
if (musicEventReference.Guid == nullGuid)
{
Debug.LogWarning("EventReference is null, ignoring.");
return;
}
musicEventInstance = CreateInstance(musicEventReference);
}
public void SetMusicParameter(string parameter, float value)
{
musicEventInstance.setParameterByName(parameter, value);
}
public void StartMusic()
{
if (!musicEventInstance.isValid())
{
Debug.LogWarning("Music is not initialized yet, ignoring.");
return;
}
musicEventInstance.start();
}
public int GetMusicPosition()
{
musicEventInstance.getTimelinePosition(out int position);
return position;
}
public void FadeOutMusic()
{
musicEventInstance.stop(FMOD.Studio.STOP_MODE.ALLOWFADEOUT);
musicEventInstance.release();
}
//=====//
//=====//
public void StopSFX()
{
sfxBus.stopAllEvents(FMOD.Studio.STOP_MODE.IMMEDIATE);
}
public static bool IsPlaying(EventInstance instance)
{
instance.getPlaybackState(out PLAYBACK_STATE state);
return state != PLAYBACK_STATE.STOPPED;
}
public static void Unpause()
{
musicEventInstance.setPaused(false);
}
public static void Unpause(EventInstance instance)
{
instance.setPaused(false);
}
public static void Pause()
{
musicEventInstance.setPaused(true);
}
public static void Pause(EventInstance instance)
{
instance.setPaused(true);
}
private void CleanUp()
{
if (eventInstances != null)
{
foreach (EventInstance eventInstance in eventInstances)
{
eventInstance.stop(FMOD.Studio.STOP_MODE.IMMEDIATE);
eventInstance.release();
}
}
}
private void OnDestroy()
{
CleanUp();
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c87d04403eccfb742b177e2556692f35
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: -20
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,82 @@
using FMODUnity;
using UnityEngine;
public class FMODEvents : MonoBehaviour
{
[field: Header("Musical Ambiences")]
[field: SerializeField] public EventReference Kosmos { get; private set; }
[field: Header("SFX")]
[field: SerializeField] public EventReference Steps { get; private set; }
[field: SerializeField] public EventReference StepSpin { get; private set; }
[field: SerializeField] public EventReference StepOverall { get; private set; }
[field: SerializeField] public EventReference Teleport { get; private set; }
[field: SerializeField] public EventReference UFODestroy { get; private set; }
[field: SerializeField] public EventReference PortalEnter { get; private set; }
[field: SerializeField] public EventReference SprayerGrab { get; private set; }
[field: SerializeField] public EventReference DefaultGrab { get; private set; }
[field: SerializeField] public EventReference BowGrab { get; private set; }
[field: SerializeField] public EventReference Spray { get; private set; }
[field: SerializeField] public EventReference Coughing { get; private set; }
[field: Header("CAR")]
[field: SerializeField] public EventReference DoorOpen { get; private set; }
[field: SerializeField] public EventReference DoorClose { get; private set; }
[field: SerializeField] public EventReference CarModulatedDriving { get; private set; }
[field: Header("UI")]
[field: SerializeField] public EventReference Click { get; private set; }
[field: SerializeField] public EventReference MapOpen { get; private set; }
[field: SerializeField] public EventReference Hover { get; private set; }
[field: SerializeField] public EventReference LetterEnter { get; private set; }
[field: SerializeField] public EventReference LetterHover { get; private set; }
[field: Header("Initial events")]
[field: SerializeField] public EventReference PortalSpacial { get; private set; }
[field: SerializeField] public EventReference UfoPassing { get; private set; }
[field: SerializeField] public EventReference BowArrowHit { get; private set; }
[field: SerializeField] public EventReference BowArrowNock { get; private set; }
[field: SerializeField] public EventReference BowArrowRelease { get; private set; }
[field: SerializeField] public EventReference BowPullback { get; private set; }
[field: SerializeField] public EventReference BowPullbackMax { get; private set; }
[field: SerializeField] public EventReference ElevatorDoorClosing { get; private set; }
[field: SerializeField] public EventReference ElevatorDoorOpening { get; private set; }
[field: SerializeField] public EventReference ElevatorArrival { get; private set; }
[field: SerializeField] public EventReference ElevatorMovement { get; private set; }
[field: SerializeField] public EventReference BoltCarStopSound { get; private set; }
[field: SerializeField] public EventReference BoltCarSimpleDriving { get; private set; }
[field: SerializeField] public EventReference BoltCarHorn { get; private set; }
[field: SerializeField] public EventReference ServerRoomAlarm { get; private set; }
[field: SerializeField] public EventReference ServerRoomButton { get; private set; }
[field: SerializeField] public EventReference ServerRoomHumming { get; private set; }
[field: SerializeField] public EventReference ServerRoomRackHum { get; private set; }
[field: SerializeField] public EventReference Jackal { get; private set; }
[field: SerializeField] public EventReference Robotont { get; private set; }
public static FMODEvents Instance { get; private set; }
public enum GrabSoundType
{
Default,
Bow,
Sprayer
}
private void Awake()
{
if (Instance != null)
{
return;
}
Instance = this;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f7db9618133cf954a8f3392be7f313b3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: -10
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,208 @@
using UnityEngine;
using FMODUnity;
using FMOD.Studio;
using System.Collections;
using System.Collections.Generic;
public class FirstPersonOcclusion : MonoBehaviour
{
[Header("FMOD Event")]
[SerializeField] private EventReference SelectAudio;
private EventInstance AudioOccluded;
private EventDescription AudioDes;
private StudioListener Listener;
private PLAYBACK_STATE pb;
[Header("Occlusion Options")]
[SerializeField][Range(0f, 10f)] private float SoundOcclusionWidening = 1f;
[SerializeField][Range(0f, 10f)] private float PlayerOcclusionWidening = 1f;
[SerializeField] private LayerMask OcclusionLayer;
private bool AudioIsVirtual;
private float MaxDistance;
private float ListenerDistance;
private float lineCastHitCount = 0f;
private Color colour;
private bool initialisedExternally = false;
private List<EventInstance> managedInstances = new List<EventInstance>();
public void InitialiseWithInstance(EventInstance instance)
{
AudioOccluded = instance;
initialisedExternally = true;
RuntimeManager.AttachInstanceToGameObject(
AudioOccluded,
gameObject,
GetComponent<Rigidbody>()
);
//instance.setParameterByName("Occlusion", 1f, true);
managedInstances.Add(AudioOccluded);
AudioOccluded.getDescription(out AudioDes);
AudioDes.getMinMaxDistance(out float min, out MaxDistance);
}
public void AddInstance(EventInstance instance)
{
if (instance.isValid())
{
RuntimeManager.AttachInstanceToGameObject(
instance,
gameObject,
GetComponent<Rigidbody>()
);
managedInstances.Add(instance);
}
}
private IEnumerator Start()
{
// If already initialised, skip internal creation
// 1. Event Instance Creation
if (!initialisedExternally)
{
AudioOccluded = RuntimeManager.CreateInstance(SelectAudio);
// 2. Attaching Instance
RuntimeManager.AttachInstanceToGameObject(AudioOccluded, gameObject);
// 3. Starting Audio
AudioOccluded.start();
// 4. Releasing Instance (This allows the event to self-manage its lifetime, which is fine)
AudioOccluded.release();
managedInstances.Add(AudioOccluded); // ADDED
// 5. Getting Event Description and Max Distance
AudioDes = RuntimeManager.GetEventDescription(SelectAudio);
AudioDes.getMinMaxDistance(out float minDistance, out MaxDistance);
}
// 6. Finding Listener
yield return new WaitUntil(() => FindObjectOfType<StudioListener>() != null);
Listener = FindObjectOfType<StudioListener>();
}
private void FixedUpdate()
{
if (Listener == null) return;
AudioOccluded.isVirtual(out AudioIsVirtual);
AudioOccluded.getPlaybackState(out pb);
ListenerDistance = Vector3.Distance(transform.position, Listener.transform.position);
// 7. Check Occlusion Condition
if (!AudioIsVirtual && pb == PLAYBACK_STATE.PLAYING && ListenerDistance <= MaxDistance)
{
OccludeBetween(transform.position, Listener.transform.position);
}
// 8. Reset Hit Count
lineCastHitCount = 0f;
}
private void OccludeBetween(Vector3 sound, Vector3 listener)
{
// 9. Calculate Points (Log only a few to avoid clutter)
Vector3 SoundLeft = CalculatePoint(sound, listener, SoundOcclusionWidening, true);
Vector3 SoundRight = CalculatePoint(sound, listener, SoundOcclusionWidening, false);
Vector3 ListenerLeft = CalculatePoint(listener, sound, PlayerOcclusionWidening, true);
Vector3 ListenerRight = CalculatePoint(listener, sound, PlayerOcclusionWidening, false);
Vector3 SoundAbove = new Vector3(sound.x, sound.y + SoundOcclusionWidening, sound.z);
Vector3 SoundBelow = new Vector3(sound.x, sound.y - SoundOcclusionWidening, sound.z);
Vector3 ListenerAbove = new Vector3(listener.x, listener.y + PlayerOcclusionWidening * .5f, listener.z);
Vector3 ListenerBelow = new Vector3(listener.x, listener.y - PlayerOcclusionWidening * .5f, listener.z);
// 10. Casting Lines (The line casts themselves will log hits)
CastLine(SoundLeft, ListenerLeft);
CastLine(SoundLeft, listener);
CastLine(SoundLeft, ListenerRight);
CastLine(sound, ListenerLeft);
CastLine(sound, listener);
CastLine(sound, ListenerRight);
CastLine(SoundRight, ListenerLeft);
CastLine(SoundRight, listener);
CastLine(SoundRight, ListenerRight);
CastLine(SoundAbove, ListenerAbove);
CastLine(SoundBelow, ListenerBelow);
colour = (PlayerOcclusionWidening == 0f || SoundOcclusionWidening == 0f) ? Color.blue : Color.green;
SetParameter();
}
private Vector3 CalculatePoint(Vector3 a, Vector3 b, float m, bool posOrneg)
{
float n = Vector3.Distance(new Vector3(a.x, 0f, a.z), new Vector3(b.x, 0f, b.z));
if (n == 0f) return a;
float mn = (m / n);
float x, z;
if (posOrneg)
{
x = a.x + (mn * (a.z - b.z));
z = a.z - (mn * (a.x - b.x));
}
else
{
x = a.x - (mn * (a.z - b.z));
z = a.z + (mn * (a.x - b.x));
}
return new Vector3(x, a.y, z);
}
private void CastLine(Vector3 Start, Vector3 End)
{
RaycastHit hit;
// 11. Raycast result
bool isHit = Physics.Linecast(Start, End, out hit, OcclusionLayer);
if (isHit)
{
lineCastHitCount++;
//Debug.DrawLine(Start, End, Color.red);
}
else
{
//Debug.DrawLine(Start, End, colour);
}
}
public bool HasInstance(EventInstance instance)
{
return managedInstances.Contains(instance);
}
private void SetParameter()
{
float occlusionValue = lineCastHitCount / 11;
// 12. Final Parameter Value
foreach (var inst in managedInstances)
{
if (inst.isValid())
{
inst.setParameterByName("Occlusion", occlusionValue);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6c6205a218222364ca440c740b7a6b8f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 300
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,35 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LoadBankAndScene : MonoBehaviour
{
[FMODUnity.BankRef]
public List<string> banks;
public static event Action OnBanksLoaded;
private void Awake()
{
LoadBanks();
}
public void LoadBanks()
{
foreach (string b in banks)
{
FMODUnity.RuntimeManager.LoadBank(b, true);
Debug.Log("Loaded bank " + b);
}
StartCoroutine(CheckBanksLoaded());
}
IEnumerator CheckBanksLoaded()
{
while (!FMODUnity.RuntimeManager.HaveAllBanksLoaded)
{
yield return null;
}
OnBanksLoaded?.Invoke();
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 26520d10d6a04d84fbbdad4ae135f015
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: