Skip to content

Commit

Permalink
Merge branch 'dev' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
VolcanicArts committed Apr 26, 2023
2 parents e03b053 + bcd0fec commit b0bb0a7
Show file tree
Hide file tree
Showing 39 changed files with 720 additions and 220 deletions.
4 changes: 2 additions & 2 deletions VRCOSC.Desktop/VRCOSC.Desktop.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
<ApplicationIcon>game.ico</ApplicationIcon>
<ApplicationManifest>app.manifest</ApplicationManifest>
<Version>0.0.0</Version>
<FileVersion>2023.424.0</FileVersion>
<FileVersion>2023.426.0</FileVersion>
<Title>VRCOSC</Title>
<Authors>VolcanicArts</Authors>
<Company>VolcanicArts</Company>
<Nullable>enable</Nullable>
<AssemblyVersion>2023.424.0</AssemblyVersion>
<AssemblyVersion>2023.426.0</AssemblyVersion>
</PropertyGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\VRCOSC.Game\VRCOSC.Game.csproj" />
Expand Down
150 changes: 100 additions & 50 deletions VRCOSC.Game/ChatBox/ChatBoxManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Newtonsoft.Json;
using osu.Framework.Bindables;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Platform;
using VRCOSC.Game.ChatBox.Clips;
using VRCOSC.Game.ChatBox.Serialisation.V1;
using VRCOSC.Game.Graphics.Notifications;
using VRCOSC.Game.Modules;
using VRCOSC.Game.OSC.VRChat;

Expand Down Expand Up @@ -41,14 +43,16 @@ public bool SendEnabled
public IReadOnlyDictionary<string, bool> ModuleEnabledCache = null!;
private Bindable<int> sendDelay = null!;
private VRChatOscClient oscClient = null!;
private NotificationContainer notification = null!;
private TimelineSerialiser serialiser = null!;

public readonly Dictionary<(string, string), string?> VariableValues = new();
public readonly Dictionary<string, string> StateValues = new();
public readonly List<(string, string)> TriggeredEvents = new();
private readonly object triggeredEventsLock = new();

public readonly Bindable<TimeSpan> TimelineLength = new(TimeSpan.FromMinutes(1));
public readonly Bindable<TimeSpan> TimelineLength = new();
public int TimelineLengthSeconds => (int)TimelineLength.Value.TotalSeconds;
public float TimelineResolution => 1f / (float)TimelineLength.Value.TotalSeconds;

public float CurrentPercentage => ((DateTimeOffset.Now - startTime).Ticks % TimelineLength.Value.Ticks) / (float)TimelineLength.Value.Ticks;
Expand All @@ -62,96 +66,122 @@ public bool SendEnabled
private bool isClear;
private bool isLoaded;

public void Load(Storage storage, GameManager gameManager)
public void Load(Storage storage, GameManager gameManager, NotificationContainer notification)
{
GameManager = gameManager;
serialiser = new TimelineSerialiser(storage);
this.notification = notification;

bool clipDataLoaded;

if (storage.Exists(@"chatbox.json"))
loadClipData();
{
clipDataLoaded = loadClipData();
}
else
{
Clips.AddRange(DefaultTimeline.GenerateDefaultTimeline(this));
TimelineLength.Value = TimeSpan.FromMinutes(1);
clipDataLoaded = true;
}

Clips.BindCollectionChanged((_, _) => Save());
TimelineLength.BindValueChanged(_ => Save());

isLoaded = true;

Save();
if (clipDataLoaded) Save();
}

