diff --git a/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/DataFormats/AniMiku/AnimatedTexture/AMTDataFormat.cs b/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/DataFormats/AniMiku/AnimatedTexture/AMTDataFormat.cs new file mode 100644 index 00000000..15b1153e --- /dev/null +++ b/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/DataFormats/AniMiku/AnimatedTexture/AMTDataFormat.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Text; + +using UniversalEditor.ObjectModels.FileSystem; + +namespace UniversalEditor.DataFormats.AniMiku.AnimatedTexture +{ + public class AMTDataFormat : DataFormat + { + private static DataFormatReference _dfr = null; + public override DataFormatReference MakeReference() + { + if (_dfr == null) + { + _dfr = base.MakeReference(); + _dfr.Capabilities.Add(typeof(FileSystemObjectModel), DataFormatCapabilities.All); + _dfr.Filters.Add("AniMiku texture package", new string[] { "*.amt" }); + } + return _dfr; + } + protected override void LoadInternal(ref ObjectModel objectModel) + { + FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel); + if (fsom == null) return; + + IO.BinaryReader br = base.Stream.BinaryReader; + int unknown = br.ReadInt32(); + int count = br.ReadInt32(); + for (int i = 0; i < count; i++) + { + int dataSize = br.ReadInt32(); + byte[] data = br.ReadBytes(dataSize); + fsom.Files.Add(i.ToString().PadLeft(8, '0'), data); + } + } + protected override void SaveInternal(ObjectModel objectModel) + { + FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel); + if (fsom == null) return; + + IO.BinaryWriter bw = base.Stream.BinaryWriter; + int unknown = 150; + bw.Write(unknown); + + bw.Write(fsom.Files.Count); + foreach (File file in fsom.Files) + { + byte[] data = file.GetDataAsByteArray(); + bw.Write(data.Length); + bw.Write(data); + } + } + } +} diff --git a/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/DataFormats/AniMiku/Concert/AniMikuINIDataFormat.cs b/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/DataFormats/AniMiku/Concert/AniMikuINIDataFormat.cs new file mode 100644 index 00000000..fac5e8f7 --- /dev/null +++ b/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/DataFormats/AniMiku/Concert/AniMikuINIDataFormat.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using UniversalEditor; +using UniversalEditor.DataFormats.PropertyList.Microsoft; + +using UniversalEditor.ObjectModels.PropertyList; + +using UniversalEditor.ObjectModels.Concertroid; +using UniversalEditor.ObjectModels.Concertroid.Concert; + +namespace UniversalEditor.DataFormats.AniMiku.Concert +{ + public class AniMikuINIDataFormat : WindowsConfigurationDataFormat + { + public override DataFormatReference MakeReference() + { + DataFormatReference dfr = base.MakeReference(); + dfr.Clear(); + dfr.Capabilities.Add(typeof(ConcertObjectModel), DataFormatCapabilities.All); + dfr.Filters.Add("AniMiku performance", new byte?[][] { new byte?[] { (byte)'A', (byte)'M', (byte)'P', (byte)'V', (byte)'2', (byte)'\r', (byte)'\n' } }, new string[] { "*.amp" }); + return dfr; + } + + protected override void BeforeLoadInternal(Stack objectModels) + { + base.BeforeLoadInternal(objectModels); + + objectModels.Push(new PropertyListObjectModel()); + + string magic = base.Stream.TextReader.ReadLine(); + if (magic != "AMPV2") throw new DataFormatException(UniversalEditor.Localization.StringTable.ErrorDataFormatInvalid); + } + protected override void AfterLoadInternal(Stack objectModels) + { + base.AfterLoadInternal(objectModels); + + PropertyListObjectModel plom = (objectModels.Pop() as PropertyListObjectModel); + ConcertObjectModel concert = (objectModels.Pop() as ConcertObjectModel); + + Group grpPERF = plom.Groups["PERF"]; + if (grpPERF == null) throw new DataFormatException(UniversalEditor.Localization.StringTable.ErrorDataFormatInvalid); + + Property prpPERFnum = grpPERF.Properties["num"]; + if (prpPERFnum == null) throw new DataFormatException(UniversalEditor.Localization.StringTable.ErrorDataFormatInvalid); + + int perfNum = Int32.Parse(prpPERFnum.Value.ToString()); + + for (int i = 0; i < perfNum; i++) + { + Group grp = plom.Groups["CHP-" + i.ToString()]; + + Performance perf = new Performance(); + + Property prpName = grp.Properties["name"]; + perf.Title = prpName.Value.ToString(); + + Property prpVmd1 = grp.Properties["vmd1"]; + Property prpVmd2 = grp.Properties["vmd2"]; + + Property prpSound = grp.Properties["sound"]; + Property prpDelay = grp.Properties["delay"]; + + Property prpModel1 = grp.Properties["model1"]; + Property prpModel2 = grp.Properties["model2"]; + Property prpOffset1 = grp.Properties["offset1"]; + Property prpOffset2 = grp.Properties["offset2"]; + + #region Performer 1 + { + Performer performer = new Performer(); + performer.Character = new Character(); + performer.Character.FullName = System.IO.Path.GetFileNameWithoutExtension(prpModel1.Value.ToString()); + + performer.Costume = new Costume(); + performer.Costume.Title = System.IO.Path.GetFileNameWithoutExtension(prpModel1.Value.ToString()); + performer.Costume.ModelFileName = prpModel1.Value.ToString(); + + performer.Animation = new Animation(); + performer.Animation.FileName = prpVmd1.Value.ToString(); + performer.Offset = new PositionVector3((double)prpOffset1.Value, 0, 0); + perf.Performers.Add(performer); + } + #endregion + #region Performer 2 + { + Performer performer = new Performer(); + performer.Character = new Character(); + performer.Character.FullName = System.IO.Path.GetFileNameWithoutExtension(prpModel2.Value.ToString()); + + performer.Costume = new Costume(); + performer.Costume.Title = System.IO.Path.GetFileNameWithoutExtension(prpModel2.Value.ToString()); + performer.Costume.ModelFileName = prpModel2.Value.ToString(); + + performer.Animation = new Animation(); + performer.Animation.FileName = prpVmd2.Value.ToString(); + performer.Offset = new PositionVector3((double)prpOffset2.Value, 0, 0); + perf.Performers.Add(performer); + } + #endregion + #region Song + Song song = new Song(); + song.AudioFileName = prpSound.Value.ToString(); + song.Delay = (int)prpDelay.Value; + song.Title = System.IO.Path.GetFileNameWithoutExtension(song.AudioFileName); + perf.Song = song; + #endregion + + concert.Performances.Add(perf); + } + } + } +} + diff --git a/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/DataFormats/AniMiku/ExtendedPMD/ExtendedPMDDataFormat.cs b/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/DataFormats/AniMiku/ExtendedPMD/ExtendedPMDDataFormat.cs new file mode 100644 index 00000000..0b251e94 --- /dev/null +++ b/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/DataFormats/AniMiku/ExtendedPMD/ExtendedPMDDataFormat.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using UniversalEditor.Accessors.Stream; + +using UniversalEditor.ObjectModels.AniMiku.PMDExtension; +using UniversalEditor.DataFormats.AniMiku.PMDExtension; + +using UniversalEditor.DataFormats.Multimedia3D.Model.PolygonMovieMaker; +using UniversalEditor.ObjectModels.Multimedia3D.Model; + +namespace UniversalEditor.DataFormats.AniMiku.ExtendedPMD +{ + public class ExtendedPMDDataFormat : PMDModelDataFormat + { + private static DataFormatReference _dfr = null; + public override DataFormatReference MakeReference() + { + if (_dfr == null) + { + _dfr = base.MakeReference(); + _dfr.Clear(); + _dfr.Capabilities.Add(typeof(ModelObjectModel), DataFormatCapabilities.All); + _dfr.Filters.Add("AniMiku extended Polygon Movie Maker model", new string[] { "*.apmd" }); + _dfr.Priority = 1; + } + return _dfr; + } + protected override void AfterLoadInternal(Stack objectModels) + { + base.AfterLoadInternal(objectModels); + + ModelObjectModel model = (objectModels.Pop() as ModelObjectModel); + + // attempt to load more + IO.BinaryReader br = base.Stream.BinaryReader; + if (br.EndOfStream) return; + byte[] datas = br.ReadUntil("END", false); + + PMDExtensionObjectModel pmdo = new PMDExtensionObjectModel(); + PMDExtensionDataFormat pmdf = new PMDExtensionDataFormat(); + StreamAccessor accessor = new StreamAccessor(pmdo, pmdf); + + pmdf.Model = model; + + System.IO.MemoryStream ms = new System.IO.MemoryStream(datas); + accessor.Open(ms); + accessor.Load(); + accessor.Close(); + + foreach (PMDExtensionTextureGroup file in pmdo.ArchiveFiles) + { + foreach (string fileName in file.TextureImageFileNames) + { + file.Material.Textures.Add(file.ArchiveFileName + "::/" + fileName, null, ModelTextureFlags.Texture); + } + } + } + } +} diff --git a/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/DataFormats/AniMiku/PMDExtension/PMDExtensionDataFormat.cs b/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/DataFormats/AniMiku/PMDExtension/PMDExtensionDataFormat.cs new file mode 100644 index 00000000..7a8f7644 --- /dev/null +++ b/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/DataFormats/AniMiku/PMDExtension/PMDExtensionDataFormat.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using UniversalEditor.ObjectModels.AniMiku.PMDExtension; +using UniversalEditor.ObjectModels.Multimedia3D.Model; + +namespace UniversalEditor.DataFormats.AniMiku.PMDExtension +{ + internal class PMDExtensionDataFormat : DataFormat + { + private static DataFormatReference _dfr = null; + public override DataFormatReference MakeReference() + { + if (_dfr == null) + { + _dfr = base.MakeReference(); + _dfr.Capabilities.Add(typeof(PMDExtensionObjectModel), DataFormatCapabilities.All); + // _dfr.Filters.Add("AniMiku PMD extension"); + } + return _dfr; + } + protected override void LoadInternal(ref ObjectModel objectModel) + { + PMDExtensionObjectModel pmdo = (objectModel as PMDExtensionObjectModel); + if (pmdo == null) return; + + IO.BinaryReader br = base.Stream.BinaryReader; + foreach (ModelMaterial mat in mvarModel.Materials) + { + mat.AlwaysLight = br.ReadBoolean(); + mat.EnableAnimation = br.ReadBoolean(); + mat.EnableGlow = br.ReadBoolean(); + + if (mat.EnableAnimation) + { + int textureCount = br.ReadInt32(); + string archiveFileName = br.ReadNullTerminatedString(100); + + PMDExtensionTextureGroup file = new PMDExtensionTextureGroup(); + file.Material = mat; + file.ArchiveFileName = archiveFileName; + for (int i = 0; i < textureCount; i++) + { + string textureFileName = br.ReadNullTerminatedString(256); + file.TextureImageFileNames.Add(textureFileName); + } + pmdo.ArchiveFiles.Add(file); + } + } + + int originalModelLength = br.ReadInt32(); + string END = br.ReadFixedLengthString(3); + } + protected override void SaveInternal(ObjectModel objectModel) + { +#if READYTOSAVE + IO.BinaryWriter bw = base.Stream.BinaryWriter; + foreach (ModelMaterial mat in mvarModel.Materials) + { + bw.Write(mat.AlwaysLight); + bw.Write(mat.EnableAnimation); + bw.Write(mat.EnableGlow); + + if (mat.EnableAnimation) + { + // TODO: figure out how to get texture count for the model + int textureCount = br.ReadInt32(); + string archiveFileName = br.ReadNullTerminatedString(100); + + PMDExtensionTextureGroup file = new PMDExtensionTextureGroup(); + file.Material = mat; + file.ArchiveFileName = archiveFileName; + for (int i = 0; i < textureCount; i++) + { + string textureFileName = br.ReadNullTerminatedString(256); + file.TextureImageFileNames.Add(textureFileName); + } + pmdo.ArchiveFiles.Add(file); + } + } + + int originalModelLength = br.ReadInt32(); + string END = br.ReadFixedLengthString(3); +#endif + throw new NotImplementedException(); + } + + private ModelObjectModel mvarModel = null; + public ModelObjectModel Model { get { return mvarModel; } set { mvarModel = value; } } + } +} diff --git a/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/DataFormats/Multimedia3D/Motion/AniMiku/AniMikuMotionDataFormat.cs b/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/DataFormats/Multimedia3D/Motion/AniMiku/AniMikuMotionDataFormat.cs new file mode 100644 index 00000000..9162d256 --- /dev/null +++ b/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/DataFormats/Multimedia3D/Motion/AniMiku/AniMikuMotionDataFormat.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UniversalEditor.ObjectModels.Multimedia3D.Motion; + +namespace UniversalEditor.DataFormats.Multimedia3D.Motion.AniMiku +{ + public class AniMikuMotionDataFormat : DataFormat + { + private static DataFormatReference _dfr = null; + public override DataFormatReference MakeReference() + { + if (_dfr == null) + { + _dfr = base.MakeReference(); + _dfr.Capabilities.Add(typeof(MotionObjectModel), DataFormatCapabilities.All); + _dfr.Filters.Add("AniMiku motion data", new byte?[][] { new byte?[] { (byte)'a', (byte)'m', (byte)'d' } }, new string[] { "*.amd" }); + } + return _dfr; + } + + protected override void LoadInternal(ref ObjectModel objectModel) + { + IO.BinaryReader br = new IO.BinaryReader(base.Stream.BaseStream, System.Text.Encoding.UTF8); + br.BaseStream.Position = 0; + + MotionObjectModel motion = (objectModel as MotionObjectModel); + string amd = br.ReadFixedLengthString(3); + if (amd != "amd") throw new InvalidDataFormatException("File does not begin with \"amd\""); + + float version = br.ReadSingle(); + if (version != 1.0) Console.WriteLine("AniMiku: do not know how to parse version " + version.ToString()); + + uint boneCount = br.ReadUInt32(); + for (uint i = 0; i < boneCount; i++) + { + string boneName = br.ReadString(); + uint frameCount = br.ReadUInt32(); + + for (uint j = 0; j < frameCount; j++) + { + uint frameIndex = br.ReadUInt32(); + + MotionFrame frame = new MotionFrame(); + frame.Index = frameIndex; + + float px = br.ReadSingle(); + float py = br.ReadSingle(); + float pz = br.ReadSingle(); + + float rx = br.ReadSingle(); + float ry = br.ReadSingle(); + float rz = br.ReadSingle(); + float rw = br.ReadSingle(); + + byte[] interpolationData = br.ReadBytes(64); + + MotionBoneRepositionAction repos = new MotionBoneRepositionAction(); + repos.BoneName = boneName; + repos.Position = new PositionVector3(px, py, pz); + repos.Rotation = new PositionVector4(rx, ry, rz, rw); + + frame.Actions.Add(repos); + motion.Frames.Add(frame); + } + } + } + + protected override void SaveInternal(ObjectModel objectModel) + { + throw new NotImplementedException(); + } + } +} diff --git a/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/ObjectModels/AniMiku/PMDExtension/PMDExtensionArchiveFile.cs b/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/ObjectModels/AniMiku/PMDExtension/PMDExtensionArchiveFile.cs new file mode 100644 index 00000000..f1f85ae8 --- /dev/null +++ b/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/ObjectModels/AniMiku/PMDExtension/PMDExtensionArchiveFile.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace UniversalEditor.ObjectModels.AniMiku.PMDExtension +{ + public class PMDExtensionArchiveFile : ICloneable + { + public class PMDExtensionArchiveFileCollection + : System.Collections.ObjectModel.Collection + { + } + + private string mvarName = String.Empty; + public string Name { get { return mvarName; } set { mvarName = value; } } + + private System.Collections.Specialized.StringCollection mvarTextureImageFileNames = new System.Collections.Specialized.StringCollection(); + public System.Collections.Specialized.StringCollection TextureImageFileNames { get { return mvarTextureImageFileNames; } } + + public object Clone() + { + PMDExtensionArchiveFile clone = new PMDExtensionArchiveFile(); + clone.Name = (mvarName.Clone() as string); + foreach (string s in mvarTextureImageFileNames) + { + clone.TextureImageFileNames.Add(s.Clone() as string); + } + return clone; + } + } +} diff --git a/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/ObjectModels/AniMiku/PMDExtension/PMDExtensionObjectModel.cs b/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/ObjectModels/AniMiku/PMDExtension/PMDExtensionObjectModel.cs new file mode 100644 index 00000000..6f5c6f32 --- /dev/null +++ b/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/ObjectModels/AniMiku/PMDExtension/PMDExtensionObjectModel.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace UniversalEditor.ObjectModels.AniMiku.PMDExtension +{ + internal class PMDExtensionObjectModel : ObjectModel + { + private static ObjectModelReference _omr = null; + public override ObjectModelReference MakeReference() + { + if (_omr == null) + { + _omr = base.MakeReference(); + _omr.Title = "AniMiku PMD model extension"; + } + return _omr; + } + public override void Clear() + { + mvarArchiveFiles.Clear(); + } + public override void CopyTo(ObjectModel where) + { + PMDExtensionObjectModel clone = (where as PMDExtensionObjectModel); + if (clone == null) return; + + foreach (PMDExtensionTextureGroup file in mvarArchiveFiles) + { + clone.ArchiveFiles.Add(file.Clone() as PMDExtensionTextureGroup); + } + } + + private PMDExtensionTextureGroup.PMDExtensionArchiveFileCollection mvarArchiveFiles = new PMDExtensionTextureGroup.PMDExtensionArchiveFileCollection(); + public PMDExtensionTextureGroup.PMDExtensionArchiveFileCollection ArchiveFiles + { + get { return mvarArchiveFiles; } + } + } +} diff --git a/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/ObjectModels/AniMiku/PMDExtension/PMDExtensionTextureGroup.cs b/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/ObjectModels/AniMiku/PMDExtension/PMDExtensionTextureGroup.cs new file mode 100644 index 00000000..17abd9fa --- /dev/null +++ b/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/ObjectModels/AniMiku/PMDExtension/PMDExtensionTextureGroup.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using UniversalEditor.ObjectModels.Multimedia3D.Model; + +namespace UniversalEditor.ObjectModels.AniMiku.PMDExtension +{ + public class PMDExtensionTextureGroup : ICloneable + { + public class PMDExtensionArchiveFileCollection + : System.Collections.ObjectModel.Collection + { + } + + private string mvarName = String.Empty; + public string ArchiveFileName { get { return mvarName; } set { mvarName = value; } } + + private System.Collections.Specialized.StringCollection mvarTextureImageFileNames = new System.Collections.Specialized.StringCollection(); + public System.Collections.Specialized.StringCollection TextureImageFileNames { get { return mvarTextureImageFileNames; } } + + public object Clone() + { + PMDExtensionTextureGroup clone = new PMDExtensionTextureGroup(); + clone.ArchiveFileName = (mvarName.Clone() as string); + foreach (string s in mvarTextureImageFileNames) + { + clone.TextureImageFileNames.Add(s.Clone() as string); + } + return clone; + } + + private ModelMaterial mvarMaterial = null; + public ModelMaterial Material { get { return mvarMaterial; } set { mvarMaterial = value; } } + } +} diff --git a/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/Properties/AssemblyInfo.cs b/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..8d757722 --- /dev/null +++ b/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("AniMiku plugin for Universal Editor")] +[assembly: AssemblyDescription("Provides data formats and object models to load AniMiku extended PMD model files.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Mike Becker's Software")] +[assembly: AssemblyProduct("Universal Editor Plugin Pack")] +[assembly: AssemblyCopyright("Copyright ©2012 Mike Becker's Software")] +[assembly: AssemblyTrademark("AniMiku is a trademark of Re:VB-P.")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("fe57a2f7-9093-45a5-acd5-1dbdbbe8a412")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/UniversalEditor.Plugins.AniMiku.csproj b/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/UniversalEditor.Plugins.AniMiku.csproj new file mode 100644 index 00000000..64753be7 --- /dev/null +++ b/CSharp/Plugins/UniversalEditor.Plugins.AniMiku/UniversalEditor.Plugins.AniMiku.csproj @@ -0,0 +1,77 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {FEC4EAD0-8A6E-4029-A537-EBD9F420B227} + Library + Properties + UniversalEditor + UniversalEditor.Plugins.AniMiku + v3.5 + 512 + + + true + full + false + ..\..\Output\Debug\Plugins\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\Output\Release\Plugins\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + {AF46D67F-5172-40E9-A0E5-7A25BDF874FD} + Neo + + + {a92d520b-ffa3-4464-8cf6-474d18959e03} + UniversalEditor.Core + + + {d3bbda07-5088-454e-a16d-da24d8d88037} + UniversalEditor.Plugins.Concertroid + + + {4FD9DB1D-76AA-48D1-8446-95376C4A2BC2} + UniversalEditor.Plugins.Multimedia3D + + + {BE4D0BA3-0888-42A5-9C09-FC308A4509D2} + UniversalEditor.Plugins.Multimedia + + + + + \ No newline at end of file