Monogame: Extract platform-agnostic classes from MG.Framework into separate assembly

Created on 10 Aug 2019  路  10Comments  路  Source: MonoGame/MonoGame

This is essentially meant to restart the discussions from #2500.

I suggest we extract some foundational platform-agnostic classes into a seperate assembly called MonoGame.Core.

The content pipeline and tools by proxy reference a platform specific assembly right now. In practice this doesn't matter because the parts of MonoGame.Framework that are used by the content pipeline are the same across all platforms (it does not use any device resources like gpu, windowing or audio system), but that's also why it does not make sense to build the CP with a reference to a platform-specific assembly.

Mostly this restructuring serves to make things more sensible. We go from this:

DesktopGL    WindowsDX
    ^            ^
    | ref        | also
    |            | works
    CP -----------

To this:

      -------->  Core  <------
      |           ^          |
      |           |          |
DesktopGL    WindowsDX       CP

It also makes things less complicated for users that want to write a reusable library that only uses stuff in Core or a CP extension. The Core project can multitarget netstandard1.1 (for .NET Framework 4.5) and netstandard2.0.

Additional misc stuff this improves:

  • Doesn't include MonoGame.Framework runtime dependencies in Content.Pipeline and dependents.
  • Shared stuff isn't tested seperately for each platform.

@tomspilman Will this work for consoles? What .NET do they target?

cc @vpenades

Design

Most helpful comment

Yes, except it won't be PCL, but .NET Standard libs. Still will require bait-and-switch though.
See #6419 and #6175 for some discussion on interfaces and runtime abstractions.

All 10 comments

Candidate types to be moved to the core would be:

Maths types: Vector2, Vector3, Matrix, Quaternion...
Bounding types: BoundingBox, Rectangle, etc.
Curve types.
Color.
GameTime.
ReusableItemList.
Probably many types from Input namespace.

and... Interfaces!

As I stated in the past, the advantages of having a shared entry point assembly for all platforms is that it could help in simplifying a number of use cases.

For example, right now, many physics engines (Box2D, Farseer) targeting monogame and reusing monogame's maths, need to deploy multiple packages, one per monogame's target package. This is extremely inefficient, since physics are inherently platform agnostic.

Another use case is, for people like me that likes to use the MVC pattern, having the game logic in a separated assembly that is platform agnostic is a plus.

Also, any MonoGame extension capable of targeting only the Core would be future proof. Right now, even the simplest of monogame extension becomes outdated very fast as new platform specific packages are updated or introduced.

I would love having this to eliminate the need for Piranha and PCLs. Instead of a game's shared project depending on a PCL, it would depend on the Core package with all of its core functionality and interfaces for the platform-specific pieces. And then after the Protobuild elimination, everything builds from top to bottom with core build tools.

interfaces for the platform-specific pieces

This is not at all what I'm suggesting here. This discussion is only about extracting classes that are platform independent into their own assembly. If you want to discuss the interfaces idea, open a new issue (or there might already be an open issue for it).

This discussion is only about extracting classes that are platform independent into their own assembly.

My mistake. I assumed it was referring to all platform-independent types (which would include many interfaces, even if they have multiple platform-dependent implementations), but I suppose it鈥檚 really referring to class implementations.

So does that mean even though we have this shared Core project, we鈥檒l still need a PCL to capture the shared API of the outer surface for something like a shared game library that references graphics, despite it still only touching a platform-agnostic API? I suppose these are orthogonal issues and can be discussed and solved separately, even if with the same mechanism.

Yes, except it won't be PCL, but .NET Standard libs. Still will require bait-and-switch though.
See #6419 and #6175 for some discussion on interfaces and runtime abstractions.

Given that this is not gaining a lot of momentum, mostly because the different views of what should be abstracted or not.... I would propose this:

Let's abstract ONLY, what everybody agrees it's platform agnostic: _the maths_

And I would propose to name the assembly as _MonoGame.Numerics.Vectors_

The reason is that the already standarised System.Numeric.Vectors has its foundation on XNA's math types, with many of the names and methods being fully exchangeable:

|MonoGame|System.Numerics.Vectors|
|-|-|
|Vector2|Vector2|
|Vector3|Vector3|
|Vector4|Vector4|
|Quaternion|Quaternion|
|Matrix|Matrix4x4|

I would like to notice that the System.Numerics.Vectors nuget package does support NET45 via the _portable-net45+win8+wp8+wpa81_ profile. So theoretically, it could be possible to use them in consoles.

