add McxMini parser and library functionality (incomplete)

This commit is contained in:
Michael Becker 2024-08-25 09:46:18 -04:00
parent 4d11d9f155
commit f15d81d63a
15 changed files with 531 additions and 20 deletions

@ -1 +1 @@
Subproject commit 9919125a5130e5a5a9412dbed5520e5286703a43 Subproject commit 8c138247e0ca8104f7cbecbdb54ccd7760d331c3

View File

@ -39,7 +39,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mocha.Core.Tests", "mocha-d
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "plugins", "plugins", "{B024FD23-7084-4DDF-A185-D58BEE7A006F}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "plugins", "plugins", "{B024FD23-7084-4DDF-A185-D58BEE7A006F}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mocha.Plugins.Libraries.Yaml", "mocha-dotnet\src\plugins\Mocha.Plugins.Libraries.Yaml\Mocha.Plugins.Libraries.Yaml.csproj", "{96400F5A-98ED-48FF-8000-6135BDF10360}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mocha.Plugins.Libraries.McxMini", "mocha-dotnet\src\plugins\Mocha.Plugins.Libraries.McxMini\Mocha.Plugins.Libraries.McxMini.csproj", "{6005DB73-30D8-4398-8B1F-5E23C0F2FFBF}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -67,10 +67,10 @@ Global
{20B7D199-322C-4942-85FE-46B90C75E92A}.Debug|Any CPU.Build.0 = Debug|Any CPU {20B7D199-322C-4942-85FE-46B90C75E92A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{20B7D199-322C-4942-85FE-46B90C75E92A}.Release|Any CPU.ActiveCfg = Release|Any CPU {20B7D199-322C-4942-85FE-46B90C75E92A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{20B7D199-322C-4942-85FE-46B90C75E92A}.Release|Any CPU.Build.0 = Release|Any CPU {20B7D199-322C-4942-85FE-46B90C75E92A}.Release|Any CPU.Build.0 = Release|Any CPU
{96400F5A-98ED-48FF-8000-6135BDF10360}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6005DB73-30D8-4398-8B1F-5E23C0F2FFBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{96400F5A-98ED-48FF-8000-6135BDF10360}.Debug|Any CPU.Build.0 = Debug|Any CPU {6005DB73-30D8-4398-8B1F-5E23C0F2FFBF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{96400F5A-98ED-48FF-8000-6135BDF10360}.Release|Any CPU.ActiveCfg = Release|Any CPU {6005DB73-30D8-4398-8B1F-5E23C0F2FFBF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{96400F5A-98ED-48FF-8000-6135BDF10360}.Release|Any CPU.Build.0 = Release|Any CPU {6005DB73-30D8-4398-8B1F-5E23C0F2FFBF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -91,7 +91,7 @@ Global
{27C300F5-5172-4225-A6F7-3503B9007DD8} = {2A2B84F1-FA6B-4D67-ACB8-E277D50C98F2} {27C300F5-5172-4225-A6F7-3503B9007DD8} = {2A2B84F1-FA6B-4D67-ACB8-E277D50C98F2}
{20B7D199-322C-4942-85FE-46B90C75E92A} = {27C300F5-5172-4225-A6F7-3503B9007DD8} {20B7D199-322C-4942-85FE-46B90C75E92A} = {27C300F5-5172-4225-A6F7-3503B9007DD8}
{B024FD23-7084-4DDF-A185-D58BEE7A006F} = {66EB3261-A473-41C7-8D40-E1B4DC8ED4B3} {B024FD23-7084-4DDF-A185-D58BEE7A006F} = {66EB3261-A473-41C7-8D40-E1B4DC8ED4B3}
{96400F5A-98ED-48FF-8000-6135BDF10360} = {B024FD23-7084-4DDF-A185-D58BEE7A006F} {6005DB73-30D8-4398-8B1F-5E23C0F2FFBF} = {B024FD23-7084-4DDF-A185-D58BEE7A006F}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D28A9CF8-0235-4F8F-865F-C460BDCAE16D} SolutionGuid = {D28A9CF8-0235-4F8F-865F-C460BDCAE16D}

View File

@ -19,6 +19,7 @@ using System.Net;
using MBS.Core; using MBS.Core;
using MBS.Web; using MBS.Web;
using Mocha.Core; using Mocha.Core;
using Mocha.Core.OmsImplementations;
using Mocha.Core.OmsImplementations.Mini; using Mocha.Core.OmsImplementations.Mini;
using Mocha.Core.Oop; using Mocha.Core.Oop;
using Mocha.Core.Oop.Methods; using Mocha.Core.Oop.Methods;
@ -49,17 +50,23 @@ public class Program : MochaWebApplication
protected override Oms CreateOms() protected override Oms CreateOms()
{ {
// we can override this here to provide a different default OMS // we can override this here to provide a different default OMS
MiniOms oms = new MiniOms(); Oms oms = new MemoryOms(); // new MiniOms();
// oms.Libraries.Add("/path/to/Mocha.System.mcl");
string PJPATH = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);
PJPATH += "/../../../../../../../";
// "/home/beckermj/Documents/Projects/mochapowered/mocha-dotnet";
LibraryHandle l_System = oms.LoadLibrary(PJPATH + "mocha-common/mocha-common/output/net.alcetech.Mocha.System.mcl");
oms.TenantCreated += oms_TenantCreated; oms.TenantCreated += oms_TenantCreated;
oms.Initialize(); oms.Initialize();
TenantHandle t_super = oms.GetTenantByName("super"); TenantHandle t_super = oms.CreateTenant("super");
{ {
// FIXME! : selecting tenant doesn't seem to be working, routes get overwritten / not created // FIXME! : selecting tenant doesn't seem to be working, routes get overwritten / not created
oms.SelectTenant(t_super); oms.SelectTenant(t_super);
oms.AddLibraryReference(l_System);
InstanceHandle c_Application = oms.GetInstance(KnownInstanceGuids.Classes.Application); InstanceHandle c_Application = oms.GetInstance(KnownInstanceGuids.Classes.Application);
InstanceHandle i_Application = oms.CreateInstanceOf(c_Application, new Guid("{773f6c6e-6cef-4a04-b333-ac097c0ab705}")); InstanceHandle i_Application = oms.CreateInstanceOf(c_Application, new Guid("{773f6c6e-6cef-4a04-b333-ac097c0ab705}"));

View File

@ -10,4 +10,8 @@ public class Library
public void Link() public void Link()
{ {
} }
public LibraryInstance.LibraryInstanceCollection Instances { get; } = new LibraryInstance.LibraryInstanceCollection();
public List<LibraryAttribute> Attributes { get; } = new List<LibraryAttribute>();
public List<LibraryRelationship> Relationships { get; } = new List<LibraryRelationship>();
} }

View File

@ -0,0 +1,22 @@
using System;
namespace Mocha.Core;
public class LibraryAttribute
{
public Guid SourceInstanceGuid { get; }
public Guid AttributeInstanceGuid { get; }
public string Value { get; }
public LibraryAttribute(Guid sourceInstanceGuid, Guid attributeInstanceGuid, string value)
{
SourceInstanceGuid = sourceInstanceGuid;
AttributeInstanceGuid = attributeInstanceGuid;
Value = value;
}
public override string ToString()
{
return String.Format("A: {0} . {1} = '{2}'", SourceInstanceGuid.ToString("b"), AttributeInstanceGuid.ToString("b"), Value);
}
}

View File

@ -0,0 +1,80 @@
/**
* Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
*
* This file is part of Mocha.NET.
*
* Mocha.NET is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Mocha.NET is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Mocha.NET. If not, see <https://www.gnu.org/licenses/>.
*/
namespace Mocha.Core;
public class LibraryInstance
{
public class LibraryInstanceCollection : System.Collections.ObjectModel.Collection<LibraryInstance>
{
private Dictionary<Guid, LibraryInstance> _itemsByGuid = new Dictionary<Guid, LibraryInstance>();
private Dictionary<InstanceKey, LibraryInstance> _itemsByKey = new Dictionary<InstanceKey, LibraryInstance>();
protected override void ClearItems()
{
base.ClearItems();
_itemsByGuid.Clear();
}
protected override void InsertItem(int index, LibraryInstance item)
{
base.InsertItem(index, item);
_itemsByGuid[item.InstanceGuid] = item;
}
protected override void RemoveItem(int index)
{
_itemsByGuid.Remove(this[index].InstanceGuid);
base.RemoveItem(index);
}
public bool Contains(Guid globalIdentifier)
{
return _itemsByGuid.ContainsKey(globalIdentifier);
}
public LibraryInstance this[Guid globalIdentifier]
{
get
{
if (_itemsByGuid.ContainsKey(globalIdentifier))
{
return _itemsByGuid[globalIdentifier];
}
return null;
}
}
}
public InstanceKey InstanceKey { get; set; }
public Guid InstanceGuid { get; set; }
public Guid ClassGuid { get; set; }
public LibraryInstance(InstanceKey key, Guid instanceGuid, Guid classGuid)
{
this.InstanceKey = key;
this.InstanceGuid = instanceGuid;
this.ClassGuid = classGuid;
}
public override string ToString()
{
return String.Format("I: {0} : {1} [{2}]", this.InstanceGuid.ToString("b"), this.ClassGuid.ToString("b"), this.InstanceKey.ToString());
}
}

View File

@ -0,0 +1,21 @@
using System;
namespace Mocha.Core;
public class LibraryRelationship
{
public Guid SourceInstanceGuid { get; set; }
public Guid RelationshipInstanceGuid { get; set; }
public Guid TargetInstanceGuid { get; set; }
public LibraryRelationship(Guid sourceInstanceGuid, Guid relationshipInstanceGuid, Guid targetInstanceGuid)
{
this.SourceInstanceGuid = sourceInstanceGuid;
this.RelationshipInstanceGuid = relationshipInstanceGuid;
this.TargetInstanceGuid = targetInstanceGuid;
}
public override string ToString()
{
return String.Format("R: {0} . {1} = {2}", SourceInstanceGuid.ToString("b"), RelationshipInstanceGuid.ToString("b"), TargetInstanceGuid.ToString("b"));
}
}

View File

@ -356,7 +356,7 @@ public abstract class Oms
public bool TryGetAttributeValue<T>(InstanceHandle source, InstanceHandle attribute, DateTime? effectiveDate, out T value) public bool TryGetAttributeValue<T>(InstanceHandle source, InstanceHandle attribute, DateTime? effectiveDate, out T value)
{ {
DateTime dt = DateTime.Now; DateTime dt = DateTime.Now;
if (HasAttributeValueInternal(source, attribute, effectiveDate.GetValueOrDefault(dt))) // if (HasAttributeValueInternal(source, attribute, effectiveDate.GetValueOrDefault(dt)))
{ {
object? val = GetAttributeValueInternal(source, attribute, effectiveDate.GetValueOrDefault(dt)); object? val = GetAttributeValueInternal(source, attribute, effectiveDate.GetValueOrDefault(dt));
if (val is T) if (val is T)
@ -400,7 +400,7 @@ public abstract class Oms
{ {
string name = GetAttributeValue<string>(attribute, GetInstance(KnownAttributeGuids.Text.Name)); string name = GetAttributeValue<string>(attribute, GetInstance(KnownAttributeGuids.Text.Name));
string sourceParentClassName = GetAttributeValue<string>(sourceParentClass, GetInstance(KnownAttributeGuids.Text.Name)); string sourceParentClassName = GetAttributeValue<string>(sourceParentClass, GetInstance(KnownAttributeGuids.Text.Name));
throw new ArgumentException(String.Format("Undefined attribute `{0}` on class `{1}`", name ?? GetGlobalIdentifier(attribute).ToString("b"), sourceParentClassName)); throw new ArgumentException(String.Format("Undefined attribute `{0}` on class `{1}`", name ?? GetGlobalIdentifier(attribute).ToString("b"), sourceParentClassName ?? GetGlobalIdentifier(sourceParentClass).ToString("b")));
} }
if (IsInstanceOf(attribute, a_TextAttribute)) if (IsInstanceOf(attribute, a_TextAttribute))
@ -1074,7 +1074,6 @@ public abstract class Oms
// /path/to/directory containing a bunch of XML / JSON / YAML files // /path/to/directory containing a bunch of XML / JSON / YAML files
// .mcz ZIP archive of XML / JSON / YAML files (slowest?) // .mcz ZIP archive of XML / JSON / YAML files (slowest?)
LibraryHandle lh = LibraryHandle.Create(); LibraryHandle lh = LibraryHandle.Create();
return lh;
Library lib = new Library(); Library lib = new Library();
// _libraries[name] = lh; // _libraries[name] = lh;
@ -1111,9 +1110,13 @@ public abstract class Oms
// to do its second pass "linking" the objects // to do its second pass "linking" the objects
lib.Link(); lib.Link();
InitializeLibraryInternal(lh, lib);
return lh; return lh;
} }
protected abstract void InitializeLibraryInternal(LibraryHandle lh, Library lib);
public string? GetTenantName(TenantHandle tenant) public string? GetTenantName(TenantHandle tenant)
{ {
if (_namesForTenant.ContainsKey(tenant)) if (_namesForTenant.ContainsKey(tenant))

View File

@ -15,7 +15,8 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Mocha.NET. If not, see <https://www.gnu.org/licenses/>. // along with Mocha.NET. If not, see <https://www.gnu.org/licenses/>.

using System.ComponentModel;
using System.Data; using System.Data;
namespace Mocha.Core.OmsImplementations; namespace Mocha.Core.OmsImplementations;
@ -34,9 +35,13 @@ public class MemoryOms : Oms
private Dictionary<InstanceHandle, Dictionary<InstanceHandle, List<RelationshipValue>>> _Relationships = new Dictionary<InstanceHandle, Dictionary<InstanceHandle, List<RelationshipValue>>>(); private Dictionary<InstanceHandle, Dictionary<InstanceHandle, List<RelationshipValue>>> _Relationships = new Dictionary<InstanceHandle, Dictionary<InstanceHandle, List<RelationshipValue>>>();
public Guid GetGlobalIdentifier(InstanceHandle instance) public Guid GetGlobalIdentifier(InstanceHandle instance)
{
if (_guidsByInstance.ContainsKey(instance))
{ {
return _guidsByInstance[instance]; return _guidsByInstance[instance];
} }
return Guid.Empty;
}
public InstanceKey GetInstanceKey(InstanceHandle instance) public InstanceKey GetInstanceKey(InstanceHandle instance)
{ {
if (_keysByInstance.ContainsKey(instance)) if (_keysByInstance.ContainsKey(instance))
@ -195,6 +200,8 @@ public class MemoryOms : Oms
private Dictionary<TenantHandle, _Tenant> _tenantData = new Dictionary<TenantHandle, _Tenant>(); private Dictionary<TenantHandle, _Tenant> _tenantData = new Dictionary<TenantHandle, _Tenant>();
private _Tenant _CurrentTenantData = null; private _Tenant _CurrentTenantData = null;
private Dictionary<LibraryHandle, _Tenant> _libraries = new Dictionary<LibraryHandle, _Tenant>();
private TenantHandle _CurrentTenant = TenantHandle.Empty; private TenantHandle _CurrentTenant = TenantHandle.Empty;
protected override TenantHandle CreateTenantInternal(string tenantName) protected override TenantHandle CreateTenantInternal(string tenantName)
@ -234,7 +241,15 @@ public class MemoryOms : Oms
if (_CurrentTenantData == null) if (_CurrentTenantData == null)
throw new InvalidOperationException("Please select a tenant first."); throw new InvalidOperationException("Please select a tenant first.");
return _CurrentTenantData.GetGlobalIdentifier(instance); Guid gid = _CurrentTenantData.GetGlobalIdentifier(instance);
if (gid == Guid.Empty)
{
if (_libraryInst_is.ContainsKey(instance))
{
gid = _libraryInst_is[instance].GlobalIdentifier;
}
}
return gid;
} }
protected override InstanceKey GetInstanceKeyInternal(InstanceHandle instance) protected override InstanceKey GetInstanceKeyInternal(InstanceHandle instance)
{ {
@ -271,12 +286,73 @@ public class MemoryOms : Oms
return ik; return ik;
} }
protected override void InitializeLibraryInternal(LibraryHandle lh, Library data)
{
_Tenant lib = new _Tenant();
foreach (LibraryInstance inst in data.Instances)
{
lib.CreateInstance(inst.InstanceGuid);
}
foreach (LibraryAttribute att in data.Attributes)
{
if (lib.TryGetInstance(att.SourceInstanceGuid, out InstanceHandle src)
&& lib.TryGetInstance(att.AttributeInstanceGuid, out InstanceHandle dst))
{
lib.SetAttributeValue(src, dst, att.Value, DateTime.Now);
}
}
foreach (LibraryRelationship rel in data.Relationships)
{
if (lib.TryGetInstance(rel.SourceInstanceGuid, out InstanceHandle src)
&& lib.TryGetInstance(rel.RelationshipInstanceGuid, out InstanceHandle dst)
&& lib.TryGetInstance(rel.TargetInstanceGuid, out InstanceHandle tgt))
{
lib.AssignRelationship(src, dst, new InstanceHandle[] { tgt }, DateTime.Now);
}
}
_libraries[lh] = lib;
}
private struct LibraryInst_g
{
public LibraryHandle SourceLibrary;
public InstanceHandle InstanceHandle;
public Guid GlobalIdentifier;
}
private Dictionary<Guid, LibraryInst_g> _libraryInst_gs = new Dictionary<Guid, LibraryInst_g>();
private Dictionary<InstanceHandle, LibraryInst_g> _libraryInst_is = new Dictionary<InstanceHandle, LibraryInst_g>();
protected override bool TryGetInstanceInternal(Guid globalIdentifier, out InstanceHandle ih) protected override bool TryGetInstanceInternal(Guid globalIdentifier, out InstanceHandle ih)
{ {
if (_CurrentTenantData == null) if (_CurrentTenantData == null)
throw new InvalidOperationException("Please select a tenant first."); throw new InvalidOperationException("Please select a tenant first.");
return _CurrentTenantData.TryGetInstance(globalIdentifier, out ih); bool v = _CurrentTenantData.TryGetInstance(globalIdentifier, out ih);
if (!v)
{
if (_libraryInst_gs.ContainsKey(globalIdentifier))
{
ih = _libraryInst_gs[globalIdentifier].InstanceHandle;
return true;
}
else
{
foreach (LibraryHandle lh in _libraryReferences[_CurrentTenant])
{
if (_libraries.ContainsKey(lh))
{
if (_libraries[lh].TryGetInstance(globalIdentifier, out ih))
{
LibraryInst_g g = new LibraryInst_g() { InstanceHandle = ih, SourceLibrary = lh, GlobalIdentifier = globalIdentifier };
_libraryInst_gs[globalIdentifier] = g;
_libraryInst_is[ih] = g;
return true;
}
}
}
}
}
return false;
} }
protected override bool TryGetInstanceInternal(InstanceKey ik, out InstanceHandle ih) protected override bool TryGetInstanceInternal(InstanceKey ik, out InstanceHandle ih)
{ {
@ -323,7 +399,22 @@ public class MemoryOms : Oms
if (_CurrentTenantData == null) if (_CurrentTenantData == null)
throw new InvalidOperationException("Please select a tenant first."); throw new InvalidOperationException("Please select a tenant first.");
return _CurrentTenantData.GetRelatedInstances(source, relationship, effectiveDate); IReadOnlyCollection<InstanceHandle> insts = _CurrentTenantData.GetRelatedInstances(source, relationship, effectiveDate);
if (insts.Count == 0)
{
foreach (LibraryHandle lh in _libraryReferences[_CurrentTenant])
{
if (_libraries.ContainsKey(lh))
{
IReadOnlyCollection<InstanceHandle> insts2 = _libraries[lh].GetRelatedInstances(source, relationship, effectiveDate);
if (insts2.Count > 0)
{
return insts2;
}
}
}
}
return insts;
} }
protected override bool HasAttributeValueInternal(InstanceHandle source, InstanceHandle attribute, DateTime effectiveDate) protected override bool HasAttributeValueInternal(InstanceHandle source, InstanceHandle attribute, DateTime effectiveDate)
@ -338,7 +429,22 @@ public class MemoryOms : Oms
if (_CurrentTenantData == null) if (_CurrentTenantData == null)
throw new InvalidOperationException("Please select a tenant first."); throw new InvalidOperationException("Please select a tenant first.");
return _CurrentTenantData.GetAttributeValue(source, attribute, effectiveDate); object value = _CurrentTenantData.GetAttributeValue(source, attribute, effectiveDate);
if (value == null)
{
foreach (LibraryHandle lh in _libraryReferences[_CurrentTenant])
{
if (_libraries.ContainsKey(lh))
{
value = _libraries[lh].GetAttributeValue(source, attribute, effectiveDate);
if (value != null)
{
return value;
}
}
}
}
return value;
} }
protected override void SetAttributeValueInternal(InstanceHandle source, InstanceHandle attribute, object value, DateTime effectiveDate) protected override void SetAttributeValueInternal(InstanceHandle source, InstanceHandle attribute, object value, DateTime effectiveDate)
{ {

View File

@ -26,6 +26,11 @@ using MBS.Core;
/// </summary> /// </summary>
public class MiniOms : MemoryOms public class MiniOms : MemoryOms
{ {
private MiniOms()
{
}
private TenantHandle t_super; private TenantHandle t_super;
private InstanceHandle c_Class, c_Attribute, c_Relationship, c_TextAttribute, c_BooleanAttribute, c_NumericAttribute, c_DateAttribute, c_WorkSet, c_Instance, c_OMS, c_File; private InstanceHandle c_Class, c_Attribute, c_Relationship, c_TextAttribute, c_BooleanAttribute, c_NumericAttribute, c_DateAttribute, c_WorkSet, c_Instance, c_OMS, c_File;
private InstanceHandle c_CommonText, c_CommonBoolean, c_CommonNumeric, c_CommonDate, c_CommonInstanceSet; private InstanceHandle c_CommonText, c_CommonBoolean, c_CommonNumeric, c_CommonDate, c_CommonInstanceSet;
@ -37,7 +42,7 @@ public class MiniOms : MemoryOms
public List<MiniOmsModule> Modules { get; } = new List<MiniOmsModule>(); public List<MiniOmsModule> Modules { get; } = new List<MiniOmsModule>();
public MiniOms(MiniOmsModule[] modules = null) private MiniOms(MiniOmsModule[] modules = null)
{ {
if (modules == null) if (modules == null)
{ {

View File

@ -0,0 +1,55 @@
using System;
using MBS.Core;
namespace Mocha.Plugins.Libraries.McxMini;
public static class BinaryReaderExtensions
{
public static string ReadFixedString(this System.IO.BinaryReader reader, int length, System.Text.Encoding encoding = null)
{
if (encoding == null)
{
encoding = System.Text.Encoding.UTF8;
}
byte[] bytes = reader.ReadBytes(length);
return encoding.GetString(bytes);
}
public static Guid ReadGuid(this System.IO.BinaryReader reader)
{
byte[] bytes = reader.ReadBytes(16);
return new Guid(bytes);
}
public static string ReadNullTerminatedString(this System.IO.BinaryReader reader, System.Text.Encoding encoding = null)
{
if (encoding == null)
{
encoding = System.Text.Encoding.UTF8;
}
List<byte> bytes = new List<byte>();
while (true)
{
try
{
byte value = reader.ReadByte();
if (value == 0)
{
// FIXME: If we use Unicode (UTF-16), end of string is actually two zeroes (\0\0)
break;
}
bytes.Add(value);
}
catch (EndOfStreamException ex)
{
break;
}
catch (IOException ex)
{
break;
}
}
return encoding.GetString(bytes.ToArray());
}
}

View File

@ -0,0 +1,8 @@
using System;
namespace Mocha.Plugins.Libraries.McxMini.EditorMini;
public class InvalidDataFormatException : Exception
{
}

View File

@ -0,0 +1,13 @@
using System;
namespace Mocha.Plugins.Libraries.McxMini;
[Flags]
public enum McxMiniFlags
{
None = 0x00,
HasSections = 0x01,
HasNames = 0x02,
HasCounts = 0x04,
Debug = 0x08
}

View File

@ -0,0 +1,173 @@
namespace Mocha.Plugins.Libraries.McxMini;
using System.Runtime.InteropServices;
using MBS.Core;
using Mocha.Core;
using Mocha.Plugins.Libraries.McxMini.EditorMini;
public class McxMiniLibraryPlugin : LibraryPlugin
{
private struct McxInstance
{
public Guid ClassGuid;
public Guid InstanceGuid;
public int ClassIndex;
public int InstanceIndex;
}
private struct McxAttribute
{
public Guid SourceInstanceGuid;
public Guid AttributeInstanceGuid;
public int ValueIndex;
}
private struct McxSection
{
public string Name;
public int Offset;
public int Length;
public int Count;
}
protected override bool SupportsFileNameInternal(string filename)
{
string ext = System.IO.Path.GetExtension(filename);
return ext.Equals(".mcx") || ext.Equals(".mcl");
}
protected override void LoadInternal(string filename, Library library)
{
FileStream fs = File.Open(filename, FileMode.Open);
BinaryReader r = new BinaryReader(fs);
string signature = r.ReadFixedString(4);
if (!signature.Equals("MCX!"))
{
throw new InvalidDataFormatException();
}
float version = r.ReadSingle();
if (version != 2.0f)
{
Console.Error.WriteLine(String.Format("MCX format version {0} unsupported", version));
}
McxMiniFlags flags = (McxMiniFlags)r.ReadInt32();
int sectionsCount = r.ReadInt32();
Dictionary<string, McxSection> sections = new Dictionary<string, McxSection>();
for (int i = 0; i < sectionsCount; i++)
{
McxSection section = new McxSection();
if ((flags & McxMiniFlags.HasNames) == McxMiniFlags.HasNames)
{
section.Name = r.ReadFixedString(16).TrimNull();
}
else
{
section.Name = i.ToString();
}
section.Offset = r.ReadInt32();
section.Length = r.ReadInt32();
if ((flags & McxMiniFlags.HasCounts) == McxMiniFlags.HasCounts)
{
section.Count = r.ReadInt32();
}
if (((flags & McxMiniFlags.HasNames) == McxMiniFlags.HasNames)
&& ((flags & McxMiniFlags.HasCounts) == McxMiniFlags.HasCounts))
{
int reserved = r.ReadInt32(); // padding
}
sections[section.Name] = section;
}
if (sections.Count < 5)
{
throw new InvalidDataFormatException();
}
McxSection guidsSection = sections["GUIDTable"];
McxSection instancesSection = sections["Instances"];
McxSection attributesSection = sections["Attributes"];
McxSection relationshipsSection = sections["Relationships"];
McxSection stringTableSection = sections["StringTable"];
McxSection resourcesSection = new McxSection();
if (sections.ContainsKey("Resources"))
{
resourcesSection = sections["Resources"];
}
if (guidsSection.Count != instancesSection.Count)
{
Console.Error.WriteLine("guid count not equal to instance count?");
}
r.BaseStream.Seek(guidsSection.Offset, SeekOrigin.Begin);
List<Guid> guids = new List<Guid>();
for (int i = 0; i < guidsSection.Count; i++)
{
Guid guid = r.ReadGuid();
guids.Add(guid);
}
r.BaseStream.Seek(instancesSection.Offset, SeekOrigin.Begin);
// McxInstance[] instances = new McxInstance[instancesCount];
for (int i = 0; i < instancesSection.Count; i++)
{
int classGuidIndex = r.ReadInt32();
int instanceGuidIndex = r.ReadInt32();
int classIndex = r.ReadInt32();
int instanceIndex = r.ReadInt32();
Guid classGuid = guids[classGuidIndex];
Guid instanceGuid = guids[instanceGuidIndex];
InstanceKey key = new InstanceKey(classIndex, instanceIndex);
library.Instances.Add(new LibraryInstance(key, instanceGuid, classGuid));
}
r.BaseStream.Seek(attributesSection.Offset, SeekOrigin.Begin);
McxAttribute[] attributes = new McxAttribute[attributesSection.Count];
for (int i = 0; i < attributesSection.Count; i++)
{
int sourceInstanceIndex = r.ReadInt32();
int attributeInstanceIndex = r.ReadInt32();
attributes[i].SourceInstanceGuid = guids[sourceInstanceIndex];
attributes[i].AttributeInstanceGuid = guids[attributeInstanceIndex];
attributes[i].ValueIndex = r.ReadInt32();
}
r.BaseStream.Seek(relationshipsSection.Offset, SeekOrigin.Begin);
for (int i = 0; i < relationshipsSection.Count; i++)
{
int sourceInstanceIndex = r.ReadInt32();
int relationshipInstanceIndex = r.ReadInt32();
int targetInstanceIndex = r.ReadInt32();
Guid sourceInstanceGuid = guids[sourceInstanceIndex];
Guid relationshipInstanceGuid = guids[relationshipInstanceIndex];
Guid targetInstanceGuid = guids[targetInstanceIndex];
library.Relationships.Add(new LibraryRelationship(sourceInstanceGuid, relationshipInstanceGuid, targetInstanceGuid));
}
r.BaseStream.Seek(stringTableSection.Offset, SeekOrigin.Begin);
string[] stringTable = new string[stringTableSection.Count];
for (int i = 0; i < stringTableSection.Count; i++)
{
stringTable[i] = r.ReadNullTerminatedString();
}
for (int i = 0; i < attributesSection.Count; i++)
{
library.Attributes.Add(new LibraryAttribute(attributes[i].SourceInstanceGuid, attributes[i].AttributeInstanceGuid, stringTable[attributes[i].ValueIndex]));
}
if (resourcesSection.Length > 0)
{
}
}
}

View File

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\..\lib\Mocha.Core\Mocha.Core.csproj" />
<ProjectReference Include="..\..\..\..\framework-dotnet\framework-dotnet\src\lib\MBS.Core\MBS.Core.csproj" />
</ItemGroup>
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>