mirror of
https://github.com/RHeavenStudio/HeavenStudio.git
synced 2025-06-12 08:17:38 +02:00
Configurable Event Priority & Bugfixes (#209)
* add event priority fix crop stomp queuing inputs while chart is paused fix rhythm tweezers not killing queued inputs when switching veggies * file cleanup * remove debug print * remove more files
This commit is contained in:
@ -1,140 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HeavenStudio
|
||||
{
|
||||
public class AudioDspTimeKeeper : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private List<double> xValuesL = new List<double>();
|
||||
[SerializeField] private List<double> yValuesL = new List<double>();
|
||||
|
||||
private double coeff1, coeff2;
|
||||
|
||||
private double audioDspStartTime;
|
||||
|
||||
private AudioSource audioSource;
|
||||
|
||||
public double currentSmoothedDSPTime;
|
||||
|
||||
public double dspTime;
|
||||
public float audioTime;
|
||||
|
||||
private double musicDrift;
|
||||
|
||||
private Conductor conductor;
|
||||
|
||||
public float latencyAdjustment;
|
||||
|
||||
public void Play()
|
||||
{
|
||||
audioSource.PlayScheduled(audioDspStartTime);
|
||||
audioDspStartTime = AudioSettings.dspTime;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
conductor = GetComponent<Conductor>();
|
||||
audioSource = conductor.musicSource;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!audioSource.isPlaying) return;
|
||||
|
||||
float currentGameTime = Time.realtimeSinceStartup;
|
||||
double currentDspTime = AudioSettings.dspTime;
|
||||
|
||||
// Update our linear regression model by adding another data point.
|
||||
UpdateLinearRegression(currentGameTime, currentDspTime);
|
||||
CheckForDrift();
|
||||
|
||||
dspTime = GetCurrentTimeInSong();
|
||||
audioTime = audioSource.time;
|
||||
}
|
||||
|
||||
public double SmoothedDSPTime()
|
||||
{
|
||||
double result = Time.unscaledTimeAsDouble * coeff1 + coeff2;
|
||||
if (result > currentSmoothedDSPTime)
|
||||
{
|
||||
currentSmoothedDSPTime = result;
|
||||
}
|
||||
return currentSmoothedDSPTime;
|
||||
}
|
||||
|
||||
public double GetCurrentTimeInSong()
|
||||
{
|
||||
return this.SmoothedDSPTime() - audioDspStartTime - latencyAdjustment;
|
||||
}
|
||||
|
||||
private void CheckForDrift()
|
||||
{
|
||||
double timeFromDSP = this.SmoothedDSPTime() - audioDspStartTime;
|
||||
double timeFromAudioSource = audioSource.timeSamples / (float)audioSource.clip.frequency;
|
||||
|
||||
double drift = timeFromDSP - timeFromAudioSource;
|
||||
musicDrift = drift;
|
||||
|
||||
if (Mathf.Abs((float)drift) > 0.05)
|
||||
{
|
||||
Debug.LogWarningFormat("Music drift of {0} detected, resyncing!", musicDrift);
|
||||
audioDspStartTime += musicDrift;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateLinearRegression(float currentGameTime, double currentDspTime)
|
||||
{
|
||||
if (xValuesL.Count > 3000)
|
||||
{
|
||||
xValuesL.RemoveRange(0, 2000);
|
||||
yValuesL.RemoveRange(0, 2000);
|
||||
}
|
||||
|
||||
xValuesL.Add((double)currentGameTime);
|
||||
var xVals = xValuesL.ToArray();
|
||||
|
||||
yValuesL.Add((double)currentDspTime);
|
||||
var yVals = yValuesL.ToArray();
|
||||
|
||||
if (xVals.Length != yVals.Length)
|
||||
{
|
||||
throw new Exception("Input values should be with the same length.");
|
||||
}
|
||||
|
||||
double sumOfX = 0;
|
||||
double sumOfY = 0;
|
||||
double sumOfXSq = 0;
|
||||
double sumOfYSq = 0;
|
||||
double sumCodeviates = 0;
|
||||
|
||||
for (var i = 0; i < xVals.Length; i++)
|
||||
{
|
||||
var x = xVals[i];
|
||||
var y = yVals[i];
|
||||
sumCodeviates += x * y;
|
||||
sumOfX += x;
|
||||
sumOfY += y;
|
||||
sumOfXSq += x * x;
|
||||
sumOfYSq += y * y;
|
||||
}
|
||||
|
||||
var count = xVals.Length;
|
||||
var ssX = sumOfXSq - ((sumOfX * sumOfX) / count);
|
||||
var ssY = sumOfYSq - ((sumOfY * sumOfY) / count);
|
||||
|
||||
var rNumerator = (count * sumCodeviates) - (sumOfX * sumOfY);
|
||||
var rDenom = (count * sumOfXSq - (sumOfX * sumOfX)) * (count * sumOfYSq - (sumOfY * sumOfY));
|
||||
var sCo = sumCodeviates - ((sumOfX * sumOfY) / count);
|
||||
|
||||
var meanX = sumOfX / count;
|
||||
var meanY = sumOfY / count;
|
||||
var dblR = rNumerator / Math.Sqrt(rDenom);
|
||||
|
||||
// coeff1 = dblR * dblR;
|
||||
coeff2 = meanY - ((sCo / ssX) * meanX);
|
||||
coeff1 = sCo / ssX;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b2e012d929a258243a865112df346c34
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -190,7 +190,7 @@ namespace HeavenStudio
|
||||
}
|
||||
}
|
||||
|
||||
public void SeekAheadAndPreload(float start, float seekTime = 8f)
|
||||
public void SeekAheadAndPreload(double start, float seekTime = 8f)
|
||||
{
|
||||
//seek ahead to preload games that have assetbundles
|
||||
//check game switches first
|
||||
@ -217,6 +217,7 @@ namespace HeavenStudio
|
||||
if (start + seekTime >= entities[currentPreEvent])
|
||||
{
|
||||
var entitiesAtSameBeat = Beatmap.entities.FindAll(c => c.beat == Beatmap.entities[currentPreEvent].beat && !EventCaller.FXOnlyGames().Contains(EventCaller.instance.GetMinigame(c.datamodel.Split('/')[0])));
|
||||
SortEventsByPriority(entitiesAtSameBeat);
|
||||
foreach (DynamicBeatmap.DynamicEntity entity in entitiesAtSameBeat)
|
||||
{
|
||||
string gameName = entity.datamodel.Split('/')[0];
|
||||
@ -233,7 +234,7 @@ namespace HeavenStudio
|
||||
}
|
||||
}
|
||||
|
||||
public void SeekAheadAndDoPreEvent(float start, float seekTime = 2f)
|
||||
public void SeekAheadAndDoPreEvent(double start, float seekTime = 2f)
|
||||
{
|
||||
List<float> entities = Beatmap.entities.Select(c => c.beat).ToList();
|
||||
if (currentPreSequence < Beatmap.entities.Count && currentPreSequence >= 0)
|
||||
@ -242,8 +243,10 @@ namespace HeavenStudio
|
||||
{
|
||||
float beat = Beatmap.entities[currentPreSequence].beat;
|
||||
var entitiesAtSameBeat = Beatmap.entities.FindAll(c => c.beat == Beatmap.entities[currentPreSequence].beat);
|
||||
SortEventsByPriority(entitiesAtSameBeat);
|
||||
foreach (DynamicBeatmap.DynamicEntity entity in entitiesAtSameBeat)
|
||||
{
|
||||
currentPreSequence++;
|
||||
string gameName = entity.datamodel.Split('/')[0];
|
||||
var inf = GetGameInfo(gameName);
|
||||
if (inf.usesAssetBundle && inf.AssetsLoaded && !inf.SequencesPreloaded)
|
||||
@ -251,8 +254,10 @@ namespace HeavenStudio
|
||||
Debug.Log($"Preloading game {gameName}");
|
||||
PreloadGameSequences(gameName);
|
||||
}
|
||||
eventCaller.CallPreEvent(entity);
|
||||
currentPreSequence++;
|
||||
else
|
||||
{
|
||||
eventCaller.CallPreEvent(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -274,7 +279,7 @@ namespace HeavenStudio
|
||||
List<float> tempoChanges = Beatmap.tempoChanges.Select(c => c.beat).ToList();
|
||||
if (currentTempoEvent < Beatmap.tempoChanges.Count && currentTempoEvent >= 0)
|
||||
{
|
||||
if (Conductor.instance.songPositionInBeats >= tempoChanges[currentTempoEvent])
|
||||
if (Conductor.instance.songPositionInBeatsAsDouble >= tempoChanges[currentTempoEvent])
|
||||
{
|
||||
Conductor.instance.SetBpm(Beatmap.tempoChanges[currentTempoEvent].tempo);
|
||||
currentTempoEvent++;
|
||||
@ -284,7 +289,7 @@ namespace HeavenStudio
|
||||
List<float> volumeChanges = Beatmap.volumeChanges.Select(c => c.beat).ToList();
|
||||
if (currentVolumeEvent < Beatmap.volumeChanges.Count && currentVolumeEvent >= 0)
|
||||
{
|
||||
if (Conductor.instance.songPositionInBeats >= volumeChanges[currentVolumeEvent])
|
||||
if (Conductor.instance.songPositionInBeatsAsDouble >= volumeChanges[currentVolumeEvent])
|
||||
{
|
||||
Conductor.instance.SetVolume(Beatmap.volumeChanges[currentVolumeEvent].volume);
|
||||
currentVolumeEvent++;
|
||||
@ -294,7 +299,7 @@ namespace HeavenStudio
|
||||
List<float> chartSections = Beatmap.beatmapSections.Select(c => c.beat).ToList();
|
||||
if (currentSectionEvent < Beatmap.beatmapSections.Count && currentSectionEvent >= 0)
|
||||
{
|
||||
if (Conductor.instance.songPositionInBeats >= chartSections[currentSectionEvent])
|
||||
if (Conductor.instance.songPositionInBeatsAsDouble >= chartSections[currentSectionEvent])
|
||||
{
|
||||
Debug.Log("Section " + Beatmap.beatmapSections[currentSectionEvent].sectionName + " started");
|
||||
currentSection = Beatmap.beatmapSections[currentSectionEvent];
|
||||
@ -309,18 +314,21 @@ namespace HeavenStudio
|
||||
|
||||
float seekTime = 8f;
|
||||
//seek ahead to preload games that have assetbundles
|
||||
SeekAheadAndPreload(Conductor.instance.songPositionInBeats, seekTime);
|
||||
SeekAheadAndPreload(Conductor.instance.songPositionInBeatsAsDouble, seekTime);
|
||||
|
||||
SeekAheadAndDoPreEvent(Conductor.instance.songPositionInBeats, 2f);
|
||||
SeekAheadAndDoPreEvent(Conductor.instance.songPositionInBeatsAsDouble, 2f);
|
||||
|
||||
if (currentEvent < Beatmap.entities.Count && currentEvent >= 0)
|
||||
{
|
||||
if (Conductor.instance.songPositionInBeats >= entities[currentEvent] /*&& SongPosLessThanClipLength(Conductor.instance.songPositionInBeats)*/)
|
||||
if (Conductor.instance.songPositionInBeatsAsDouble >= entities[currentEvent])
|
||||
{
|
||||
// allows for multiple events on the same beat to be executed on the same frame, so no more 1-frame delay
|
||||
var entitiesAtSameBeat = Beatmap.entities.FindAll(c => c.beat == Beatmap.entities[currentEvent].beat && !EventCaller.FXOnlyGames().Contains(EventCaller.instance.GetMinigame(c.datamodel.Split('/')[0])));
|
||||
var fxEntities = Beatmap.entities.FindAll(c => c.beat == Beatmap.entities[currentEvent].beat && EventCaller.FXOnlyGames().Contains(EventCaller.instance.GetMinigame(c.datamodel.Split('/')[0])));
|
||||
|
||||
SortEventsByPriority(fxEntities);
|
||||
SortEventsByPriority(entitiesAtSameBeat);
|
||||
|
||||
// FX entities should ALWAYS execute before gameplay entities
|
||||
for (int i = 0; i < fxEntities.Count; i++)
|
||||
{
|
||||
@ -427,6 +435,19 @@ namespace HeavenStudio
|
||||
Beatmap.volumeChanges.Sort((x, y) => x.beat.CompareTo(y.beat));
|
||||
}
|
||||
|
||||
void SortEventsByPriority(List<DynamicBeatmap.DynamicEntity> entities)
|
||||
{
|
||||
entities.Sort((x, y) => {
|
||||
Minigames.Minigame xGame = EventCaller.instance.GetMinigame(x.datamodel.Split(0));
|
||||
Minigames.GameAction xAction = EventCaller.instance.GetGameAction(xGame, x.datamodel.Split(1));
|
||||
Minigames.Minigame yGame = EventCaller.instance.GetMinigame(y.datamodel.Split(0));
|
||||
Minigames.GameAction yAction = EventCaller.instance.GetGameAction(yGame, y.datamodel.Split(1));
|
||||
|
||||
return yAction.priority.CompareTo(xAction.priority);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public void SetCurrentEventToClosest(float beat)
|
||||
{
|
||||
SortEventsList();
|
||||
|
@ -25,7 +25,7 @@ namespace HeavenStudio.Games.Scripts_CropStomp
|
||||
return;
|
||||
Conductor cond = Conductor.instance;
|
||||
|
||||
if (stomp == null)
|
||||
if (stomp == null && cond.isPlaying)
|
||||
{
|
||||
if (GameManager.instance.currentGame == "cropStomp")
|
||||
stomp = game.ScheduleUserInput(nextStompBeat - 1f, 1f, InputType.STANDARD_DOWN, Just, Miss, Out);
|
||||
|
@ -37,7 +37,9 @@ namespace HeavenStudio.Games.Scripts_CropStomp
|
||||
public void Init()
|
||||
{
|
||||
game = CropStomp.instance;
|
||||
game.ScheduleInput(targetBeat - 1, 1f, InputType.STANDARD_DOWN, StompJust, StompMiss, Out);
|
||||
|
||||
if (Conductor.instance.isPlaying)
|
||||
game.ScheduleInput(targetBeat - 1, 1f, InputType.STANDARD_DOWN, StompJust, StompMiss, Out);
|
||||
|
||||
if (!isMole)
|
||||
{
|
||||
|
@ -15,7 +15,8 @@ namespace HeavenStudio.Games.Loaders
|
||||
{
|
||||
function = delegate { FirstContact.instance.SetIntervalStart(eventCaller.currentEntity.beat, eventCaller.currentEntity.length); },
|
||||
defaultLength = 4f,
|
||||
resizable = true
|
||||
resizable = true,
|
||||
priority = 1,
|
||||
},
|
||||
new GameAction("alien speak", "Alien Speak")
|
||||
{
|
||||
|
@ -194,7 +194,7 @@ namespace HeavenStudio.Games.Scripts_ForkLifter
|
||||
|
||||
private void Miss(PlayerActionEvent caller)
|
||||
{
|
||||
Jukebox.PlayOneShot("audience/disappointed");
|
||||
Jukebox.PlayOneShot("forkLifter/disappointed");
|
||||
BeatAction.New(game.gameObject, new List<BeatAction.Action>()
|
||||
{
|
||||
new BeatAction.Action(startBeat+ 2.45f, delegate {
|
||||
|
@ -15,6 +15,8 @@ namespace HeavenStudio.Games.Scripts_RhythmTweezers
|
||||
private Tweezers tweezers;
|
||||
private bool plucked;
|
||||
|
||||
PlayerActionEvent pluckEvent;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
game = RhythmTweezers.instance;
|
||||
@ -22,7 +24,7 @@ namespace HeavenStudio.Games.Scripts_RhythmTweezers
|
||||
}
|
||||
|
||||
private void Start() {
|
||||
game.ScheduleInput(createBeat, game.tweezerBeatOffset + game.beatInterval, InputType.STANDARD_DOWN | InputType.DIRECTION_DOWN, Just, Miss, Out);
|
||||
pluckEvent = game.ScheduleInput(createBeat, game.tweezerBeatOffset + game.beatInterval, InputType.STANDARD_DOWN | InputType.DIRECTION_DOWN, Just, Miss, Out);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
@ -58,5 +60,11 @@ namespace HeavenStudio.Games.Scripts_RhythmTweezers
|
||||
}
|
||||
|
||||
private void Out(PlayerActionEvent caller) {}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if (pluckEvent != null)
|
||||
pluckEvent.Disable();
|
||||
}
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ namespace HeavenStudio.Games.Scripts_RhythmTweezers
|
||||
|
||||
private Sound pullSound;
|
||||
|
||||
PlayerActionEvent pluckEvent;
|
||||
PlayerActionEvent endEvent;
|
||||
InputType endInput;
|
||||
|
||||
@ -122,5 +123,13 @@ namespace HeavenStudio.Games.Scripts_RhythmTweezers
|
||||
}
|
||||
EndAce();
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if (pluckEvent != null)
|
||||
pluckEvent.Disable();
|
||||
if (endEvent != null)
|
||||
endEvent.Disable();
|
||||
}
|
||||
}
|
||||
}
|
@ -19,7 +19,8 @@ namespace HeavenStudio.Games.Loaders
|
||||
{
|
||||
function = delegate { RhythmTweezers.instance.SetIntervalStart(eventCaller.currentEntity.beat, eventCaller.currentEntity.length); },
|
||||
defaultLength = 4f,
|
||||
resizable = true
|
||||
resizable = true,
|
||||
priority = 1
|
||||
},
|
||||
new GameAction("short hair", "Short Hair")
|
||||
{
|
||||
@ -41,7 +42,8 @@ namespace HeavenStudio.Games.Loaders
|
||||
new Param("type", RhythmTweezers.VegetableType.Onion, "Type", "The vegetable to switch to"),
|
||||
new Param("colorA", RhythmTweezers.defaultOnionColor, "Onion Color", "The color of the onion"),
|
||||
new Param("colorB", RhythmTweezers.defaultPotatoColor, "Potato Color", "The color of the potato")
|
||||
}
|
||||
},
|
||||
priority = 3
|
||||
},
|
||||
new GameAction("change vegetable", "Change Vegetable (Instant)")
|
||||
{
|
||||
@ -57,12 +59,14 @@ namespace HeavenStudio.Games.Loaders
|
||||
new GameAction("set tweezer delay", "Offset Tweezer")
|
||||
{
|
||||
function = delegate { RhythmTweezers.instance.tweezerBeatOffset = eventCaller.currentEntity.length; },
|
||||
resizable = true
|
||||
resizable = true,
|
||||
priority = 2
|
||||
},
|
||||
new GameAction("reset tweezer delay", "Reset Tweezer Offset")
|
||||
{
|
||||
function = delegate { RhythmTweezers.instance.tweezerBeatOffset = 0f; },
|
||||
defaultLength = 0.5f
|
||||
defaultLength = 0.5f,
|
||||
priority = 2
|
||||
},
|
||||
new GameAction("set background color", "Background Colour")
|
||||
{
|
||||
@ -350,7 +354,10 @@ namespace HeavenStudio.Games
|
||||
if (transitioning)
|
||||
{
|
||||
if (transitionTween != null)
|
||||
transitionTween.Kill(true);
|
||||
{
|
||||
transitionTween.Complete(true);
|
||||
transitionTween.Kill();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,8 @@ namespace HeavenStudio.Games.Loaders
|
||||
{
|
||||
function = delegate { WizardsWaltz.instance.SetIntervalStart(eventCaller.currentEntity.beat, eventCaller.currentEntity.length); },
|
||||
defaultLength = 4f,
|
||||
resizable = true
|
||||
resizable = true,
|
||||
priority = 1
|
||||
},
|
||||
new GameAction("plant", "Plant")
|
||||
{
|
||||
|
@ -152,6 +152,7 @@ namespace HeavenStudio
|
||||
public bool resizable = false;
|
||||
public List<Param> parameters = null;
|
||||
public bool hidden = false;
|
||||
public int priority = 0;
|
||||
public EventCallback inactiveFunction = delegate { };
|
||||
public EventCallback preFunction = delegate { };
|
||||
|
||||
@ -169,7 +170,9 @@ namespace HeavenStudio
|
||||
/// <param name="inactiveFunction">What the block does when read while the game it's associated with isn't loaded.</param>
|
||||
/// <param name="prescheduleFunction">What the block does when the GameManager seeks to this cue for pre-scheduling.</param>
|
||||
/// <param name="hidden">Prevents the block from being shown in the game list. Block will still function normally if it is in the timeline.</param>
|
||||
public GameAction(string actionName, string displayName, float defaultLength = 1, bool resizable = false, List<Param> parameters = null, EventCallback function = null, EventCallback inactiveFunction = null, EventCallback prescheduleFunction = null, bool hidden = false)
|
||||
/// <param name="preFunction">Runs two beats before this event is reached.</param>
|
||||
/// <param name="priority">Priority of this event. Higher priority events will be run first.</param>
|
||||
public GameAction(string actionName, string displayName, float defaultLength = 1, bool resizable = false, List<Param> parameters = null, EventCallback function = null, EventCallback inactiveFunction = null, EventCallback prescheduleFunction = null, bool hidden = false, EventCallback preFunction = null, int priority = 0)
|
||||
{
|
||||
this.actionName = actionName;
|
||||
if (displayName == String.Empty) this.displayName = actionName;
|
||||
@ -182,6 +185,8 @@ namespace HeavenStudio
|
||||
this.function = function ?? delegate { };
|
||||
this.inactiveFunction = inactiveFunction ?? delegate { };
|
||||
this.preFunction = prescheduleFunction ?? delegate { };
|
||||
this.priority = priority;
|
||||
|
||||
|
||||
//todo: converting to new versions of GameActions
|
||||
}
|
||||
|
@ -1,12 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HeavenStudio.Util
|
||||
{
|
||||
public class Audio
|
||||
{
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ecc1c133593e69141b1824b99aace736
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,21 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
// this is a script for testing
|
||||
|
||||
using HeavenStudio.Editor;
|
||||
|
||||
namespace HeavenStudio.Tests
|
||||
{
|
||||
public class WTF : MonoBehaviour
|
||||
{
|
||||
public GameObject test;
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (Input.GetKeyDown(KeyCode.Z))
|
||||
{
|
||||
GetComponent<CommandManager>().Execute(new TestCommand(test, new Vector3(Random.Range(-8f, 8f), Random.Range(-6f, 6f))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 490e729f742a40644a3a2abd88fce1a3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user