refactor asset loading

This commit is contained in:
2023-08-29 16:15:37 -06:00
parent e2bb87f3d5
commit f3722910e4
6 changed files with 145 additions and 67 deletions

10
memory-fix.org Normal file
View File

@@ -0,0 +1,10 @@
* DONE for all asset types, make the Director define load*()
* DONE instead of requiring Cloneable<Set>, add Director.cloneSet()
* DONE in all newMethods take a path, not the object.
** DONE allow for alternative loading with the object directly, like how some props in HollywooFlixel are animated via ActorFlxSprite
** DONE if the assetpath doesn't start with assets/, call (assetPath "<typeDir>" "<path>")
** DONE make loading things at runtime a compiler error
* TODO in all new* methods, save the path that was loaded
* TODO in all with_ macros, mark those assets as dirty (needing to be reloaded)
* TODO Movie.scavenge before cleanup
* TODO in all new* methods, don't load the new thing if it exists already

View File

@@ -26,7 +26,7 @@ typedef AutoZConfig = {
}; };
@:keepSub @:keepSub
interface Director<Set:Cloneable<Set>, Actor, Sound, Song, Prop, VoiceTrack, Camera, LightSource:Jsonable<LightSource>> { interface Director<Set, Actor, Sound, Song, Prop, VoiceTrack, Camera, LightSource:Jsonable<LightSource>> {
var movie(default, default):Movie<Set, Actor, Sound, Song, Prop, VoiceTrack, Camera, LightSource>; var movie(default, default):Movie<Set, Actor, Sound, Song, Prop, VoiceTrack, Camera, LightSource>;
function autoZConfig():Option<AutoZConfig>; function autoZConfig():Option<AutoZConfig>;
@@ -51,15 +51,19 @@ interface Director<Set:Cloneable<Set>, Actor, Sound, Song, Prop, VoiceTrack, Cam
function defineStagePosition(camera:Camera, submit:StagePosition->Void, ?oldPosition:StagePosition):Void; function defineStagePosition(camera:Camera, submit:StagePosition->Void, ?oldPosition:StagePosition):Void;
function defineLightSource(submit:LightSource->Void):Void; function defineLightSource(submit:LightSource->Void):Void;
function loadSet(path:String):Set;
function cloneSet(set:Set):Set;
function showSet(set:Set, time:SceneTime, perspective:ScenePerspective, appearance:Appearance, camera:Camera, cc:Continuation):Void; function showSet(set:Set, time:SceneTime, perspective:ScenePerspective, appearance:Appearance, camera:Camera, cc:Continuation):Void;
function hideSet(set:Set, camera: Camera, cc:Continuation):Void; function hideSet(set:Set, camera: Camera, cc:Continuation):Void;
function showLighting(sceneTime:SceneTime, lightSources:Array<LightSource>, camera:Camera):Void; function showLighting(sceneTime:SceneTime, lightSources:Array<LightSource>, camera:Camera):Void;
function hideLighting():Void; function hideLighting():Void;
function loadActor(path:String):Actor;
function showCharacter(character:Character<Actor>, appearance:Appearance, camera:Camera, cc:Continuation):Void; function showCharacter(character:Character<Actor>, appearance:Appearance, camera:Camera, cc:Continuation):Void;
function hideCharacter(character:Character<Actor>, camera:Camera, cc:Continuation):Void; function hideCharacter(character:Character<Actor>, camera:Camera, cc:Continuation):Void;
function loadSound(path:String):Sound;
function playSound(sound:Sound, volumeMod:Float, ?cc:Continuation):Void; function playSound(sound:Sound, volumeMod:Float, ?cc:Continuation):Void;
function getSoundLength(sound:Sound):Float; function getSoundLength(sound:Sound):Float;
function stopSound(sound:Sound):Void; function stopSound(sound:Sound):Void;
@@ -67,11 +71,13 @@ interface Director<Set:Cloneable<Set>, Actor, Sound, Song, Prop, VoiceTrack, Cam
function showCaption(description:String, id:Int):Void; function showCaption(description:String, id:Int):Void;
function hideCaption(id:Int):Void; function hideCaption(id:Int):Void;
function loadSong(path:String):Song;
function playSong(song:Song, volumeMod:Float, loop:Bool, waitForEnd:Bool, cc:Continuation):Void; function playSong(song:Song, volumeMod:Float, loop:Bool, waitForEnd:Bool, cc:Continuation):Void;
function getSongLength(song:Song):Float; function getSongLength(song:Song):Float;
function changeSongVolume(volumeMod:Float, cc:Continuation):Void; function changeSongVolume(volumeMod:Float, cc:Continuation):Void;
function stopSong():Void; function stopSong():Void;
function loadVoiceTrack(path:String):VoiceTrack;
function playVoiceTrack(track:VoiceTrack, volumeMod:Float, start:Float, end:Float, cc:Continuation):Void; function playVoiceTrack(track:VoiceTrack, volumeMod:Float, start:Float, end:Float, cc:Continuation):Void;
function stopVoiceTrack(track:VoiceTrack):Void; function stopVoiceTrack(track:VoiceTrack):Void;
@@ -87,6 +93,7 @@ interface Director<Set:Cloneable<Set>, Actor, Sound, Song, Prop, VoiceTrack, Cam
function showBlackScreen():Void; function showBlackScreen():Void;
function hideBlackScreen():Void; function hideBlackScreen():Void;
function loadProp(path:String):Prop;
function showProp(prop:Prop, position:StagePosition, appearance:Appearance, camera:Camera, cc:Continuation):Void; function showProp(prop:Prop, position:StagePosition, appearance:Appearance, camera:Camera, cc:Continuation):Void;
function hideProp(prop:Prop, camera:Camera, cc:Continuation):Void; function hideProp(prop:Prop, camera:Camera, cc:Continuation):Void;

View File

@@ -73,15 +73,29 @@
(director.showTitleCard ["LOADING"] (director.showTitleCard ["LOADING"]
(makeCC (makeCC
(set isLoading true) (set isLoading true)
(director.doLoading ,preloadFuncs (let [loadVoiceTrack _loadVoiceTrack
(makeCC addVoiceTrack _addVoiceTrack
(set isLoading false) noVoiceTracks _noVoiceTracks
(.start (director.shortcutHandler)) loadProp _loadProp
(director.hideTitleCard) addProp _addProp
// When all loading is done, prompt to start obs recording automatically: loadSong _loadSong
(#if debug addSong _addSong
(promptToRecord cc) loadActor _loadActor
(cc))))))) addActor _addActor
loadSet _loadSet
addSet _addSet
newSceneFromSet _newSceneFromSet
loadSound _loadSound
addSound _addSound]
(director.doLoading ,preloadFuncs
(makeCC
(set isLoading false)
(.start (director.shortcutHandler))
(director.hideTitleCard)
// When all loading is done, prompt to start obs recording automatically:
(#if debug
(promptToRecord cc)
(cc))))))))
@:keep @:keep
(method doCleanup [] (method doCleanup []
(director.cleanup) (director.cleanup)

View File

@@ -20,10 +20,6 @@ import kiss_tools.TimerWithPause;
using kiss.FuzzyMapTools; using kiss.FuzzyMapTools;
typedef Cloneable<T> = {
function clone():T;
}
enum DelayHandling { enum DelayHandling {
Auto; Auto;
AutoWithSkip; AutoWithSkip;
@@ -65,4 +61,4 @@ enum PlayMode {
* Model/controller of a Hollywoo film, and main execution script * Model/controller of a Hollywoo film, and main execution script
*/ */
@:build(kiss.Kiss.build()) @:build(kiss.Kiss.build())
class Movie<Set:Cloneable<Set>, Actor, Sound, Song, Prop, VoiceTrack, Camera, LightSource:Jsonable<LightSource>> extends AsyncEmbeddedScript2 {} class Movie<Set, Actor, Sound, Song, Prop, VoiceTrack, Camera, LightSource:Jsonable<LightSource>> extends AsyncEmbeddedScript2 {}

View File

@@ -142,11 +142,36 @@
(throw "No handler for custom dialog type $type"))) (throw "No handler for custom dialog type $type")))
(otherwise (director.showDialog actorName dialogType wryly text skipCC))))))) (otherwise (director.showDialog actorName dialogType wryly text skipCC)))))))
(method noVoiceTracks [actorName] (defMacro withIndexedPath [pathVar typeDefaultDir &body body]
(dictSet voiceTracksPerActor actorName 0) (#if (or sys hxnodejs)
(dictSet voiceLines actorName (new FuzzyMap<VoiceLine>))) `(let [,pathVar
(if (StringTools.startsWith ,pathVar assetDir)
,pathVar
(assetPath ,typeDefaultDir ,pathVar))]
,@body)
body))
(method newVoiceTrack [actorName :VoiceTrack track :String lineJson] // Methods for loading new assets in a hollywoo movie follow a special naming convention.
// _add*() is a method which takes the asset DIRECTLY and adds it to the corresponding asset map.
// This is to be used in cases where the asset needs to be loaded specially in a way
// the Director's load*() function can't handle.
// _load*() is a method which takes the asset's PATH and lets the Director load the asset object.
//
// Neither of these is not meant to be called directly, as a precaution against loading new assets
// at Movie runtime. However, within the context of (preload...) blocks, they will be
// bound to these names:
// add*()
// new*() At which point you can use them. Therefore, if you accidentally try to call new*()
// outside of a preload block, your code won't compile.
// Which is desired because (preload...) blocks are meant to be allowed at any point in a script,
// even following the usage of the assets they load. Runtime loading allows for errors
// caused by moving the load calls or asset usages around so the load doesn't precede the usage.
(method _loadVoiceTrack [actorName :String path :String lineJson]
(withIndexedPath path "vo"
(_addVoiceTrack actorName (director.loadVoiceTrack path) lineJson)))
(method _addVoiceTrack [actorName :VoiceTrack track :String lineJson]
(assert isLoading)
(let [actorNumVoiceTracks (or (dictGet voiceTracksPerActor actorName) 0) (let [actorNumVoiceTracks (or (dictGet voiceTracksPerActor actorName) 0)
trackKey "${actorName}${actorNumVoiceTracks}" trackKey "${actorName}${actorNumVoiceTracks}"
:haxe.DynamicAccess<Dynamic> lines (Json.parse lineJson)] :haxe.DynamicAccess<Dynamic> lines (Json.parse lineJson)]
@@ -161,6 +186,68 @@
(dictSet voiceLines actorName (new FuzzyMap<VoiceLine>))) (dictSet voiceLines actorName (new FuzzyMap<VoiceLine>)))
(dictSet (dictGet voiceLines actorName) key (objectWith [start line.start end line.end] trackKey alts)))))) (dictSet (dictGet voiceLines actorName) key (objectWith [start line.start end line.end] trackKey alts))))))
(method _noVoiceTracks [actorName]
(assert isLoading)
(dictSet voiceTracksPerActor actorName 0)
(dictSet voiceLines actorName (new FuzzyMap<VoiceLine>)))
(method _loadProp [name :String path]
(withIndexedPath path "images"
(_addProp name (director.loadProp path))))
(method _addProp [name :Prop prop]
(assert isLoading)
(dictSet props name prop))
(method _loadSong [name :String path]
(withIndexedPath path "music"
(_addSong name (director.loadSong path))))
(method _addSong [name :Song song]
(assert isLoading)
(dictSet songs name song))
(method _loadActor [name :String path]
(withIndexedPath path "images"
(_addActor name (director.loadActor path))))
(method _addActor [name :Actor actor]
(assert isLoading)
(dictSet actors name actor))
(method _loadSet [name :String path]
(withIndexedPath path "images"
(_addSet name (director.loadSet path))))
(method _addSet [name :Set set]
(assert isLoading)
(dictSet sets name set))
(method _newSceneFromSet [name :String setKey :SceneTime time :ScenePerspective perspective :Camera camera]
(assert isLoading)
(dictSet scenes name (objectWith
[
set
(director.cloneSet (dictGet sets setKey))
characters
(new FuzzyMap<Character<Actor>>)
props
(new FuzzyMap<StageProp<Prop>>)
camera
camera
]
time
perspective)))
(method _loadSound [name :String path :String description]
(withIndexedPath path "sounds"
(_addSound name (director.loadSound path) description)))
(method _addSound [name :Sound s :String description]
(assert isLoading)
(dictSet sounds name s)
(dictSet soundDescriptions name description))
(method _ccForEach <>[T] [:Iterable<T> collection :(T,Continuation)->Void do_ :Continuation finalCC] (method _ccForEach <>[T] [:Iterable<T> collection :(T,Continuation)->Void do_ :Continuation finalCC]
(let [:Iterator<T> iter (collection.iterator)] (let [:Iterator<T> iter (collection.iterator)]
(withFunctions (withFunctions
@@ -263,8 +350,10 @@
(#when (or sys hxnodejs) (#when (or sys hxnodejs)
(prop :FuzzyMap<FuzzyMap<String>> assetPaths (new FuzzyMap)) (prop :FuzzyMap<FuzzyMap<String>> assetPaths (new FuzzyMap))
(prop &mut :String assetDir "")
(prop :Array<Array<String>> loadedCredits []) (prop :Array<Array<String>> loadedCredits [])
(method _indexAssetPaths [:String assetDir] (method _indexAssetPaths [:String assetDir]
(set this.assetDir assetDir)
(let [dirParts (assetDir.split "/")] (let [dirParts (assetDir.split "/")]
(doFor part dirParts (doFor part dirParts
(dictSet assetPaths part (new FuzzyMap)))) (dictSet assetPaths part (new FuzzyMap))))
@@ -445,15 +534,8 @@
((dictGet runners label)) ((dictGet runners label))
}))))) })))))
(super))) (super))
// END Parent class definitions
(defMacro indexAssetPaths [dir]
`(preload
(_indexAssetPaths ,dir)))
(#unless subclass
@:keep @:keep
(method :Void _strobe [:Bool skipping :Bool prop :String actorOrPropKey :Float strobeSec :Int times &opt :Continuation cc] (method :Void _strobe [:Bool skipping :Bool prop :String actorOrPropKey :Float strobeSec :Int times &opt :Continuation cc]
(when skipping (when skipping
@@ -497,6 +579,13 @@
(when cc (when cc
(TimerWithPause.delay cc (* strobeSec 2 (+ 1 times))))))) (TimerWithPause.delay cc (* strobeSec 2 (+ 1 times)))))))
// END Parent class definitions
(defMacro indexAssetPaths [dir]
`(preload
(_indexAssetPaths ,dir)))
// Some real magic happens here. This macro defines a method, AND a reader macro // Some real magic happens here. This macro defines a method, AND a reader macro
// for calling it with skipping and cc passed automatically if cc is an argument. // for calling it with skipping and cc passed automatically if cc is an argument.
// GOTCHA: DO NOT use (method) directly in this file!! // GOTCHA: DO NOT use (method) directly in this file!!
@@ -574,26 +663,6 @@
})) }))
(otherwise (throw "Unsupported delay type $delayHandling"))))) (otherwise (throw "Unsupported delay type $delayHandling")))))
(hollywooMethod newSet [name :Set set]
(assert isLoading)
(dictSet sets name set))
(hollywooMethod newSceneFromSet [name :String setKey :SceneTime time :ScenePerspective perspective :Camera camera]
(assert isLoading)
(dictSet scenes name (objectWith
[
set
(.clone (dictGet sets setKey))
characters
(new FuzzyMap<Character<Actor>>)
props
(new FuzzyMap<StageProp<Prop>>)
camera
camera
]
time
perspective)))
(hollywooMethod setSceneSong [:String scene :String songKey &opt :Float volumeMod :Continuation cc] (hollywooMethod setSceneSong [:String scene :String songKey &opt :Float volumeMod :Continuation cc]
(dictSet sceneMusic scene songKey) (dictSet sceneMusic scene songKey)
(dictSet sceneMusicVolume scene volumeMod) (dictSet sceneMusicVolume scene volumeMod)
@@ -633,12 +702,6 @@
.camera (dictGet scenes name) .camera (dictGet scenes name)
cc))))) cc)))))
(hollywooMethod newSound [name :Sound s :String description]
(assert isLoading)
(dictSet sounds name s)
(dictSet soundDescriptions name description))
(hollywooMethod playSound [:Bool skipping name :Continuation cc &opt :Float volumeMod :Bool waitForEnd] (hollywooMethod playSound [:Bool skipping name :Continuation cc &opt :Float volumeMod :Bool waitForEnd]
(when skipping (when skipping
(cc) (cc)
@@ -692,10 +755,6 @@
(playAgain)))) (playAgain))))
(cc)) (cc))
(hollywooMethod newSong [name :Song song]
(assert isLoading)
(dictSet songs name song))
// This is never skipped because the music might be expected to continue on to the place // This is never skipped because the music might be expected to continue on to the place
// we skip to: // we skip to:
(hollywooMethod playSong [name :Continuation cc &opt :Float volumeMod :Bool loop :Bool waitForEnd] (hollywooMethod playSong [name :Continuation cc &opt :Float volumeMod :Bool loop :Bool waitForEnd]
@@ -719,10 +778,6 @@
(director.stopSong) (director.stopSong)
(cc)) (cc))
(hollywooMethod newActor [name :Actor actor]
(assert isLoading)
(dictSet actors name actor))
(hollywooMethod autoZProcess [:StagePosition position :Continuation cc] (hollywooMethod autoZProcess [:StagePosition position :Continuation cc]
// handle auto z recursively // handle auto z recursively
(ifLet [(Some (objectWith zPerLayer frontLayer)) (director.autoZConfig)] (ifLet [(Some (objectWith zPerLayer frontLayer)) (director.autoZConfig)]
@@ -802,10 +857,6 @@
// TODO moveCharacter remove them, add them to another scene // TODO moveCharacter remove them, add them to another scene
// TODO moveCharacterAndFollow remove them, add them to another scene, set that the scene // TODO moveCharacterAndFollow remove them, add them to another scene, set that the scene
(hollywooMethod newProp [name :Prop prop]
(assert isLoading)
(dictSet props name prop))
(hollywooMethod addProp [name :Dynamic position :Continuation cc] (hollywooMethod addProp [name :Dynamic position :Continuation cc]
(let [name (FuzzyMapTools.bestMatch props name) (let [name (FuzzyMapTools.bestMatch props name)
prop (dictGet props name) prop (dictGet props name)

View File

@@ -38,7 +38,7 @@ typedef StageProp<Prop> = {
prop:Prop prop:Prop
}; };
typedef Scene<Set:Cloneable<Set>, Actor, Prop, Camera> = { typedef Scene<Set, Actor, Prop, Camera> = {
set:Set, set:Set,
characters:FuzzyMap<Character<Actor>>, characters:FuzzyMap<Character<Actor>>,
props:FuzzyMap<StageProp<Prop>>, props:FuzzyMap<StageProp<Prop>>,