2022-01-17 19:23:18 +00:00
using System.Collections ;
using System.Collections.Generic ;
2022-06-12 19:32:00 +00:00
2022-01-17 19:23:18 +00:00
using UnityEngine ;
2022-02-28 19:31:28 +00:00
using DG.Tweening ;
2022-01-17 19:23:18 +00:00
2022-03-14 14:21:05 +00:00
using HeavenStudio.Util ;
2022-06-06 16:54:49 +00:00
using HeavenStudio.Editor.Track ;
2022-03-14 14:21:05 +00:00
using HeavenStudio.Games ;
2023-06-10 19:13:29 +00:00
using Jukebox ;
using Jukebox.Legacy ;
2022-01-17 19:23:18 +00:00
2022-04-12 16:14:46 +00:00
using System ;
using System.Linq ;
using System.Reflection ;
2022-06-12 19:32:00 +00:00
using System.IO ;
2022-04-12 16:14:46 +00:00
2022-03-14 14:21:05 +00:00
namespace HeavenStudio
2022-01-17 19:23:18 +00:00
{
2023-09-11 22:28:04 +00:00
2022-01-17 19:23:18 +00:00
public class Minigames
{
2023-09-11 22:28:04 +00:00
2023-06-10 19:13:29 +00:00
public static void InitPreprocessor ( )
{
RiqBeatmap . OnUpdateBeatmap + = PreProcessBeatmap ;
}
2023-09-11 22:28:04 +00:00
public static Dictionary < string , object > propertiesModel = new ( )
2023-06-10 19:13:29 +00:00
{
// mapper set properties? (future: use this to flash the button)
{ "propertiesmodified" , false } ,
////// CATEGORY 1: SONG INFO
// general chart info
{ "remixtitle" , "New Remix" } , // chart name
{ "remixauthor" , "Your Name" } , // charter's name
{ "remixdesc" , "Remix Description" } , // chart description
{ "remixlevel" , 1 } , // chart difficulty (maybe offer a suggestion but still have the mapper determine it)
{ "remixtempo" , 120f } , // avg. chart tempo
{ "remixtags" , "" } , // chart tags
{ "icontype" , 0 } , // chart icon (presets, custom - future)
{ "iconurl" , "" } , // custom icon location (future)
{ "challengetype" , 0 } , // perfect challenge type
// chart song info
{ "idolgenre" , "Song Genre" } , // song genre
{ "idolsong" , "Song Name" } , // song name
{ "idolcredit" , "Artist" } , // song artist
////// CATEGORY 2: PROLOGUE AND EPILOGUE
// chart prologue
{ "prologuetype" , 0 } , // prologue card animation (future)
{ "prologuecaption" , "Remix" } , // prologue card sub-title (future)
// chart results screen messages
{ "resultcaption" , "Rhythm League Notes" } , // result screen header
{ "resultcommon_hi" , "Good rhythm." } , // generic "Superb" message (one-liner, or second line for single-type)
{ "resultcommon_ok" , "Eh. Passable." } , // generic "OK" message (one-liner, or second line for single-type)
{ "resultcommon_ng" , "Try harder next time." } , // generic "Try Again" message (one-liner, or second line for single-type)
// the following are shown / hidden in-editor depending on the tags of the games used
{ "resultnormal_hi" , "You show strong fundamentals." } , // "Superb" message for normal games (two-liner)
{ "resultnormal_ng" , "Work on your fundamentals." } , // "Try Again" message for normal games (two-liner)
{ "resultkeep_hi" , "You kept the beat well." } , // "Superb" message for keep-the-beat games (two-liner)
{ "resultkeep_ng" , "You had trouble keeping the beat." } , // "Try Again" message for keep-the-beat games (two-liner)
{ "resultaim_hi" , "You had great aim." } , // "Superb" message for aim games (two-liner)
{ "resultaim_ng" , "Your aim was a little shaky." } , // "Try Again" message for aim games (two-liner)
{ "resultrepeat_hi" , "You followed the example well." } , // "Superb" message for call-and-response games (two-liner)
{ "resultrepeat_ng" , "Next time, follow the example better." } , // "Try Again" message for call-and-response games (two-liner)
} ;
2023-06-11 16:12:25 +00:00
static Dictionary < string , object > tempoChangeModel = new ( )
{
{ "tempo" , 120f } ,
{ "swing" , 0f } ,
{ "timeSignature" , new Vector2 ( 4 , 4 ) } ,
} ;
static Dictionary < string , object > volumeChangeModel = new ( )
{
{ "volume" , 1f } ,
{ "fade" , Util . EasingFunction . Ease . Instant } ,
} ;
static Dictionary < string , object > sectionMarkModel = new ( )
{
{ "sectionName" , "" } ,
{ "isCheckpoint" , false } ,
{ "startPerfect" , false } ,
{ "breakSection" , false } ,
{ "extendsPrevious" , false } ,
{ "sectionWeight" , 1f } ,
} ;
static void PreProcessSpecialEntity ( RiqEntity e , Dictionary < string , object > model )
{
foreach ( var t in model )
{
string propertyName = t . Key ;
Type type = t . Value . GetType ( ) ;
if ( ! e . dynamicData . ContainsKey ( propertyName ) )
{
e . CreateProperty ( propertyName , t . Value ) ;
}
Type pType = e [ propertyName ] . GetType ( ) ;
if ( pType ! = type )
{
try
{
2023-06-14 01:21:13 +00:00
if ( type . IsEnum )
2023-06-11 16:12:25 +00:00
{
2023-06-14 01:21:13 +00:00
if ( pType = = typeof ( string ) )
e . dynamicData [ propertyName ] = ( int ) Enum . Parse ( type , ( string ) e [ propertyName ] ) ;
2023-06-11 16:12:25 +00:00
else
2023-06-14 01:21:13 +00:00
e . dynamicData [ propertyName ] = ( int ) e [ propertyName ] ;
2023-06-11 16:12:25 +00:00
}
else if ( pType = = typeof ( Newtonsoft . Json . Linq . JObject ) )
e [ propertyName ] = e [ propertyName ] . ToObject ( type ) ;
else
e [ propertyName ] = Convert . ChangeType ( e [ propertyName ] , type ) ;
}
catch
{
Debug . LogWarning ( $"Could not convert {propertyName} to {type}! Using default value..." ) ;
// use default value
e . CreateProperty ( propertyName , t . Value ) ;
}
}
}
}
2023-06-10 19:13:29 +00:00
/// <summary>
/// processes an riq beatmap after it is loaded
/// </summary>
public static RiqBeatmapData ? PreProcessBeatmap ( string version , RiqBeatmapData data )
{
Debug . Log ( "Preprocessing beatmap..." ) ;
Minigames . Minigame game ;
Minigames . GameAction action ;
System . Type type , pType ;
foreach ( var e in data . entities )
{
var gameName = e . datamodel . Split ( 0 ) ;
var actionName = e . datamodel . Split ( 1 ) ;
game = EventCaller . instance . GetMinigame ( gameName ) ;
if ( game = = null )
{
Debug . LogWarning ( $"Unknown game {gameName} found in remix.json! Adding game..." ) ;
game = new Minigames . Minigame ( gameName , gameName . DisplayName ( ) + " \n<color=#eb5454>[inferred from remix.json]</color>" , "" , false , false , new List < Minigames . GameAction > ( ) , inferred : true ) ;
EventCaller . instance . minigames . Add ( game ) ;
if ( Editor . Editor . instance ! = null )
Editor . Editor . instance . AddIcon ( game ) ;
}
action = EventCaller . instance . GetGameAction ( game , actionName ) ;
if ( action = = null )
{
Debug . LogWarning ( $"Unknown action {gameName}/{actionName} found in remix.json! Adding action..." ) ;
var parameters = new List < Minigames . Param > ( ) ;
foreach ( var item in e . dynamicData )
{
2023-06-11 19:52:14 +00:00
Debug . Log ( $"k: {item.Key}, v: {item.Value}" ) ;
if ( item . Key = = "track" )
continue ;
2023-09-11 22:28:04 +00:00
if ( item . Value = = null )
2023-06-12 21:18:37 +00:00
continue ;
2023-06-10 19:13:29 +00:00
var value = item . Value ;
if ( value . GetType ( ) = = typeof ( long ) )
value = new EntityTypes . Integer ( int . MinValue , int . MaxValue , ( int ) value ) ;
else if ( value . GetType ( ) = = typeof ( double ) )
value = new EntityTypes . Float ( float . NegativeInfinity , float . PositiveInfinity , ( float ) value ) ;
2023-06-12 21:18:37 +00:00
parameters . Add ( new Minigames . Param ( item . Key , value , item . Key . DisplayName ( ) , "[inferred from remix.json]" ) ) ;
2023-06-10 19:13:29 +00:00
}
action = new Minigames . GameAction ( actionName , actionName . DisplayName ( ) , e . length , true , parameters ) ;
game . actions . Add ( action ) ;
}
//check each param of the action
if ( action . parameters ! = null )
{
foreach ( var param in action . parameters )
{
type = param . parameter . GetType ( ) ;
//add property if it doesn't exist
if ( ! e . dynamicData . ContainsKey ( param . propertyName ) )
{
Debug . LogWarning ( $"Property {param.propertyName} does not exist in the entity's dynamic data! Adding..." ) ;
if ( type = = typeof ( EntityTypes . Integer ) )
e . dynamicData . Add ( param . propertyName , ( ( EntityTypes . Integer ) param . parameter ) . val ) ;
else if ( type = = typeof ( EntityTypes . Float ) )
e . dynamicData . Add ( param . propertyName , ( ( EntityTypes . Float ) param . parameter ) . val ) ;
2023-06-14 01:21:13 +00:00
else if ( type . IsEnum )
2023-06-10 19:13:29 +00:00
e . dynamicData . Add ( param . propertyName , ( int ) param . parameter ) ;
else
e . dynamicData . Add ( param . propertyName , Convert . ChangeType ( param . parameter , type ) ) ;
continue ;
}
pType = e [ param . propertyName ] . GetType ( ) ;
if ( pType ! = type )
{
try
{
if ( type = = typeof ( EntityTypes . Integer ) )
e . dynamicData [ param . propertyName ] = ( int ) e [ param . propertyName ] ;
else if ( type = = typeof ( EntityTypes . Float ) )
e . dynamicData [ param . propertyName ] = ( float ) e [ param . propertyName ] ;
2023-06-14 01:21:13 +00:00
else if ( type . IsEnum )
2023-06-10 19:13:29 +00:00
{
2023-06-14 01:21:13 +00:00
if ( pType = = typeof ( string ) )
e . dynamicData [ param . propertyName ] = ( int ) Enum . Parse ( type , ( string ) e [ param . propertyName ] ) ;
2023-06-10 19:13:29 +00:00
else
2023-06-14 01:21:13 +00:00
e . dynamicData [ param . propertyName ] = ( int ) e [ param . propertyName ] ;
2023-06-10 19:13:29 +00:00
}
else if ( pType = = typeof ( Newtonsoft . Json . Linq . JObject ) )
e . dynamicData [ param . propertyName ] = e [ param . propertyName ] . ToObject ( type ) ;
else
e . dynamicData [ param . propertyName ] = Convert . ChangeType ( e [ param . propertyName ] , type ) ;
}
catch
{
Debug . LogWarning ( $"Could not convert {param.propertyName} to {type}! Using default value..." ) ;
// GlobalGameManager.ShowErrorMessage("Warning", $"Could not convert {e.datamodel}/{param.propertyName} to {type}! This will be loaded using the default value, so chart may be unstable.");
// use default value
if ( type = = typeof ( EntityTypes . Integer ) )
e . dynamicData [ param . propertyName ] = ( ( EntityTypes . Integer ) param . parameter ) . val ;
else if ( type = = typeof ( EntityTypes . Float ) )
e . dynamicData [ param . propertyName ] = ( ( EntityTypes . Float ) param . parameter ) . val ;
else if ( type . IsEnum & & param . propertyName ! = "ease" )
e . dynamicData [ param . propertyName ] = ( int ) param . parameter ;
else
e . dynamicData [ param . propertyName ] = Convert . ChangeType ( param . parameter , type ) ;
}
}
}
}
}
foreach ( var tempo in data . tempoChanges )
{
2023-06-11 16:12:25 +00:00
PreProcessSpecialEntity ( tempo , tempoChangeModel ) ;
2023-06-10 19:13:29 +00:00
}
2023-06-11 19:52:14 +00:00
if ( data . tempoChanges [ 0 ] [ "tempo" ] < = 0 )
{
data . tempoChanges [ 0 ] [ "tempo" ] = 120 ;
}
2023-06-10 19:13:29 +00:00
foreach ( var vol in data . volumeChanges )
{
2023-06-11 16:12:25 +00:00
PreProcessSpecialEntity ( vol , volumeChangeModel ) ;
2023-06-10 19:13:29 +00:00
}
foreach ( var section in data . beatmapSections )
{
2023-06-11 16:12:25 +00:00
PreProcessSpecialEntity ( section , sectionMarkModel ) ;
2023-06-10 19:13:29 +00:00
}
//go thru each property of the model beatmap and add any missing keyvalue pair
foreach ( var prop in propertiesModel )
{
if ( ! data . properties . ContainsKey ( prop . Key ) )
{
data . properties . Add ( prop . Key , prop . Value ) ;
}
}
return data ;
}
2022-01-17 19:23:18 +00:00
public class Minigame
{
2023-09-11 22:28:04 +00:00
2022-01-17 19:23:18 +00:00
public string name ;
public string displayName ;
public string color ;
public GameObject holder ;
2023-05-21 17:35:00 +00:00
public bool hidden ;
2022-02-03 03:58:08 +00:00
public bool fxOnly ;
2022-01-17 19:23:18 +00:00
public List < GameAction > actions = new List < GameAction > ( ) ;
2022-06-12 19:32:00 +00:00
public List < string > tags ;
public string defaultLocale = "en" ;
public string wantAssetBundle = "" ;
public List < string > supportedLocales ;
2023-04-02 17:15:19 +00:00
public bool inferred ;
2022-06-12 19:32:00 +00:00
public bool usesAssetBundle = > ( wantAssetBundle ! = "" ) ;
public bool hasLocales = > ( supportedLocales . Count > 0 ) ;
public bool AssetsLoaded = > ( ( ( hasLocales & & localeLoaded & & currentLoadedLocale = = defaultLocale ) | | ( ! hasLocales ) ) & & commonLoaded ) ;
2023-01-12 01:42:12 +00:00
public bool SequencesPreloaded = > soundSequences ! = null ;
2023-04-02 17:15:19 +00:00
public string LoadableName = > inferred ? "noGame" : name ;
2022-06-12 19:32:00 +00:00
private AssetBundle bundleCommon = null ;
private bool commonLoaded = false ;
private bool commonPreloaded = false ;
private string currentLoadedLocale = "" ;
private AssetBundle bundleLocalized = null ;
private bool localeLoaded = false ;
private bool localePreloaded = false ;
2023-01-12 01:42:12 +00:00
private SoundSequence . SequenceKeyValue [ ] soundSequences = null ;
public SoundSequence . SequenceKeyValue [ ] LoadedSoundSequences
{
get = > soundSequences ;
set = > soundSequences = value ;
}
2023-05-21 17:35:00 +00:00
public Minigame ( string name , string displayName , string color , bool hidden , bool fxOnly , List < GameAction > actions , List < string > tags = null , string assetBundle = "" , string defaultLocale = "en" , List < string > supportedLocales = null , bool inferred = false )
2022-01-17 19:23:18 +00:00
{
this . name = name ;
this . displayName = displayName ;
this . color = color ;
this . actions = actions ;
2023-05-21 17:35:00 +00:00
this . hidden = hidden ;
2022-02-03 03:58:08 +00:00
this . fxOnly = fxOnly ;
2022-06-12 19:32:00 +00:00
this . tags = tags ? ? new List < string > ( ) ;
this . wantAssetBundle = assetBundle ;
this . defaultLocale = defaultLocale ;
this . supportedLocales = supportedLocales ? ? new List < string > ( ) ;
2023-04-02 17:15:19 +00:00
this . inferred = inferred ;
2022-06-12 19:32:00 +00:00
}
public AssetBundle GetLocalizedAssetBundle ( )
{
if ( ! hasLocales ) return null ;
if ( ! usesAssetBundle ) return null ;
if ( bundleLocalized = = null | | currentLoadedLocale ! = defaultLocale ) //TEMPORARY: use the game's default locale until we add localization support
{
if ( localeLoaded ) return bundleLocalized ;
// TODO: try/catch for missing assetbundles
currentLoadedLocale = defaultLocale ;
bundleLocalized = AssetBundle . LoadFromFile ( Path . Combine ( Application . streamingAssetsPath , wantAssetBundle + "/locale." + defaultLocale ) ) ;
localeLoaded = true ;
}
return bundleLocalized ;
}
public AssetBundle GetCommonAssetBundle ( )
{
if ( commonLoaded ) return bundleCommon ;
if ( ! usesAssetBundle ) return null ;
if ( bundleCommon = = null )
{
// TODO: try/catch for missing assetbundles
bundleCommon = AssetBundle . LoadFromFile ( Path . Combine ( Application . streamingAssetsPath , wantAssetBundle + "/common" ) ) ;
commonLoaded = true ;
}
return bundleCommon ;
}
public IEnumerator LoadCommonAssetBundleAsync ( )
{
if ( commonPreloaded | | commonLoaded ) yield break ;
commonPreloaded = true ;
if ( ! usesAssetBundle ) yield break ;
if ( bundleCommon ! = null ) yield break ;
AssetBundleCreateRequest asyncBundleRequest = AssetBundle . LoadFromFileAsync ( Path . Combine ( Application . streamingAssetsPath , wantAssetBundle + "/common" ) ) ;
if ( bundleCommon ! = null ) yield break ;
yield return asyncBundleRequest ;
AssetBundle localAssetBundle = asyncBundleRequest . assetBundle ;
if ( bundleCommon ! = null ) yield break ;
yield return localAssetBundle ;
if ( localAssetBundle = = null ) yield break ;
bundleCommon = localAssetBundle ;
commonLoaded = true ;
}
public IEnumerator LoadLocalizedAssetBundleAsync ( )
{
if ( localePreloaded ) yield break ;
localePreloaded = true ;
if ( ! hasLocales ) yield break ;
if ( ! usesAssetBundle ) yield break ;
if ( localeLoaded & & bundleLocalized ! = null & & currentLoadedLocale = = defaultLocale ) yield break ;
AssetBundleCreateRequest asyncBundleRequest = AssetBundle . LoadFromFileAsync ( Path . Combine ( Application . streamingAssetsPath , wantAssetBundle + "/locale." + defaultLocale ) ) ;
if ( localeLoaded & & bundleLocalized ! = null & & currentLoadedLocale = = defaultLocale ) yield break ;
yield return asyncBundleRequest ;
AssetBundle localAssetBundle = asyncBundleRequest . assetBundle ;
if ( localeLoaded & & bundleLocalized ! = null & & currentLoadedLocale = = defaultLocale ) yield break ;
yield return localAssetBundle ;
if ( localAssetBundle = = null ) yield break ;
bundleLocalized = localAssetBundle ;
currentLoadedLocale = defaultLocale ;
localeLoaded = true ;
2022-01-17 19:23:18 +00:00
}
}
public class GameAction
{
public string actionName ;
2022-08-20 23:03:51 +00:00
public string displayName ;
2022-08-21 03:13:52 +00:00
public EventCallback function = delegate { } ;
public float defaultLength = 1 ;
public bool resizable = false ;
public List < Param > parameters = null ;
public bool hidden = false ;
2023-01-19 02:31:08 +00:00
public int priority = 0 ;
2022-08-21 03:13:52 +00:00
public EventCallback inactiveFunction = delegate { } ;
public EventCallback preFunction = delegate { } ;
2023-02-18 22:12:49 +00:00
public float preFunctionLength = 2.0f ;
2022-01-17 19:23:18 +00:00
2022-03-02 21:59:35 +00:00
/// <summary>
/// <para>Creates a block that can be used in the editor. The block's function and attributes are defined in the parentheses.</para>
/// <para>Note: Every parameter after the second one is an optional parameter. You can change optional parameters by adding (name): (value) after the second parameter.</para>
/// </summary>
2022-08-20 23:03:51 +00:00
/// <param name="actionName">Entity model name</param>
/// <param name="displayName">Name of the block used in the UI</param>
2022-03-02 21:59:35 +00:00
/// <param name="defaultLength">How long the block appears in the editor</param>
/// <param name="resizable">Allows the user to resize the block</param>
/// <param name="parameters">Extra parameters for this block that change how it functions.</param>
2022-08-20 23:03:51 +00:00
/// <param name="function"><para>What the block does when read during playback</para>
/// <para>Only does this if the game that it is associated with is loaded.</para></param>
2022-03-02 21:59:35 +00:00
/// <param name="inactiveFunction">What the block does when read while the game it's associated with isn't loaded.</param>
2022-08-20 23:03:51 +00:00
/// <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>
2023-01-19 02:31:08 +00:00
/// <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>
2023-02-18 22:12:49 +00:00
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 , float preFunctionLength = 2.0f )
2022-01-17 19:23:18 +00:00
{
this . actionName = actionName ;
2022-08-20 23:03:51 +00:00
if ( displayName = = String . Empty ) this . displayName = actionName ;
else this . displayName = displayName ;
2022-01-17 19:23:18 +00:00
this . defaultLength = defaultLength ;
this . resizable = resizable ;
2022-02-03 22:20:26 +00:00
this . parameters = parameters ;
2022-03-01 08:17:06 +00:00
this . hidden = hidden ;
2022-08-20 23:03:51 +00:00
this . function = function ? ? delegate { } ;
this . inactiveFunction = inactiveFunction ? ? delegate { } ;
this . preFunction = prescheduleFunction ? ? delegate { } ;
2023-01-19 02:31:08 +00:00
this . priority = priority ;
2023-02-18 22:12:49 +00:00
this . preFunctionLength = preFunctionLength ;
2023-01-19 02:31:08 +00:00
2022-08-20 23:03:51 +00:00
//todo: converting to new versions of GameActions
}
/// <summary>
/// <para>Shorthand constructor for a GameAction with only required data</para>
/// </summary>
/// <param name="actionName">Entity model name</param>
/// <param name="displayName">Name of the block used in the UI</param>
public GameAction ( string actionName , string displayName )
{
this . actionName = actionName ;
if ( displayName = = String . Empty ) this . displayName = actionName ;
else this . displayName = displayName ;
2022-02-03 22:20:26 +00:00
}
}
[System.Serializable]
public class Param
{
public string propertyName ;
public object parameter ;
public string propertyCaption ;
2022-03-01 21:11:19 +00:00
public string tooltip ;
2023-08-16 11:00:27 +00:00
public List < CollapseParam > collapseParams ;
2022-02-03 22:20:26 +00:00
2022-03-02 21:59:35 +00:00
/// <summary>
/// A parameter that changes the function of a GameAction.
/// </summary>
2022-08-20 23:03:51 +00:00
/// <param name="propertyName">The name of the variable that's being changed.</param>
2022-03-02 21:59:35 +00:00
/// <param name="parameter">The value of the parameter</param>
/// <param name="propertyCaption">The name shown in the editor. Can be anything you want.</param>
2023-08-16 11:00:27 +00:00
public Param ( string propertyName , object parameter , string propertyCaption , string tooltip = "" , List < CollapseParam > collapseParams = null )
2022-02-03 22:20:26 +00:00
{
this . propertyName = propertyName ;
this . parameter = parameter ;
this . propertyCaption = propertyCaption ;
2022-03-01 21:11:19 +00:00
this . tooltip = tooltip ;
2023-08-16 11:00:27 +00:00
this . collapseParams = collapseParams ;
}
public class CollapseParam
{
public Func < object , bool > CollapseOn ;
public string [ ] collapseables ;
/// <summary>
/// Class that decides how other parameters will be collapsed
/// </summary>
/// <param name="collapseOn">What values should make it collapse/uncollapse?</param>
/// <param name="collapseables">IDs of the parameters to collapse</param>
public CollapseParam ( Func < object , bool > collapseOn , string [ ] collapseables )
{
CollapseOn = collapseOn ;
this . collapseables = collapseables ;
}
2022-01-17 19:23:18 +00:00
}
}
public delegate void EventCallback ( ) ;
2023-06-10 19:13:29 +00:00
public delegate void ParamChangeCallback ( string paramName , object paramValue , RiqEntity entity ) ;
2022-01-17 19:23:18 +00:00
2022-04-12 16:14:46 +00:00
// overengineered af but it's a modified version of
// https://stackoverflow.com/a/19877141
static List < Func < EventCaller , Minigame > > loadRunners ;
2023-09-11 22:28:04 +00:00
static void BuildLoadRunnerList ( )
{
2022-04-12 16:14:46 +00:00
loadRunners = System . Reflection . Assembly . GetExecutingAssembly ( )
. GetTypes ( )
. Where ( x = > x . Namespace = = "HeavenStudio.Games.Loaders" & & x . GetMethod ( "AddGame" , BindingFlags . Public | BindingFlags . Static ) ! = null )
2023-09-11 22:28:04 +00:00
. Select ( t = > ( Func < EventCaller , Minigame > ) Delegate . CreateDelegate (
typeof ( Func < EventCaller , Minigame > ) ,
null ,
2022-04-12 16:14:46 +00:00
t . GetMethod ( "AddGame" , BindingFlags . Public | BindingFlags . Static ) ,
false
) )
. ToList ( ) ;
2023-09-11 22:28:04 +00:00
2022-04-12 16:14:46 +00:00
}
2022-01-17 19:23:18 +00:00
public static void Init ( EventCaller eventCaller )
{
eventCaller . minigames = new List < Minigame > ( )
{
2022-02-03 03:58:08 +00:00
new Minigame ( "gameManager" , "Game Manager" , "" , false , true , new List < GameAction > ( )
2022-01-17 19:23:18 +00:00
{
2023-09-11 22:28:04 +00:00
new GameAction ( "switchGame" , "Switch Game" , 0.5f , false ,
function : delegate { var e = eventCaller . currentEntity ; GameManager . instance . SwitchGame ( eventCaller . currentSwitchGame , eventCaller . currentEntity . beat , e [ "toggle" ] ) ; } ,
2023-04-07 15:15:19 +00:00
parameters : new List < Param > ( )
{
new Param ( "toggle" , true , "Black Flash" , "Enable or disable the black screen for this Game Switch" )
} ,
inactiveFunction : delegate { var e = eventCaller . currentEntity ; GameManager . instance . SwitchGame ( eventCaller . currentSwitchGame , eventCaller . currentEntity . beat , e [ "toggle" ] ) ; }
2022-08-20 23:03:51 +00:00
) ,
new GameAction ( "end" , "End Remix" ,
2023-09-11 22:28:04 +00:00
function : delegate {
Debug . Log ( "end" ) ;
2022-08-20 23:03:51 +00:00
if ( Timeline . instance ! = null )
Timeline . instance ? . Stop ( 0 ) ;
else
GameManager . instance . Stop ( 0 ) ;
}
) ,
2023-03-11 04:51:22 +00:00
new GameAction ( "skill star" , "Skill Star" , 1f , true )
{
//temp for testing
function = delegate {
var e = eventCaller . currentEntity ;
HeavenStudio . Common . SkillStarManager . instance . DoStarIn ( e . beat , e . length ) ;
// BeatAction.New(HeavenStudio.Common.SkillStarManager.instance.gameObject, new List<BeatAction.Action>(){
// new BeatAction.Action(e.beat + e.length, delegate {
// HeavenStudio.Common.SkillStarManager.instance.DoStarJust();
// })
// });
}
} ,
2022-08-20 23:03:51 +00:00
new GameAction ( "toggle inputs" , "Toggle Inputs" , 0.5f , true ,
new List < Param > ( )
{
new Param ( "toggle" , true , "Enable Inputs" )
} ,
delegate
{
2022-08-21 23:46:45 +00:00
GameManager . instance . ToggleInputs ( eventCaller . currentEntity [ "toggle" ] ) ;
2022-08-20 23:03:51 +00:00
}
) ,
2022-02-08 01:07:03 +00:00
2022-08-20 23:03:51 +00:00
// These are still here for backwards-compatibility but are hidden in the editor
2023-09-11 22:28:04 +00:00
new GameAction ( "flash" , "" , 1f , true ,
2022-08-20 23:03:51 +00:00
new List < Param > ( )
{
new Param ( "colorA" , Color . white , "Start Color" ) ,
new Param ( "colorB" , Color . white , "End Color" ) ,
new Param ( "valA" , new EntityTypes . Float ( 0 , 1 , 1 ) , "Start Opacity" ) ,
new Param ( "valB" , new EntityTypes . Float ( 0 , 1 , 0 ) , "End Opacity" ) ,
2023-06-10 19:13:29 +00:00
new Param ( "ease" , Util . EasingFunction . Ease . Linear , "Ease" )
2022-08-20 23:03:51 +00:00
} ,
hidden : true
) ,
2023-09-11 22:28:04 +00:00
new GameAction ( "move camera" , "" , 1f , true , new List < Param > ( )
2022-05-16 05:29:39 +00:00
{
new Param ( "valA" , new EntityTypes . Float ( - 50 , 50 , 0 ) , "Right / Left" ) ,
new Param ( "valB" , new EntityTypes . Float ( - 50 , 50 , 0 ) , "Up / Down" ) ,
new Param ( "valC" , new EntityTypes . Float ( - 0 , 250 , 10 ) , "In / Out" ) ,
2023-06-10 19:13:29 +00:00
new Param ( "ease" , Util . EasingFunction . Ease . Linear , "Ease Type" )
2022-06-04 03:15:05 +00:00
} ,
hidden : true ) ,
2023-09-11 22:28:04 +00:00
new GameAction ( "rotate camera" , "" , 1f , true , new List < Param > ( )
2022-05-16 05:29:39 +00:00
{
new Param ( "valA" , new EntityTypes . Integer ( - 360 , 360 , 0 ) , "Pitch" ) ,
new Param ( "valB" , new EntityTypes . Integer ( - 360 , 360 , 0 ) , "Yaw" ) ,
new Param ( "valC" , new EntityTypes . Integer ( - 360 , 360 , 0 ) , "Roll" ) ,
2023-06-10 19:13:29 +00:00
new Param ( "ease" , Util . EasingFunction . Ease . Linear , "Ease Type" )
2022-06-04 03:15:05 +00:00
} ,
hidden : true ) ,
2022-01-17 19:23:18 +00:00
} ) ,
2022-07-28 23:07:19 +00:00
2022-02-03 03:58:08 +00:00
new Minigame ( "countIn" , "Count-Ins" , "" , false , true , new List < GameAction > ( )
{
2022-08-20 23:03:51 +00:00
new GameAction ( "4 beat count-in" , "4 Beat Count-In" , 4f , true ,
new List < Param > ( )
{
new Param ( "type" , SoundEffects . CountInType . Normal , "Type" , "The sounds to play for the count-in" )
} ,
2022-08-21 23:46:45 +00:00
delegate { var e = eventCaller . currentEntity ; SoundEffects . FourBeatCountIn ( e . beat , e . length / 4f , e [ "type" ] ) ; }
2022-08-20 23:03:51 +00:00
) ,
new GameAction ( "8 beat count-in" , "8 Beat Count-In" , 8f , true ,
new List < Param > ( )
{
new Param ( "type" , SoundEffects . CountInType . Normal , "Type" , "The sounds to play for the count-in" )
} ,
2022-08-21 23:46:45 +00:00
delegate { var e = eventCaller . currentEntity ; SoundEffects . EightBeatCountIn ( e . beat , e . length / 8f , e [ "type" ] ) ; }
2022-08-20 23:03:51 +00:00
) ,
new GameAction ( "count" , "Count" , 1f , false ,
new List < Param > ( )
{
new Param ( "type" , SoundEffects . CountNumbers . One , "Number" , "The sound to play" ) ,
new Param ( "toggle" , false , "Alt" , "Whether or not the alternate version should be played" )
} ,
2022-08-21 23:46:45 +00:00
delegate { var e = eventCaller . currentEntity ; SoundEffects . Count ( e [ "type" ] , e [ "toggle" ] ) ; }
2022-08-20 23:03:51 +00:00
) ,
new GameAction ( "cowbell" , "Cowbell" ,
function : delegate { SoundEffects . Cowbell ( ) ; }
) ,
new GameAction ( "ready!" , "Ready!" , 2f , true ,
function : delegate { var e = eventCaller . currentEntity ; SoundEffects . Ready ( e . beat , e . length / 2f ) ; }
) ,
new GameAction ( "and" , "And" , 0.5f ,
function : delegate { SoundEffects . And ( ) ; }
) ,
2023-09-11 22:28:04 +00:00
new GameAction ( "go!" , "Go!" , 1f , false ,
2022-08-20 23:03:51 +00:00
new List < Param > ( )
{
new Param ( "toggle" , false , "Alt" , "Whether or not the alternate version should be played" )
} ,
2022-08-21 23:46:45 +00:00
function : delegate { SoundEffects . Go ( eventCaller . currentEntity [ "toggle" ] ) ; }
2022-08-20 23:03:51 +00:00
) ,
2022-03-01 19:21:23 +00:00
// These are still here for backwards-compatibility but are hidden in the editor
2022-08-20 23:03:51 +00:00
new GameAction ( "4 beat count-in (alt)" , "" , 4f , function : delegate { var e = eventCaller . currentEntity ; SoundEffects . FourBeatCountIn ( e . beat , e . length , 1 ) ; } , hidden : true ) ,
new GameAction ( "4 beat count-in (cowbell)" , "" , 4f , function : delegate { var e = eventCaller . currentEntity ; SoundEffects . FourBeatCountIn ( e . beat , e . length , 2 ) ; } , hidden : true ) ,
new GameAction ( "8 beat count-in (alt)" , "" , 8f , function : delegate { var e = eventCaller . currentEntity ; SoundEffects . EightBeatCountIn ( e . beat , e . length , 1 ) ; } , hidden : true ) ,
new GameAction ( "8 beat count-in (cowbell)" , "" , 8f , function : delegate { var e = eventCaller . currentEntity ; SoundEffects . EightBeatCountIn ( e . beat , e . length , 2 ) ; } , hidden : true ) ,
new GameAction ( "one" , "" , function : delegate { SoundEffects . Count ( 0 , false ) ; } , hidden : true ) ,
new GameAction ( "two" , "" , function : delegate { SoundEffects . Count ( 1 , false ) ; } , hidden : true ) ,
new GameAction ( "three" , "" , function : delegate { SoundEffects . Count ( 2 , false ) ; } , hidden : true ) ,
new GameAction ( "four" , "" , function : delegate { SoundEffects . Count ( 3 , false ) ; } , hidden : true ) ,
new GameAction ( "one (alt)" , "" , function : delegate { SoundEffects . Count ( 0 , true ) ; } , hidden : true ) ,
new GameAction ( "two (alt)" , "" , function : delegate { SoundEffects . Count ( 1 , true ) ; } , hidden : true ) ,
new GameAction ( "three (alt)" , "" , function : delegate { SoundEffects . Count ( 2 , true ) ; } , hidden : true ) ,
new GameAction ( "four (alt)" , "" , function : delegate { SoundEffects . Count ( 3 , true ) ; } , hidden : true ) ,
new GameAction ( "go! (alt)" , "" , function : delegate { SoundEffects . Go ( true ) ; } , hidden : true ) ,
2022-02-03 03:58:08 +00:00
} ) ,
2022-07-28 23:07:19 +00:00
2022-06-04 03:15:05 +00:00
new Minigame ( "vfx" , "Visual Effects" , "" , false , true , new List < GameAction > ( )
{
2023-09-11 22:28:04 +00:00
new GameAction ( "flash" , "Flash" , 1f , true ,
2022-08-20 23:03:51 +00:00
new List < Param > ( )
{
new Param ( "colorA" , Color . white , "Start Color" ) ,
new Param ( "colorB" , Color . white , "End Color" ) ,
new Param ( "valA" , new EntityTypes . Float ( 0 , 1 , 1 ) , "Start Opacity" ) ,
new Param ( "valB" , new EntityTypes . Float ( 0 , 1 , 0 ) , "End Opacity" ) ,
2023-06-10 19:13:29 +00:00
new Param ( "ease" , Util . EasingFunction . Ease . Linear , "Ease" )
2022-08-20 23:03:51 +00:00
}
) ,
2023-01-27 03:42:16 +00:00
new GameAction ( "filter" , "Filter" , 1f , true ,
new List < Param > ( )
{
new Param ( "filter" , Games . Global . Filter . FilterType . grayscale , "Filter" ) ,
new Param ( "inten" , new EntityTypes . Float ( 0 , 100 , 100 ) , "Intensity" ) ,
new Param ( "fadein" , new EntityTypes . Float ( 0 , 100 , 0 ) , "Fade In" ) ,
new Param ( "fadeout" , new EntityTypes . Float ( 0 , 100 , 0 ) , "Fade Out" )
}
) ,
2023-09-11 22:28:04 +00:00
new GameAction ( "move camera" , "Move Camera" , 1f , true , new List < Param > ( )
2022-08-20 23:03:51 +00:00
{
2023-03-11 04:51:22 +00:00
new Param ( "valA" , new EntityTypes . Float ( - 50 , 50 , 0 ) , "Right / Left" , "Next position on the X axis" ) ,
new Param ( "valB" , new EntityTypes . Float ( - 50 , 50 , 0 ) , "Up / Down" , "Next position on the Y axis" ) ,
new Param ( "valC" , new EntityTypes . Float ( - 0 , 250 , 10 ) , "In / Out" , "Next position on the Z axis" ) ,
2023-06-10 19:13:29 +00:00
new Param ( "ease" , Util . EasingFunction . Ease . Linear , "Ease Type" ) ,
2023-03-11 04:51:22 +00:00
new Param ( "axis" , GameCamera . CameraAxis . All , "Axis" , "The axis to move the camera on" )
2022-08-20 23:03:51 +00:00
}
) ,
2023-09-11 22:28:04 +00:00
new GameAction ( "rotate camera" , "Rotate Camera" , 1f , true , new List < Param > ( )
2022-08-20 23:03:51 +00:00
{
2023-03-11 04:51:22 +00:00
new Param ( "valA" , new EntityTypes . Integer ( - 360 , 360 , 0 ) , "Pitch" , "Next rotation on the X axis" ) ,
new Param ( "valB" , new EntityTypes . Integer ( - 360 , 360 , 0 ) , "Yaw" , "Next rotation on the Y axis" ) ,
new Param ( "valC" , new EntityTypes . Integer ( - 360 , 360 , 0 ) , "Roll" , "Next rotation on the Z axis" ) ,
2023-06-10 19:13:29 +00:00
new Param ( "ease" , Util . EasingFunction . Ease . Linear , "Ease Type" ) ,
2023-03-11 04:51:22 +00:00
new Param ( "axis" , GameCamera . CameraAxis . All , "Axis" , "The axis to move the camera on" )
2023-09-11 22:28:04 +00:00
}
2022-08-20 23:03:51 +00:00
) ,
2023-07-17 15:56:57 +00:00
new GameAction ( "camera background color" , "Camera Background Color" , 1 , true , new List < Param > ( )
{
new Param ( "color" , Color . black , "Start Color" ) ,
new Param ( "color2" , Color . black , "End Color" ) ,
new Param ( "ease" , Util . EasingFunction . Ease . Linear , "Ease Type" )
}
) ,
2023-09-11 22:28:04 +00:00
new GameAction ( "pan view" , "Pan Viewport" , 1f , true , new List < Param > ( )
2023-03-11 04:51:22 +00:00
{
new Param ( "valA" , new EntityTypes . Float ( - 50 , 50 , 0 ) , "Right / Left" , "Next position on the X axis" ) ,
new Param ( "valB" , new EntityTypes . Float ( - 50 , 50 , 0 ) , "Up / Down" , "Next position on the Y axis" ) ,
2023-06-10 19:13:29 +00:00
new Param ( "ease" , Util . EasingFunction . Ease . Linear , "Ease Type" ) ,
2023-03-11 04:51:22 +00:00
new Param ( "axis" , StaticCamera . ViewAxis . All , "Axis" , "The axis to pan the viewport in" )
}
) ,
2023-09-11 22:28:04 +00:00
new GameAction ( "rotate view" , "Rotate Viewport" , 1f , true , new List < Param > ( )
2023-03-11 04:51:22 +00:00
{
new Param ( "valA" , new EntityTypes . Float ( - 360 , 360 , 0 ) , "Rotation" , "Next viewport rotation" ) ,
2023-06-10 19:13:29 +00:00
new Param ( "ease" , Util . EasingFunction . Ease . Linear , "Ease Type" ) ,
2023-03-11 04:51:22 +00:00
}
) ,
2023-09-11 22:28:04 +00:00
new GameAction ( "scale view" , "Scale Viewport" , 1f , true , new List < Param > ( )
2023-03-11 04:51:22 +00:00
{
new Param ( "valA" , new EntityTypes . Float ( 0 , 50 , 1 ) , "Width" , "Next viewport width" ) ,
new Param ( "valB" , new EntityTypes . Float ( 0 , 50 , 1 ) , "Height" , "Next viewport height" ) ,
2023-06-10 19:13:29 +00:00
new Param ( "ease" , Util . EasingFunction . Ease . Linear , "Ease Type" ) ,
2023-03-11 04:51:22 +00:00
new Param ( "axis" , StaticCamera . ViewAxis . All , "Axis" , "The axis to scale the viewport in" )
}
) ,
2022-08-20 23:03:51 +00:00
new GameAction ( "screen shake" , "Screen Shake" , 1f , true ,
new List < Param > ( )
{
new Param ( "valA" , new EntityTypes . Float ( 0 , 10 , 0 ) , "Horizontal Intensity" ) ,
new Param ( "valB" , new EntityTypes . Float ( 0 , 10 , 1 ) , "Vertical Intensity" )
}
) ,
2023-09-11 22:28:04 +00:00
new GameAction ( "display textbox" , "Display Textbox" , 1f , true , new List < Param > ( )
2022-08-20 23:03:51 +00:00
{
new Param ( "text1" , "" , "Text" , "The text to display in the textbox (Rich Text is supported!)" ) ,
new Param ( "type" , Games . Global . Textbox . TextboxAnchor . TopMiddle , "Anchor" , "Where to anchor the textbox" ) ,
new Param ( "valA" , new EntityTypes . Float ( 0.25f , 4 , 1 ) , "Textbox Width" , "Textbox width multiplier" ) ,
new Param ( "valB" , new EntityTypes . Float ( 0.5f , 8 , 1 ) , "Textbox Height" , "Textbox height multiplier" )
}
) ,
2023-09-11 22:28:04 +00:00
new GameAction ( "display open captions" , "Display Open Captions" , 1f , true ,
new List < Param > ( )
2022-08-20 23:03:51 +00:00
{
new Param ( "text1" , "" , "Text" , "The text to display in the captions (Rich Text is supported!)" ) ,
new Param ( "type" , Games . Global . Textbox . TextboxAnchor . BottomMiddle , "Anchor" , "Where to anchor the captions" ) ,
new Param ( "valA" , new EntityTypes . Float ( 0.25f , 4 , 1 ) , "Captions Width" , "Captions width multiplier" ) ,
new Param ( "valB" , new EntityTypes . Float ( 0.5f , 8 , 1 ) , "Captions Height" , "Captions height multiplier" )
2023-09-11 22:28:04 +00:00
}
2022-08-20 23:03:51 +00:00
) ,
2023-09-11 22:28:04 +00:00
new GameAction ( "display closed captions" , "Display Closed Captions" , 1f , true ,
new List < Param > ( )
2022-08-20 23:03:51 +00:00
{
new Param ( "text1" , "" , "Text" , "The text to display in the captions (Rich Text is supported!)" ) ,
new Param ( "type" , Games . Global . Textbox . ClosedCaptionsAnchor . Top , "Anchor" , "Where to anchor the captions" ) ,
new Param ( "valA" , new EntityTypes . Float ( 0.5f , 4 , 1 ) , "Captions Height" , "Captions height multiplier" )
}
) ,
2023-09-11 22:28:04 +00:00
new GameAction ( "display song artist" , "Display Song Info" , 1f , true ,
2022-08-20 23:03:51 +00:00
new List < Param > ( )
{
new Param ( "text1" , "" , "Title" , "Text to display in the upper label (Rich Text is supported!)" ) ,
new Param ( "text2" , "" , "Artist" , "Text to display in the lower label (Rich Text is supported!)" ) ,
}
) ,
2022-06-04 03:15:05 +00:00
} ) ,
2022-01-17 19:23:18 +00:00
} ;
2022-06-04 03:15:05 +00:00
2022-04-12 16:14:46 +00:00
BuildLoadRunnerList ( ) ;
2023-09-11 22:28:04 +00:00
foreach ( var load in loadRunners )
2022-04-12 17:30:22 +00:00
{
Debug . Log ( "Running game loader " + RuntimeReflectionExtensions . GetMethodInfo ( load ) . DeclaringType . Name ) ;
2022-04-12 16:14:46 +00:00
eventCaller . minigames . Add ( load ( eventCaller ) ) ;
2022-04-12 17:30:22 +00:00
}
2022-01-17 19:23:18 +00:00
}
}
}