private void loadClipData()
private bool loadClipData()
{
var clips = serialiser.Deserialise()?.Clips;
try
{
var data = serialiser.Deserialise();

if (clips is null) return;
if (data is null)
{
notification.Notify(new ExceptionNotification("Could not parse ChatBox config. Report on the Discord server"));
return false;
}

clips.ForEach(clip =>
{
clip.AssociatedModules.ToImmutableList().ForEach(moduleName =>
TimelineLength.Value = TimeSpan.FromTicks(data.Ticks);

data.Clips.ForEach(clip =>
{
if (!StateMetadata.ContainsKey(moduleName))
clip.AssociatedModules.ToImmutableList().ForEach(moduleName =>
{
clip.AssociatedModules.Remove(moduleName);
if (!StateMetadata.ContainsKey(moduleName))
{
clip.AssociatedModules.Remove(moduleName);

clip.States.ToImmutableList().ForEach(clipState =>
{
clipState.States.RemoveAll(pair => pair.Module == moduleName);
});

clip.Events.RemoveAll(clipEvent => clipEvent.Module == moduleName);

return;
}

clip.States.ToImmutableList().ForEach(clipState =>
{
clipState.States.RemoveAll(pair => pair.Module == moduleName);
clipState.States.RemoveAll(pair => !StateMetadata[pair.Module].ContainsKey(pair.Lookup));
});

clip.Events.RemoveAll(clipEvent => clipEvent.Module == moduleName);

return;
}

clip.States.ToImmutableList().ForEach(clipState =>
{
clipState.States.RemoveAll(pair => !StateMetadata[pair.Module].ContainsKey(pair.Lookup));
clip.Events.RemoveAll(clipEvent => !EventMetadata[clipEvent.Module].ContainsKey(clipEvent.Lookup));
});

clip.Events.RemoveAll(clipEvent => !EventMetadata[clipEvent.Module].ContainsKey(clipEvent.Lookup));
});
});

clips.ForEach(clip =>
{
var newClip = CreateClip();
data.Clips.ForEach(clip =>
{
var newClip = CreateClip();

newClip.Enabled.Value = clip.Enabled;
newClip.Name.Value = clip.Name;
newClip.Priority.Value = clip.Priority;
newClip.Start.Value = clip.Start;
newClip.End.Value = clip.End;
newClip.Enabled.Value = clip.Enabled;
newClip.Name.Value = clip.Name;
newClip.Priority.Value = clip.Priority;
newClip.Start.Value = clip.Start;
newClip.End.Value = clip.End;

newClip.AssociatedModules.AddRange(clip.AssociatedModules);
newClip.AssociatedModules.AddRange(clip.AssociatedModules);

clip.States.ForEach(clipState =>
{
var stateData = newClip.GetStateFor(clipState.States.Select(state => state.Module), clipState.States.Select(state => state.Lookup));
if (stateData is null) return;
clip.States.ForEach(clipState =>
{
var stateData = newClip.GetStateFor(clipState.States.Select(state => state.Module), clipState.States.Select(state => state.Lookup));
if (stateData is null) return;

stateData.Enabled.Value = clipState.Enabled;
stateData.Format.Value = clipState.Format;
});
stateData.Enabled.Value = clipState.Enabled;
stateData.Format.Value = clipState.Format;
});

clip.Events.ForEach(clipEvent =>
{
var eventData = newClip.GetEventFor(clipEvent.Module, clipEvent.Lookup);
if (eventData is null) return;
clip.Events.ForEach(clipEvent =>
{
var eventData = newClip.GetEventFor(clipEvent.Module, clipEvent.Lookup);
if (eventData is null) return;

eventData.Enabled.Value = clipEvent.Enabled;
eventData.Format.Value = clipEvent.Format;
eventData.Length.Value = clipEvent.Length;
eventData.Enabled.Value = clipEvent.Enabled;
eventData.Format.Value = clipEvent.Format;
eventData.Length.Value = clipEvent.Length;
});

Clips.Add(newClip);
});

Clips.Add(newClip);
});
return true;
}
catch (JsonReaderException)
{
notification.Notify(new ExceptionNotification("Could not load ChatBox config. Report on the Discord server"));
return false;
}
}

public void Save()
{
if (!isLoaded) return;

serialiser.Serialise(Clips.ToList());
serialiser.Serialise(this);
}

public void Initialise(VRChatOscClient oscClient, Bindable<int> sendDelay, Dictionary<string, bool> moduleEnabledCache)
Expand Down Expand Up @@ -194,6 +224,26 @@ public void Shutdown()
StateValues.Clear();
}

public void IncreaseTime(int amount)
{
var newTime = TimelineLength.Value + TimeSpan.FromSeconds(amount);
setNewTime(newTime);
}

public void DecreaseTime(int amount)
{
var newTime = TimelineLength.Value - TimeSpan.FromSeconds(amount);
setNewTime(newTime);
}

private void setNewTime(TimeSpan newTime)
{
if (newTime.TotalSeconds < 1) newTime = TimeSpan.FromSeconds(1);
if (newTime.TotalSeconds > 4 * 60) newTime = TimeSpan.FromSeconds(4 * 60);

TimelineLength.Value = newTime;
}

private void evaluateClips()
{
var validClip = getValidClip();
Expand Down
20 changes: 17 additions & 3 deletions VRCOSC.Game/ChatBox/Clips/Clip.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,19 @@ public void InjectDependencies(ChatBoxManager chatBoxManager)
Enabled.BindValueChanged(_ => chatBoxManager.Save());
Name.BindValueChanged(_ => chatBoxManager.Save());
Priority.BindValueChanged(_ => chatBoxManager.Save());
Start.BindValueChanged(_ => chatBoxManager.Save());
End.BindValueChanged(_ => chatBoxManager.Save());
States.BindCollectionChanged((_, _) => chatBoxManager.Save());
Events.BindCollectionChanged((_, _) => chatBoxManager.Save());

chatBoxManager.TimelineLength.BindValueChanged(_ =>
{
if (chatBoxManager.TimelineLengthSeconds <= Start.Value)
{
chatBoxManager.DeleteClip(this);
return;
}

if (chatBoxManager.TimelineLengthSeconds < End.Value) End.Value = chatBoxManager.TimelineLengthSeconds;
});
}

public void Initialise()
Expand All @@ -59,6 +68,11 @@ public void Update()
setCurrentEvent();
}

public void Save()
{
chatBoxManager.Save();
}

private void auditEvents()
{
chatBoxManager.TriggeredEvents.ForEach(moduleEvent =>
Expand Down Expand Up @@ -129,7 +143,7 @@ public bool Evalulate()
removeLessCompoundedStates(localStates);
removeInvalidStates(localStates);

if (!localStates.Any()) return false;
if (localStates.Count != 1) return false;

var chosenState = localStates.Single();
if (!chosenState.Enabled.Value) return false;
Expand Down
4 changes: 1 addition & 3 deletions VRCOSC.Game/ChatBox/Serialisation/ITimelineSerialiser.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
// Copyright (c) VolcanicArts. Licensed under the GPL-3.0 License.
// See the LICENSE file in the repository root for full license text.

using System.Collections.Generic;
using VRCOSC.Game.ChatBox.Clips;
using VRCOSC.Game.ChatBox.Serialisation.V1.Structures;

namespace VRCOSC.Game.ChatBox.Serialisation;

public interface ITimelineSerialiser
{
public void Serialise(List<Clip> clips);
public void Serialise(ChatBoxManager chatBoxManager);
public SerialisableTimeline? Deserialise();
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// Copyright (c) VolcanicArts. Licensed under the GPL-3.0 License.
// See the LICENSE file in the repository root for full license text.

using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using VRCOSC.Game.ChatBox.Clips;
using osu.Framework.Extensions.IEnumerableExtensions;

namespace VRCOSC.Game.ChatBox.Serialisation.V1.Structures;

Expand All @@ -12,6 +13,9 @@ public class SerialisableTimeline
[JsonProperty("version")]
public int Version = 1;

[JsonProperty("length")]
public long Ticks = TimeSpan.FromMinutes(1).Ticks;

[JsonProperty("clips")]
public List<SerialisableClip> Clips = new();

Expand All @@ -20,8 +24,9 @@ public SerialisableTimeline()
{
}

public SerialisableTimeline(List<Clip> clips)
public SerialisableTimeline(ChatBoxManager chatBoxManager)
{
clips.ForEach(clip => Clips.Add(new SerialisableClip(clip)));
Ticks = chatBoxManager.TimelineLength.Value.Ticks;
chatBoxManager.Clips.ForEach(clip => Clips.Add(new SerialisableClip(clip)));
}
}
6 changes: 2 additions & 4 deletions VRCOSC.Game/ChatBox/Serialisation/V1/TimelineSerialiser.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
// Copyright (c) VolcanicArts. Licensed under the GPL-3.0 License.
// See the LICENSE file in the repository root for full license text.

using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
using osu.Framework.Platform;
using VRCOSC.Game.ChatBox.Clips;
using VRCOSC.Game.ChatBox.Serialisation.V1.Structures;

namespace VRCOSC.Game.ChatBox.Serialisation.V1;
Expand All @@ -20,11 +18,11 @@ public TimelineSerialiser(Storage storage)
this.storage = storage;
}

public void Serialise(List<Clip> clips)
public void Serialise(ChatBoxManager chatBoxManager)
{
using var stream = storage.CreateFileSafely(file_name);
using var writer = new StreamWriter(stream);
writer.Write(JsonConvert.SerializeObject(new SerialisableTimeline(clips)));
writer.Write(JsonConvert.SerializeObject(new SerialisableTimeline(chatBoxManager)));
}

public SerialisableTimeline? Deserialise()
Expand Down
15 changes: 15 additions & 0 deletions VRCOSC.Game/Graphics/ChatBox/ChatBoxScreen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ private void load()
{
new Dimension(),
new Dimension(GridSizeMode.Absolute, 5),
new Dimension(GridSizeMode.Absolute, 40),
new Dimension(GridSizeMode.Absolute, 5),
new Dimension()
},
Content = new[]
Expand All @@ -60,6 +62,19 @@ private void load()
},
null,
new Drawable[]
{
new TimelineLengthContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Width = 0.2f,
Masking = true,
CornerRadius = 10
}
},
null,
new Drawable[]
{
new TimelineWrapper
{
Expand Down
Loading

0 comments on commit b0bb0a7

Please sign in to comment.