Skip to content

Commit 8b8a241

Browse files
committed
Merge branch 'dev'
2 parents d4dafe8 + de99dcd commit 8b8a241

File tree

16 files changed

+403
-111
lines changed

16 files changed

+403
-111
lines changed

.github/workflows/publish.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: Publish to NuGet & Thunderstore
2+
3+
on:
4+
push:
5+
branches:
6+
- 'master'
7+
8+
jobs:
9+
publish:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v3
13+
- uses: actions/setup-dotnet@v3
14+
with:
15+
dotnet-version: '6.0'
16+
- run: dotnet tool install -g tcli
17+
- run: dotnet build -c Release
18+
- run: dotnet nuget push bin/Release/*.nupkg -k ${{ secrets.NUGET_KEY }} -s https://api.nuget.org/v3/index.json
19+
- run: tcli publish --file bin/Release/net472/BaboonAPI-thunderstore.zip --token ${{ secrets.THUNDERSTORE_TOKEN }}

BaboonAPI/BaboonAPI.fsproj

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
<PropertyGroup>
2525
<PackageId>TromboneChamp.BaboonAPI</PackageId>
2626
<Title>BaboonAPI</Title>
27-
<Version>2.5.0</Version>
27+
<Version>2.6.0-pre</Version>
2828
<Authors>offbeatwitch</Authors>
2929
<Company>TromboneChamps</Company>
3030
<PackageTags>Trombone Champ</PackageTags>
@@ -57,6 +57,7 @@
5757
<Compile Include="internal\ScoreStorage.fs" />
5858
<Compile Include="internal\EntryPointLoader.fs" />
5959
<Compile Include="internal\Debug.fs" />
60+
<Compile Include="internal\BaseGame.fs" />
6061
<Compile Include="patch\TrackCountPatches.fs" />
6162
<Compile Include="patch\TrackrefPatches.fs" />
6263
<Compile Include="patch\BaseTracksLoaderPatch.fs" />
@@ -74,7 +75,7 @@
7475
<ItemGroup>
7576
<PackageReference Include="BepInEx.Core" Version="5.*" />
7677
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
77-
<PackageReference Include="TromboneChamp.GameLibs" Version="1.13.0-beta" />
78+
<PackageReference Include="TromboneChamp.GameLibs" Version="1.18.0" />
7879
</ItemGroup>
7980

8081
<ItemGroup>

BaboonAPI/Library.fs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ open BaboonAPI.Patch
77
open BepInEx
88
open HarmonyLib
99

10-
[<BepInPlugin("ch.offbeatwit.baboonapi.plugin", "BaboonAPI", "2.5.0.0")>]
10+
[<BepInPlugin("ch.offbeatwit.baboonapi.plugin", "BaboonAPI", "2.6.0.0")>]
1111
type BaboonPlugin() =
1212
inherit BaseUnityPlugin()
1313

@@ -21,6 +21,10 @@ type BaboonPlugin() =
2121
// Apply the initializer patchset
2222
harmony.PatchAll(typeof<BrandingPatch>)
2323

24+
member this.TestReload () =
25+
TrackAccessor.loadAsync()
26+
|> this.StartCoroutine
27+
2428
member this.TryLoadTracks() =
2529
try
2630
TrackAccessor.load()

BaboonAPI/api-post/TrackLookup.fs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ let public allTracks (): TromboneTrack list =
2727
let public reload () =
2828
TrackAccessor.load()
2929

30+
/// <summary>Reload the list of tracks asynchronously.</summary>
31+
/// <returns>A Unity coroutine that must be started using StartCoroutine.</returns>
32+
let public reloadAsync () =
33+
TrackAccessor.loadAsync()
34+
3035
/// Highest rank & most recent 5 high scores for a track
3136
type public SavedTrackScore =
3237
{ highestRank: string

BaboonAPI/internal/BaseGame.fs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
namespace BaboonAPI.Internal.BaseGame
2+
3+
open System.IO
4+
open System.Runtime.Serialization.Formatters.Binary
5+
open BaboonAPI.Hooks.Tracks
6+
open BaboonAPI.Utility
7+
open BaboonAPI.Utility.Unity
8+
open UnityEngine
9+
10+
/// Base game loaded track, emulates base game behaviour for charts
11+
type public BaseGameLoadedTrack internal (trackref: string, bundle: AssetBundle) =
12+
interface LoadedTromboneTrack with
13+
member this.LoadAudio() =
14+
let obj = bundle.LoadAsset<GameObject>($"music_{trackref}")
15+
let src = obj.GetComponent<AudioSource>()
16+
{ Clip = src.clip; Volume = src.volume }
17+
18+
member this.LoadBackground _ctx =
19+
bundle.LoadAsset<GameObject> $"BGCam_{trackref}"
20+
21+
member this.Dispose() =
22+
bundle.Unload true
23+
24+
member this.SetUpBackgroundDelayed _ _ =
25+
()
26+
27+
member this.trackref = trackref
28+
29+
interface PauseAware with
30+
member this.CanResume = true
31+
32+
member this.OnPause _ = ()
33+
34+
member this.OnResume _ = ()
35+
36+
/// Base game TromboneTrack
37+
type public BaseGameTrack internal (data: string[]) =
38+
interface TromboneTrack with
39+
member _.trackname_long = data[0]
40+
member _.trackname_short = data[1]
41+
member _.trackref = data[2]
42+
member _.year = data[3]
43+
member _.artist = data[4]
44+
member _.genre = data[5]
45+
member _.desc = data[6]
46+
member _.difficulty = int data[7]
47+
member _.length = int data[8]
48+
member _.tempo = int data[9]
49+
50+
member this.LoadTrack() =
51+
let trackref = (this :> TromboneTrack).trackref
52+
let bundle = AssetBundle.LoadFromFile $"{Application.streamingAssetsPath}/trackassets/{trackref}"
53+
new BaseGameLoadedTrack (trackref, bundle)
54+
55+
member this.IsVisible() =
56+
let trackref = (this :> TromboneTrack).trackref
57+
match trackref with
58+
| "einefinal" -> GlobalVariables.localsave.progression_trombone_champ
59+
| _ -> true
60+
61+
member this.LoadChart() =
62+
let trackref = (this :> TromboneTrack).trackref
63+
let path = $"{Application.streamingAssetsPath}/leveldata/{trackref}.tmb"
64+
use stream = File.Open(path, FileMode.Open)
65+
BinaryFormatter().Deserialize(stream) :?> SavedLevel
66+
67+
interface Previewable with
68+
member this.LoadClip() =
69+
let trackref = (this :> TromboneTrack).trackref
70+
let path = $"{Application.streamingAssetsPath}/trackclips/{trackref}-sample.ogg"
71+
72+
loadAudioClip (path, AudioType.OGGVORBIS)
73+
|> Coroutines.map (Result.map (fun audioClip -> { Clip = audioClip; Volume = 0.9f }))
74+
75+
interface Graphable with
76+
member this.CreateGraph() =
77+
match (this :> TromboneTrack).trackref with
78+
| "warmup" -> Some (SongGraph.all 10)
79+
| "einefinal" -> Some (SongGraph.all 104)
80+
| _ -> None
81+
82+
type internal BaseGameTrackRegistry(songs: SongData) =
83+
/// List of base game trackrefs
84+
member _.trackrefs =
85+
songs.data_tracktitles
86+
|> Seq.map (fun data -> data[2])
87+
|> Seq.toList
88+
89+
interface TrackRegistrationEvent.Listener with
90+
override this.OnRegisterTracks () = seq {
91+
for array in songs.data_tracktitles do
92+
yield BaseGameTrack array
93+
}

BaboonAPI/internal/EntryPointLoader.fs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,15 @@ let scan<'t> (plugin: PluginInfo): 't EntryPointContainer list =
4444
let pluginType = plugin.Instance.GetType()
4545
let assembly = pluginType.Assembly
4646

47+
let types =
48+
try
49+
assembly.GetTypes()
50+
with
51+
| :? ReflectionTypeLoadException as exc ->
52+
exc.Types |> Array.filter (isNull >> not)
53+
4754
let candidates =
48-
assembly.GetTypes()
55+
types
4956
|> Seq.filter target.IsAssignableFrom
5057
|> Seq.filter (getCustomAttribute<BaboonEntryPointAttribute> >> Option.isSome)
5158

BaboonAPI/internal/TrackAccessor.fs

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
open System.Collections.Generic
44
open BaboonAPI.Hooks.Tracks
5+
open BaboonAPI.Utility.Coroutines
56

67
exception DuplicateTrackrefException of string
78

@@ -36,22 +37,40 @@ let private checkForDuplicates (tracks: seq<string * RegisteredTrack>): seq<stri
3637

3738
type TrackLoader() =
3839
let mutable tracks = Map.empty
39-
let mutable tracksByIndex = []
40+
let mutable tracksByIndex = Array.empty
4041

41-
member _.LoadTracks() =
42-
tracks <-
43-
TrackRegistrationEvent.EVENT.invoker.OnRegisterTracks()
42+
let makeTrackLoader () =
43+
TrackRegistrationEvent.EVENT.invoker.OnRegisterTracks()
4444
|> Seq.indexed
4545
|> Seq.map (fun (i, track) -> track.trackref, { track = track; trackIndex = i })
4646
|> checkForDuplicates
47-
|> Map.ofSeq
4847

49-
let unsorted = tracks.Values |> List.ofSeq
50-
tracksByIndex <- unsorted |> List.permute (fun i -> unsorted[i].trackIndex)
48+
let onTracksLoaded (loaded: seq<string * RegisteredTrack>) =
49+
// Our track sequence is already sorted - trackIndex is set above ^
50+
let sortedTracks = loaded |> Seq.toArray
51+
tracks <- Map.ofArray sortedTracks
52+
tracksByIndex <- sortedTracks |> Array.map snd
5153

52-
let allTracks = tracks.Values |> Seq.map (fun rt -> rt.track) |> Seq.toList
54+
let allTracks = tracksByIndex |> Seq.map (fun rt -> rt.track) |> Seq.toList
5355
TracksLoadedEvent.EVENT.invoker.OnTracksLoaded allTracks
5456

57+
member _.LoadTracks() =
58+
makeTrackLoader() |> onTracksLoaded
59+
60+
member _.LoadTracksAsync () =
61+
coroutine {
62+
let task = Async.StartAsTask (async {
63+
return makeTrackLoader()
64+
})
65+
66+
yield WaitForTask(task)
67+
68+
if task.IsCompletedSuccessfully then
69+
onTracksLoaded task.Result
70+
else if task.IsFaulted then
71+
raise task.Exception
72+
}
73+
5574
member _.Tracks = tracks
5675
member _.TracksByIndex = tracksByIndex
5776

@@ -73,9 +92,12 @@ let fetchTrackIndex (ref: string) = trackLoader.lookup(ref).trackIndex
7392

7493
let trackCount () = trackLoader.Tracks.Count
7594

76-
let allTracks () = trackLoader.TracksByIndex |> Seq.ofList
95+
let allTracks () = trackLoader.TracksByIndex |> Seq.ofArray
7796

7897
let toTrackData (track: TromboneTrack) = makeTrackData track (fetchTrackIndex track.trackref)
7998

8099
let load () =
81100
trackLoader.LoadTracks()
101+
102+
let loadAsync () =
103+
trackLoader.LoadTracksAsync()

BaboonAPI/patch/BaseTracksLoaderPatch.fs

Lines changed: 1 addition & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -4,95 +4,11 @@ open System.IO
44
open System.Runtime.Serialization.Formatters.Binary
55
open BaboonAPI.Hooks.Tracks
66
open BaboonAPI.Internal
7-
open BaboonAPI.Utility
8-
open BaboonAPI.Utility.Unity
7+
open BaboonAPI.Internal.BaseGame
98
open BepInEx.Logging
109
open HarmonyLib
1110
open UnityEngine
1211

13-
type internal BaseGameLoadedTrack(trackref: string, bundle: AssetBundle) =
14-
interface LoadedTromboneTrack with
15-
member this.LoadAudio() =
16-
let obj = bundle.LoadAsset<GameObject>($"music_{trackref}")
17-
let src = obj.GetComponent<AudioSource>()
18-
{ Clip = src.clip; Volume = src.volume }
19-
20-
member this.LoadBackground _ctx =
21-
bundle.LoadAsset<GameObject> $"BGCam_{trackref}"
22-
23-
member this.Dispose() =
24-
bundle.Unload true
25-
26-
member this.SetUpBackgroundDelayed _ _ =
27-
()
28-
29-
member this.trackref = trackref
30-
31-
interface PauseAware with
32-
member this.CanResume = true
33-
34-
member this.OnPause _ = ()
35-
36-
member this.OnResume _ = ()
37-
38-
type internal BaseGameTrack(data: string[]) =
39-
interface TromboneTrack with
40-
member _.trackname_long = data[0]
41-
member _.trackname_short = data[1]
42-
member _.trackref = data[2]
43-
member _.year = data[3]
44-
member _.artist = data[4]
45-
member _.genre = data[5]
46-
member _.desc = data[6]
47-
member _.difficulty = int data[7]
48-
member _.length = int data[8]
49-
member _.tempo = int data[9]
50-
51-
member this.LoadTrack() =
52-
let trackref = (this :> TromboneTrack).trackref
53-
let bundle = AssetBundle.LoadFromFile $"{Application.streamingAssetsPath}/trackassets/{trackref}"
54-
new BaseGameLoadedTrack (trackref, bundle)
55-
56-
member this.IsVisible() =
57-
let trackref = (this :> TromboneTrack).trackref
58-
match trackref with
59-
| "einefinal" -> GlobalVariables.localsave.progression_trombone_champ
60-
| _ -> true
61-
62-
member this.LoadChart() =
63-
let trackref = (this :> TromboneTrack).trackref
64-
let path = $"{Application.streamingAssetsPath}/leveldata/{trackref}.tmb"
65-
use stream = File.Open(path, FileMode.Open)
66-
BinaryFormatter().Deserialize(stream) :?> SavedLevel
67-
68-
interface Previewable with
69-
member this.LoadClip() =
70-
let trackref = (this :> TromboneTrack).trackref
71-
let path = $"{Application.streamingAssetsPath}/trackclips/{trackref}-sample.ogg"
72-
73-
loadAudioClip (path, AudioType.OGGVORBIS)
74-
|> Coroutines.map (Result.map (fun audioClip -> { Clip = audioClip; Volume = 0.9f }))
75-
76-
interface Graphable with
77-
member this.CreateGraph() =
78-
match (this :> TromboneTrack).trackref with
79-
| "warmup" -> Some (SongGraph.all 10)
80-
| "einefinal" -> Some (SongGraph.all 104)
81-
| _ -> None
82-
83-
type internal BaseGameTrackRegistry(songs: SongData) =
84-
/// List of base game trackrefs
85-
member _.trackrefs =
86-
songs.data_tracktitles
87-
|> Seq.map (fun data -> data[2])
88-
|> Seq.toList
89-
90-
interface TrackRegistrationEvent.Listener with
91-
override this.OnRegisterTracks () = seq {
92-
for array in songs.data_tracktitles do
93-
yield BaseGameTrack array
94-
}
95-
9612
[<HarmonyPatch(typeof<SaverLoader>, "loadLevelData")>]
9713
type LoaderPatch() =
9814
static let logger = Logger.CreateLogSource "BaboonAPI.BaseTracksLoader"

BaboonAPI/patch/GameControllerPatch.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ type private GameControllerExtension() =
4141
if not instance.freeplay then
4242
let audio = l.LoadAudio()
4343
instance.musictrack.clip <- audio.Clip
44-
instance.musictrack.volume <- audio.Volume
44+
instance.musictrack.volume <- audio.Volume * GlobalVariables.localsettings.maxvolume_music
4545

4646
let context = BackgroundContext instance
4747
let bgObj = Object.Instantiate<GameObject>(

0 commit comments

Comments
 (0)