diff --git a/LibMatrix.EventTypes.Abstractions/BaseMatrixEventContent.cs b/LibMatrix.EventTypes.Abstractions/BaseMatrixEventContent.cs
new file mode 100644
index 0000000..eba50a5
--- /dev/null
+++ b/LibMatrix.EventTypes.Abstractions/BaseMatrixEventContent.cs
@@ -0,0 +1,54 @@
+using System.Reflection;
+using System.Text.Json;
+using System.Text.Json.Nodes;
+using System.Text.Json.Serialization;
+using ArcaneLibs.Extensions;
+
+namespace LibMatrix.EventTypes;
+
+// <T> : MatrixEventContent where T : MatrixEventContent<T>, new() {
+/// <summary>
+/// Extensible Event Content, aims to provide an API similar to JsonNode/JsonObject
+/// <seealso cref="System.Text.Json.Nodes.JsonNode"/>
+/// <seealso cref="System.Text.Json.Nodes.JsonObject"/>
+/// </summary>
+[JsonConverter(typeof(MatrixEventContentConverter<BaseMatrixEventContent>))]
+// [JsonSerializable(typeof(MatrixEventContent))]
+public class BaseMatrixEventContent {
+ public JsonObject InternalJson { get; set; } = new();
+
+ public BaseMatrixEventContent() { }
+
+ public BaseMatrixEventContent(JsonNode json) {
+ InternalJson = json.AsObject();
+ }
+
+ public static implicit operator BaseMatrixEventContent(JsonNode json) => new(json);
+
+ // public static implicit operator JsonNode(MatrixEventContent content) => content.InternalJson;
+
+ [JsonIgnore]
+ public IEnumerable<string> EventTypes => this.GetType().GetCustomAttributes<MatrixEventAttribute>().Select(x => x.EventType);
+
+ [JsonIgnore]
+ public string EventType => EventTypes.First();
+
+ public JsonNode? this[string key] => InternalJson[key];
+
+ public string ToJson() => InternalJson.ToJson();
+
+
+ public class MatrixEventContentConverter<T> : JsonConverter<T> where T : BaseMatrixEventContent, new() {
+ public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {
+ // read entire object into a JsonObject
+ // Console.WriteLine($"MatrixEventContentConverter<T>: Reading {typeToConvert}");
+ var json = JsonNode.Parse(ref reader);
+ return new T { InternalJson = json.AsObject() };
+ }
+
+ public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) {
+ // Console.WriteLine($"MatrixEventContentConverter<T>: Writing {value.GetType()}");
+ value.InternalJson.WriteTo(writer);
+ }
+ }
+}
\ No newline at end of file
diff --git a/LibMatrix.EventTypes.Abstractions/Converters/EventConverterFactory.cs b/LibMatrix.EventTypes.Abstractions/Converters/EventConverterFactory.cs
new file mode 100644
index 0000000..3b4c493
--- /dev/null
+++ b/LibMatrix.EventTypes.Abstractions/Converters/EventConverterFactory.cs
@@ -0,0 +1,112 @@
+/*namespace LibMatrix.EventTypes.Converters;
+
+using System.Reflection;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+public class MatrixEventConverter : JsonConverterFactory {
+ public override bool CanConvert(Type typeToConvert) {
+ Console.WriteLine(typeToConvert);
+ if (!typeToConvert.IsGenericType) {
+ return false;
+ }
+
+ if (typeToConvert.GetGenericTypeDefinition() != typeof(MatrixEvent<>)) {
+ return false;
+ }
+
+ return typeToConvert.GetGenericArguments()[0].IsAssignableTo(typeof(MatrixEventContent));
+ }
+
+ public override JsonConverter CreateConverter(
+ Type type,
+ JsonSerializerOptions options) {
+ Type[] typeArguments = type.GetGenericArguments();
+ Type keyType = typeArguments[0];
+ Type valueType = typeArguments[1];
+
+ JsonConverter converter = (JsonConverter)Activator.CreateInstance(
+ typeof(DictionaryEnumConverterInner<,>).MakeGenericType(
+ [keyType, valueType]),
+ BindingFlags.Instance | BindingFlags.Public,
+ binder: null,
+ args: [options],
+ culture: null)!;
+
+ return converter;
+ }
+
+ private class DictionaryEnumConverterInner<TKey, TValue> :
+ JsonConverter<Dictionary<TKey, TValue>> where TKey : struct, Enum {
+ private readonly JsonConverter<TValue> _valueConverter;
+ private readonly Type _keyType;
+ private readonly Type _valueType;
+
+ public DictionaryEnumConverterInner(JsonSerializerOptions options) {
+ // For performance, use the existing converter.
+ _valueConverter = (JsonConverter<TValue>)options
+ .GetConverter(typeof(TValue));
+
+ // Cache the key and value types.
+ _keyType = typeof(TKey);
+ _valueType = typeof(TValue);
+ }
+
+ public override Dictionary<TKey, TValue> Read(
+ ref Utf8JsonReader reader,
+ Type typeToConvert,
+ JsonSerializerOptions options) {
+ if (reader.TokenType != JsonTokenType.StartObject) {
+ throw new JsonException();
+ }
+
+ var dictionary = new Dictionary<TKey, TValue>();
+
+ while (reader.Read()) {
+ if (reader.TokenType == JsonTokenType.EndObject) {
+ return dictionary;
+ }
+
+ // Get the key.
+ if (reader.TokenType != JsonTokenType.PropertyName) {
+ throw new JsonException();
+ }
+
+ string? propertyName = reader.GetString();
+
+ // For performance, parse with ignoreCase:false first.
+ if (!Enum.TryParse(propertyName, ignoreCase: false, out TKey key) &&
+ !Enum.TryParse(propertyName, ignoreCase: true, out key)) {
+ throw new JsonException(
+ $"Unable to convert \"{propertyName}\" to Enum \"{_keyType}\".");
+ }
+
+ // Get the value.
+ reader.Read();
+ TValue value = _valueConverter.Read(ref reader, _valueType, options)!;
+
+ // Add to dictionary.
+ dictionary.Add(key, value);
+ }
+
+ throw new JsonException();
+ }
+
+ public override void Write(
+ Utf8JsonWriter writer,
+ Dictionary<TKey, TValue> dictionary,
+ JsonSerializerOptions options) {
+ writer.WriteStartObject();
+
+ foreach ((TKey key, TValue value) in dictionary) {
+ string propertyName = key.ToString();
+ writer.WritePropertyName
+ (options.PropertyNamingPolicy?.ConvertName(propertyName) ?? propertyName);
+
+ _valueConverter.Write(writer, value, options);
+ }
+
+ writer.WriteEndObject();
+ }
+ }
+}*/
\ No newline at end of file
diff --git a/LibMatrix.EventTypes.Abstractions/Converters/EventJsonSerializerContext.cs b/LibMatrix.EventTypes.Abstractions/Converters/EventJsonSerializerContext.cs
new file mode 100644
index 0000000..5b8e2dc
--- /dev/null
+++ b/LibMatrix.EventTypes.Abstractions/Converters/EventJsonSerializerContext.cs
@@ -0,0 +1,10 @@
+// using System.Text.Json;
+// using System.Text.Json.Serialization;
+// using System.Text.Json.Serialization.Metadata;
+//
+// namespace LibMatrix.EventTypes.Converters;
+//
+// [JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Serialization)]
+// [JsonSerializable(typeof(MatrixEvent<>))]
+// internal partial class EventJsonSerializerContext : JsonSerializerContext {
+// }
\ No newline at end of file
diff --git a/LibMatrix.EventTypes.Abstractions/LibMatrix.EventTypes.Abstractions.csproj b/LibMatrix.EventTypes.Abstractions/LibMatrix.EventTypes.Abstractions.csproj
new file mode 100644
index 0000000..dce51ea
--- /dev/null
+++ b/LibMatrix.EventTypes.Abstractions/LibMatrix.EventTypes.Abstractions.csproj
@@ -0,0 +1,14 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>net8.0</TargetFramework>
+ <ImplicitUsings>enable</ImplicitUsings>
+ <Nullable>enable</Nullable>
+ <LangVersion>preview</LangVersion>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="..\ArcaneLibs\ArcaneLibs\ArcaneLibs.csproj" />
+ </ItemGroup>
+
+</Project>
diff --git a/LibMatrix.EventTypes.Abstractions/MatrixEvent.cs b/LibMatrix.EventTypes.Abstractions/MatrixEvent.cs
new file mode 100644
index 0000000..0e548c6
--- /dev/null
+++ b/LibMatrix.EventTypes.Abstractions/MatrixEvent.cs
@@ -0,0 +1,9 @@
+using System.Text.Json.Serialization;
+
+namespace LibMatrix.EventTypes;
+
+public interface IMatrixEvent<out T> where T : BaseMatrixEventContent;
+public class MatrixEvent<T> : IMatrixEvent<T> where T : BaseMatrixEventContent {
+ [JsonPropertyName("content")]
+ public T? Content { get; set; }
+}
\ No newline at end of file
diff --git a/LibMatrix.EventTypes.Abstractions/MatrixEventAttribute.cs b/LibMatrix.EventTypes.Abstractions/MatrixEventAttribute.cs
new file mode 100644
index 0000000..aface6d
--- /dev/null
+++ b/LibMatrix.EventTypes.Abstractions/MatrixEventAttribute.cs
@@ -0,0 +1,9 @@
+using System.Text.Json.Serialization;
+
+namespace LibMatrix.EventTypes;
+
+[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
+public class MatrixEventAttribute(string eventType, bool deprecated = false) : Attribute {
+ public string EventType { get; } = eventType;
+ public bool Deprecated { get; } = deprecated;
+}
\ No newline at end of file
diff --git a/LibMatrix.EventTypes.Abstractions/MatrixEventCollection.cs b/LibMatrix.EventTypes.Abstractions/MatrixEventCollection.cs
new file mode 100644
index 0000000..78886d9
--- /dev/null
+++ b/LibMatrix.EventTypes.Abstractions/MatrixEventCollection.cs
@@ -0,0 +1,71 @@
+// using System.Collections;
+//
+// namespace LibMatrix.EventTypes;
+//
+// public interface IMatrixEventCollection<out T> : IEnumerable<IMatrixEvent<T>> where T : MatrixEventContent {
+//
+// }
+// public class MatrixEventCollection : IMatrixEventCollection<MatrixEventContent>, IList<MatrixEvent<MatrixEventContent> {
+// private IList<MatrixEvent<MatrixEventContent>> _listImplementation;
+// public IEnumerator<MatrixEvent<MatrixEventContent>> GetEnumerator() => _listImplementation.GetEnumerator();
+//
+// IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)_listImplementation).GetEnumerator();
+//
+// public void Add(MatrixEvent<MatrixEventContent> item) => _listImplementation.Add(item);
+//
+// public void Clear() => _listImplementation.Clear();
+//
+// public bool Contains(MatrixEvent<MatrixEventContent> item) => _listImplementation.Contains(item);
+//
+// public void CopyTo(MatrixEvent<MatrixEventContent>[] array, int arrayIndex) => _listImplementation.CopyTo(array, arrayIndex);
+//
+// public bool Remove(MatrixEvent<MatrixEventContent> item) => _listImplementation.Remove(item);
+//
+// public int Count => _listImplementation.Count;
+//
+// public bool IsReadOnly => _listImplementation.IsReadOnly;
+//
+// public int IndexOf(MatrixEvent<MatrixEventContent> item) => _listImplementation.IndexOf(item);
+//
+// public void Insert(int index, MatrixEvent<MatrixEventContent> item) => _listImplementation.Insert(index, item);
+//
+// public void RemoveAt(int index) => _listImplementation.RemoveAt(index);
+//
+// public MatrixEvent<MatrixEventContent> this[int index] {
+// get => _listImplementation[index];
+// set => _listImplementation[index] = value;
+// }
+// }
+// public class MatrixEventCollection<T> : IMatrixEventCollection<T>, IList<MatrixEvent<T>> where T : MatrixEventContent {
+// //TODO: implement
+//
+// private IList<MatrixEvent<T>> _listImplementation = new List<MatrixEvent<T>>();
+// public IEnumerator<MatrixEvent<T>> GetEnumerator() => _listImplementation.GetEnumerator();
+//
+// IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)_listImplementation).GetEnumerator();
+//
+// public void Add(MatrixEvent<T> item) => _listImplementation.Add(item);
+//
+// public void Clear() => _listImplementation.Clear();
+//
+// public bool Contains(MatrixEvent<T> item) => _listImplementation.Contains(item);
+//
+// public void CopyTo(MatrixEvent<T>[] array, int arrayIndex) => _listImplementation.CopyTo(array, arrayIndex);
+//
+// public bool Remove(MatrixEvent<T> item) => _listImplementation.Remove(item);
+//
+// public int Count => _listImplementation.Count;
+//
+// public bool IsReadOnly => _listImplementation.IsReadOnly;
+//
+// public int IndexOf(MatrixEvent<T> item) => _listImplementation.IndexOf(item);
+//
+// public void Insert(int index, MatrixEvent<T> item) => _listImplementation.Insert(index, item);
+//
+// public void RemoveAt(int index) => _listImplementation.RemoveAt(index);
+//
+// public MatrixEvent<T> this[int index] {
+// get => _listImplementation[index];
+// set => _listImplementation[index] = value;
+// }
+// }a
\ No newline at end of file
|