So, having _the maths_ in a separate assembly, AND having standarised System.Numerics.Vectors available in net45, could help to better align and leverage both APIs, allowing us to go in a number of directions:

  • Better interoperability between System.Numerics.Vectors and Monogame.Numeric.Vectors (implicit conversions, please?)
  • Eventually replace the maths of the framework with System.Numeric.Vectors, but keeping MonoGame.Numeric.Vectors around for backward compatibility (with reverse implicit conversions!)

Roadmap proposal

  1. Move the math types from MonoGame.Framework to MonoGame.Numerics.Vectors
  2. Provided System.Numerics.Vectors does not conflict with consoles, add implicit conversions between Monogame.Numerics.Vectors and System.Numerics.Vectors
  3. In the framework, replace Monogame maths, with System maths. backward compatibility should be preserved via implicit conversions provided by step 2.
  4. Finally, make MonoGame.Numerics.Vectors optional, only required for compiling legacy projects. New projects would use System.Numeric.Vectors.

Obviosly steps 3 and 4 are breaking changes that might be implemented in future versions of monogame. I would be happy if we just move to step 1 (and very happy if we reach step 2)

Eventually replace the maths of the framework with System.Numeric.Vectors, but keeping MonoGame.Numeric.Vectors around for backward compatibility (with reverse implicit conversions!)

I would also like to see us move to System.Numerics.Vectors. However my main goal in opening this issue is to have the Content Pipeline not depend on anything platform-specific. We can do both by separating out 2 shared assemblies from MonoGame.Framework. We can have the MonoGame.Numerics.Vectors assembly that contains the vector types and Matrix as suggested by @vpenades in the previous comment. Depending on that we can have the MonoGame.Core assembly which contains everything else that's not platform-specific, or at least whatever the Content Pipeline needs. Meaning the Content Pipeline only needs to depend on that assembly.

However my main goal in opening this issue is to have the Content Pipeline not depend on anything specific.

One key change is to decouple the contentManager from GraphicsDevice.
Custom readers that need to create graphic resources will request the GraphicsDevice through the ServiceProvider. (here we could add a generic 'T GetService()' in IServiceProvider to make it more readable.)

        var graphicsDeviceService = (IGraphicsDeviceService)input.ContentManager.ServiceProvider.GetService(typeof(IGraphicsDeviceService));
        var device = graphicsDeviceService.GraphicsDevice;

However MonoGame internally uses a private GraphicsDevice from ContentReader.
https://github.com/MonoGame/MonoGame/blob/3e92fc7bff7b4c32edf1314e143a4b7de4fab161/MonoGame.Framework/Content/ContentReaders/Texture2DReader.cs#L67
https://github.com/MonoGame/MonoGame/blob/develop/MonoGame.Framework/Content/ContentReader.cs#L33-L39
Which in turn it gets from serviceProvider.
https://github.com/MonoGame/MonoGame/blob/3e92fc7bff7b4c32edf1314e143a4b7de4fab161/MonoGame.Framework/Content/ContentManager.cs#L319
https://github.com/MonoGame/MonoGame/blob/3e92fc7bff7b4c32edf1314e143a4b7de4fab161/MonoGame.Framework/Content/ContentManager.cs#L392

We can remove those GraphicsDevice references from ContentReader and ContentManager to move ContentManager and basic readers (Vectors,Matrix,etc) in the core library.

I did not mean content readers and ContentManager as those are part of the runtime. I specifically mean the MonoGame.Framework.Content.Pipeline assembly. Since ContentManager and readers are part of the runtime - in the context where they are actually used, the full runtime is required because e.g. textures are loaded directly into VRAM - there is less value in decoupling them from the platform-specific stuff of the runtime in my opinion. I'd like to not complicate this assembly separation by making code changes.

If we finish the assembly separation we can see if there's anything else we can push into the shared assemblies. But IMO there needs to be value in doing so. If something can be in the shared assembly doesn't mean it has to be.

EDIT: I agree readers should use the graphics device service to get a GraphicsDevice, but that's not relevant for what I see as the purpose of this issue.

About MonoGame.Framework.Content.Pipeline, I think we should split the importers with all the 3rd party dependencies. The remaining assembly will then have the building Base classes for use/ref by building tools.
Additionally we can move all MonoGame extensions (ContentItem, ContentStats) under a MonoGame.Framework.Content namespace.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bjornenalfa picture bjornenalfa  路  5Comments

Ellesent picture Ellesent  路  5Comments

willmotil picture willmotil  路  5Comments

Legendree picture Legendree  路  3Comments

tomspilman picture tomspilman  路  4Comments