Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unity Recorder のカスタムソースに対応 #22

Merged
merged 8 commits into from
Nov 9, 2024
36 changes: 33 additions & 3 deletions Assets/ArtNet/Editor/DmxRecorder/RecordData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,24 @@ namespace ArtNet.Editor.DmxRecorder
{
public static class RecordData
{
private enum DataType
{
ArtNet = 0,
Dmx = 1
}

private const byte IdentifierLength = 4;
private static readonly byte[] Identifiers = { 0xFF, 0x44, 0x4D, 0x58 };
private static readonly byte[] ReservedBuffer = new byte[11];
private static byte Version = 0x01;
private static readonly byte[] ReservedBuffer = new byte[10];
private const byte Version = 0x01;

public static byte[] Serialize(IReadOnlyList<(int time, DmxPacket packet)> dmxPackets)
{
var startTime = dmxPackets.Select(x => x.time).OrderBy(x => x).First();
using var memoryStream = new MemoryStream();
memoryStream.Write(Identifiers);
memoryStream.WriteByte(Version);
memoryStream.WriteByte((byte) DataType.ArtNet);
memoryStream.Write(ReservedBuffer);

foreach (var (time, dmxPacket) in dmxPackets)
Expand All @@ -37,6 +44,27 @@ public static byte[] Serialize(IReadOnlyList<(int time, DmxPacket packet)> dmxPa
return memoryStream.ToArray();
}

public static byte[] SerializeUniverseData(List<UniverseData> universeData)
{
var sortedData = universeData.OrderBy(x => x.Time).ToList();
var startTime = sortedData.First().Time;
using var memoryStream = new MemoryStream();
memoryStream.Write(Identifiers);
memoryStream.WriteByte(Version);
memoryStream.WriteByte((byte) DataType.Dmx);
memoryStream.Write(ReservedBuffer);

foreach (var data in sortedData)
{
memoryStream.Write(BitConverter.GetBytes((float) data.Time - startTime));
memoryStream.Write(BitConverter.GetBytes(data.Universe));
memoryStream.Write(BitConverter.GetBytes(data.Values.Length));
memoryStream.Write(data.Values);
}

return memoryStream.ToArray();
}

public static List<(int time, DmxPacket packet)> Deserialize(ReadOnlySpan<byte> data)
{
var dataLength = data.Length;
Expand All @@ -49,7 +77,9 @@ public static byte[] Serialize(IReadOnlyList<(int time, DmxPacket packet)> dmxPa
return null;
}

var position = IdentifierLength + 1 + ReservedBuffer.Length;
var dataType = (DataType) data[IdentifierLength + 1];

var position = IdentifierLength + 2 + ReservedBuffer.Length;
var result = new List<(int time, DmxPacket packet)>();
while (position < dataLength - 10)
{
Expand Down
16 changes: 16 additions & 0 deletions Assets/ArtNet/Editor/DmxRecorder/UniverseData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace ArtNet.Editor.DmxRecorder
{
public class UniverseData
{
public double Time { get; }
public uint Universe { get; }
public byte[] Values { get; }

public UniverseData(double time, uint universe, byte[] values)
{
Time = time;
Universe = universe;
Values = values;
}
}
}
11 changes: 11 additions & 0 deletions Assets/ArtNet/Editor/DmxRecorder/UniverseData.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Assets/ArtNet/Editor/UnityRecorder.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 28 additions & 0 deletions Assets/ArtNet/Editor/UnityRecorder/ArtNet.UnityEditor.asmdef
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "ArtNet.UnityEditor",
"rootNamespace": "",
"references": [
"Unity.Recorder.Editor",
"ArtNet",
"ArtNet.Editor"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": false,
"defineConstraints": [
"USE_UNITY_RECORDER"
],
"versionDefines": [
{
"name": "com.unity.recorder",
"expression": "",
"define": "USE_UNITY_RECORDER"
}
],
"noEngineReferences": false
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

42 changes: 42 additions & 0 deletions Assets/ArtNet/Editor/UnityRecorder/ArtNetRecorder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System.Linq;
using ArtNet.Editor.DmxRecorder;
using ArtNet.Editor.UnityRecorder.Input;
using UnityEditor.Recorder;
using UnityEngine;

namespace ArtNet.Editor.UnityRecorder
{
public class ArtNetRecorder : GenericRecorder<ArtNetRecorderSettings>
{
protected override void RecordFrame(RecordingSession session)
{
}

protected override void EndRecording(RecordingSession session)
{
var settings = (ArtNetRecorderSettings) session.settings;

foreach (var input in m_Inputs)
{
var artNetInput = (ArtNetInput) input;
if (artNetInput.Recorder == null)
continue;

var frames = artNetInput.Recorder.Frames;
var groupedFrames = frames.GroupBy(f => f.Universe);
foreach (var group in groupedFrames)
{
Debug.Log($"Universe {group.Key}, Frames: {group.Count()}");
}

settings.FileNameGenerator.CreateDirectory(session);
var absolutePath = settings.FileNameGenerator.BuildAbsolutePath(session);

var binary = RecordData.SerializeUniverseData(frames);
System.IO.File.WriteAllBytes(absolutePath, binary);
}

base.EndRecording(session);
}
}
}
3 changes: 3 additions & 0 deletions Assets/ArtNet/Editor/UnityRecorder/ArtNetRecorder.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions Assets/ArtNet/Editor/UnityRecorder/ArtNetRecorderEditor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using UnityEditor;
using UnityEditor.Recorder;

namespace ArtNet.Editor.UnityRecorder
{
[CustomEditor(typeof(ArtNetRecorderSettings))]
public class ArtNetRecorderEditor : RecorderEditor
{
protected override void FileTypeAndFormatGUI()
{
EditorGUILayout.LabelField("Format", "ArtNet Binary");
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

58 changes: 58 additions & 0 deletions Assets/ArtNet/Editor/UnityRecorder/ArtNetRecorderSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using System.Collections.Generic;
using ArtNet.Editor.UnityRecorder.Input;
using UnityEditor.Recorder;
using UnityEngine;

namespace ArtNet.Editor.UnityRecorder
{
[RecorderSettings(typeof(ArtNetRecorder), "Art-Net")]
public class ArtNetRecorderSettings : RecorderSettings
{
[SerializeField] private ArtNetInputSettings _artNetInputSettings = new();

protected override string Extension => "dmx";

public ArtNetInputSettings ArtNetInputSettings => _artNetInputSettings;
public override IEnumerable<RecorderInputSettings> InputsSettings
{
get { yield return _artNetInputSettings; }
}

public ArtNetRecorderSettings()
{
FileNameGenerator.AddWildcard(DefaultWildcard.GeneratePattern("GameObject"), GameObjectNameResolver);
FileNameGenerator.AddWildcard(DefaultWildcard.GeneratePattern("GameObjectScene"), GameObjectSceneNameResolver);

FileNameGenerator.ForceAssetsFolder = false;
FileNameGenerator.Root = OutputPath.Root.AssetsFolder;
FileNameGenerator.FileName = "artnet_dmx_" + DefaultWildcard.Take;
}

private string GameObjectNameResolver(RecordingSession session)
{
var dmxManager = ArtNetInputSettings.DmxManager;
return dmxManager != null ? dmxManager.gameObject.name : "None";
}

private string GameObjectSceneNameResolver(RecordingSession session)
{
var dmxManager = ArtNetInputSettings.DmxManager;
return dmxManager != null ? dmxManager.gameObject.scene.name : "None";
}

protected override void GetErrors(List<string> errors)
{
base.GetErrors(errors);

if (ArtNetInputSettings.GameObject == null)
errors.Add("No assigned game object to record");
else if (ArtNetInputSettings.DmxManager == null)
errors.Add($"No DmxManager component found on {ArtNetInputSettings.GameObject.name}");
}

public override void OnAfterDuplicate()
{
ArtNetInputSettings.DuplicateExposedReference();
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Assets/ArtNet/Editor/UnityRecorder/Input.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

50 changes: 50 additions & 0 deletions Assets/ArtNet/Editor/UnityRecorder/Input/ArtNetInput.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System.Collections.Generic;
using ArtNet.Editor.DmxRecorder;
using UnityEditor.Recorder;
using UnityEngine;

namespace ArtNet.Editor.UnityRecorder.Input
{
public class ArtNetInput : RecorderInput
{
internal class DmxRecorder
{
private readonly DmxManager _dmxManager;
internal List<UniverseData> Frames { get; } = new();

public DmxRecorder(DmxManager dmxManager)
{
_dmxManager = dmxManager;
}

public void RecordFrame(double time)
{
var universes = _dmxManager.Universes();
foreach (var universe in universes)
{
var values = _dmxManager.DmxValues(universe);
Frames.Add(new UniverseData(time, universe, values));
}
}
}

internal DmxRecorder Recorder;
private double _startTime;

protected override void BeginRecording(RecordingSession session)
{
var artNetSettings = (ArtNetInputSettings) settings;
var dmxManager = artNetSettings.DmxManager;
if (dmxManager == null) return;

Recorder = new DmxRecorder(dmxManager);
_startTime = Time.time;
}


protected override void NewFrameReady(RecordingSession session)
{
Recorder?.RecordFrame(Time.time - _startTime);
}
}
}
3 changes: 3 additions & 0 deletions Assets/ArtNet/Editor/UnityRecorder/Input/ArtNetInput.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

59 changes: 59 additions & 0 deletions Assets/ArtNet/Editor/UnityRecorder/Input/ArtNetInputSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using System;
using System.ComponentModel;
using UnityEditor;
using UnityEditor.Recorder;
using UnityEngine;

namespace ArtNet.Editor.UnityRecorder.Input
{
[DisplayName("ArtNet")]
[Serializable]
public class ArtNetInputSettings : RecorderInputSettings
{
protected override Type InputType => typeof(ArtNetInput);

[SerializeField] private string _bindingID;

public GameObject GameObject
{
get
{
if (string.IsNullOrEmpty(_bindingID)) return null;

return BindingManager.Get(_bindingID) as GameObject;
}
set
{
if (string.IsNullOrEmpty(_bindingID))
_bindingID = GenerateBindingId();

BindingManager.Set(_bindingID, value);
}
}

public DmxManager DmxManager
{
get
{
var gameObject = GameObject;
return gameObject?.GetComponent<DmxManager>();
}
}

public void DuplicateExposedReference()
{
if (string.IsNullOrEmpty(_bindingID)) return;

var src = _bindingID;
var dst = GenerateBindingId();
_bindingID = dst;

BindingManager.Duplicate(src, dst);
}

private static string GenerateBindingId()
{
return GUID.Generate().ToString();
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading