Skip to content

Commit

Permalink
Merge pull request #305 from Chris3606/develop
Browse files Browse the repository at this point in the history
GoRogue 3.0.0-beta06
  • Loading branch information
Chris3606 authored May 23, 2023
2 parents 3cd0e58 + 97675b9 commit 9a3b53e
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 16 deletions.
4 changes: 2 additions & 2 deletions GoRogue/Components/ParentAware/IParentAwareComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace GoRogue.Components.ParentAware
{
/// <summary>
/// Optional interface for components that are attached to something implementing <see cref="IObjectWithComponents"/>.
/// Optional interface for components that are attached to something via a components field.
/// </summary>
/// <remarks>
/// While the implementation of this interface is not required for GoRogue components, when it is used with something
Expand All @@ -22,6 +22,6 @@ public interface IParentAwareComponent
/// <see cref="IComponentCollection"/>. It is set automatically when added/removed from an object's
/// component collection.
/// </remarks>
public IObjectWithComponents? Parent { get; set; }
public object? Parent { get; set; }
}
}
56 changes: 43 additions & 13 deletions GoRogue/Components/ParentAware/ParentAwareComponentBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ namespace GoRogue.Components.ParentAware
/// <typeparam name="T">The type of the parent being passed.</typeparam>
[PublicAPI]
public class ParentAwareComponentRemovedEventArgs<T> : EventArgs
where T : IObjectWithComponents
{
/// <summary>
/// The parent from which the object was detached.
Expand All @@ -33,6 +32,17 @@ public ParentAwareComponentRemovedEventArgs(T oldParent)
/// type-checking of parent, or requiring that the object it's attached to has or does not have certain types of
/// components.
/// </summary>
/// <remarks>
/// This class may be added as a component to any class that implements <see cref="IObjectWithComponents"/>, however components
/// inheriting from this class will not implicitly fail in any way if it is used with a class that does not implement that interface.
/// Certain functions such as <see cref="IncompatibleWith{TComponent}"/> do require that their parent implement IObjectWithComponents,
/// and in general there is no guarantee that the Parent field gets updated if the parent doesn't implement that interface; however
/// you can sync the parent field manually as applicable.
///
/// In most cases, the intended usage is to add this as a component to a class that implements <see cref="IObjectWithComponents"/>;
/// however the option of not doing so and manually syncing the Parent field instead allows this functionality to be tied into other
/// component systems as well.
/// </remarks>
[PublicAPI]
public class ParentAwareComponentBase : IParentAwareComponent
{
Expand All @@ -44,13 +54,13 @@ public class ParentAwareComponentBase : IParentAwareComponent
/// <summary>
/// Fires when the component is unattached from an object
/// </summary>
public event EventHandler<ParentAwareComponentRemovedEventArgs<IObjectWithComponents>>? Removed;
public event EventHandler<ParentAwareComponentRemovedEventArgs<object>>? Removed;

private IObjectWithComponents? _parent;
private object? _parent;
/// <summary>
/// The object the component is attached to.
/// </summary>
public virtual IObjectWithComponents? Parent
public virtual object? Parent
{
get => _parent;
set
Expand All @@ -62,14 +72,13 @@ public virtual IObjectWithComponents? Parent
var oldValue = _parent;
_parent = value;
// Null for oldValue is not possible because value == null AND value != _parent
Removed?.Invoke(this, new ParentAwareComponentRemovedEventArgs<IObjectWithComponents>(oldValue!));
Removed?.Invoke(this, new ParentAwareComponentRemovedEventArgs<object>(oldValue!));
}
else
{
if (_parent != null)
throw new Exception($"Components of type {nameof(ParentAwareComponentBase)} inherit from " +
$"{nameof(IParentAwareComponent)}, so they can't be attached to multiple " +
"objects simultaneously.");
throw new Exception($"Components of type {nameof(ParentAwareComponentBase)} " +
"can't be attached to multiple objects simultaneously.");

_parent = value;
Added?.Invoke(this, EventArgs.Empty);
Expand Down Expand Up @@ -102,26 +111,47 @@ public static void ParentTypeCheck<TParent>(object? s, EventArgs e)
/// can't have multiple instances of itself attached to the same object by using
/// Added += IncompatibleWith&lt;MyOwnType&gt;.
/// </summary>
/// <remarks>
/// This function only works if the parent is of type IObjectWithComponents. If the parent is not of that
/// type, this function will throw an exception.
/// </remarks>
/// <typeparam name="TComponent">Type of the component this one is incompatible with.</typeparam>
/// <param name="s"/>
/// <param name="e"/>
public void IncompatibleWith<TComponent>(object? s, EventArgs e)
where TComponent : class
{
if (Parent!.GoRogueComponents.GetAll<TComponent>().Any(i => !ReferenceEquals(this, i)))
var parent = Parent as IObjectWithComponents;
if (parent == null)
throw new Exception($"{nameof(IncompatibleWith)} can only be used with components that are attached to " +
$"objects that implement {nameof(IObjectWithComponents)}.");

if (parent.GoRogueComponents.GetAll<TComponent>().Any(i => !ReferenceEquals(this, i)))
throw new Exception($"{GetType().Name} components are marked as incompatible with {typeof(TComponent).Name} components, so the component couldn't be added.");
}
}

/// <summary>
/// Optional base class for components attached to a a class implementing <see cref="IObjectWithComponents"/>.
/// Optional base class for components attached to a class implementing <see cref="IObjectWithComponents"/>.
/// Adds all functionality of <see cref="ParentAwareComponentBase"/>, and additionally type-checks the object it's
/// attached to to make sure it is of the given type. It also exposes its <see cref="Parent"/> property as that type
/// instead of IObjectWithComponents.
/// instead of object.
/// </summary>
/// <remarks>
/// Like <see cref="ParentAwareComponentBase"/>, subclasses of this class may be added as a component to any class that implements
/// <see cref="IObjectWithComponents"/>, however components inheriting from this class will not implicitly fail in any way if it is
/// used with a class that does not implement that interface. Certain functions such as
/// <see cref="ParentAwareComponentBase.IncompatibleWith{TComponent}"/> do require that their parent implement IObjectWithComponents,
/// and in general there is no guarantee that the Parent field gets updated if the parent doesn't implement that interface; however
/// you can sync the parent field manually as applicable.
///
/// In most cases, the intended usage is to add this as a component to a class that implements <see cref="IObjectWithComponents"/>;
/// however the option of not doing so and manually syncing the Parent field instead allows this functionality to be tied into other
/// component systems as well.
/// </remarks>
/// <typeparam name="TParent">Type of the component's parent.</typeparam>
[PublicAPI]
public class ParentAwareComponentBase<TParent> : ParentAwareComponentBase where TParent : class, IObjectWithComponents
public class ParentAwareComponentBase<TParent> : ParentAwareComponentBase where TParent : class
{
/// <summary>
/// The object the component is attached to.
Expand All @@ -147,7 +177,7 @@ public ParentAwareComponentBase()
base.Removed += OnRemoved;
}

private void OnRemoved(object? sender, ParentAwareComponentRemovedEventArgs<IObjectWithComponents> e)
private void OnRemoved(object? sender, ParentAwareComponentRemovedEventArgs<object> e)
=> Removed?.Invoke(sender, new ParentAwareComponentRemovedEventArgs<TParent>((TParent)e.OldParent));
}
}
2 changes: 1 addition & 1 deletion GoRogue/GoRogue.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
Configure versioning information, making sure to append "debug" to Debug version to allow publishing
to NuGet seperately from Release version.
-->
<Version>3.0.0-beta05</Version>
<Version>3.0.0-beta06</Version>
<Version Condition="'$(Configuration)'=='Debug'">$(Version)-debug</Version>

<!-- More nuget package settings-->
Expand Down
7 changes: 7 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

None

## [3.0.0-beta06] - 2023-05-22

### Changed
- `IParentAwareComponent` and `ParentAwareComponentBase` now record the parent as type `object`
- `ParentAwareComponentBase<T>` no longer has type restrictions on type T; it can now accept any type as the parent.
- This makes integration into other component systems more feasible since `IObjectWithComponents` is no longer required

## [3.0.0-beta05] - 2023-05-17

### Added
Expand Down

0 comments on commit 9a3b53e

Please sign in to comment.