@Jjagg make some MSPaint for how it could look
If a plugin has a runtime component and a non-runtime component I think we need some kind of dependency injection system and a IoC container. Not sure exactly how weād go about this, but base components like this should be in the base editor so it can provide an easy to use API for plugins.
Iād also like the editor to be aware of and be able to modify .mgcb files. Kind of like a super powered Pipeline Tool. Also for the reason of providing a nice plugin API. It would be a hassle to open up the Pipeline Tool after creating content to actually add it to your project.
The editor itself is just an empty shell, not sure what you want me to draw And I havenāt given much thought to how the interface for getting plugins would look.
All very interesting. If the MonoGame Editor is useless without plugins, then I think we should brainstorm a set of plugins that actually do the lifting. Iām not saying we create the plugins. I am saying we should generate a list of plugins, and understand how theyād click together inside the MonoGame Editor to form a useful whole.
Heres twoā¦
- A Camera Plugin
Something to manage World/Proj/View matrices. - A UI Plugin for rendering 2D assets with SpriteBatch. Iām not sure if this plugin would also allow for visual sprite manipulation (like, click and drag to move a sprite), or if that would be another package.
Am I on the wrong track even suggesting these things? I understand that the Editor itself is a service provider, but I think itād be meaningful to know what kinds of functionality it needs to support for packages.
We should outline and define the abstractions. Before I get stone for bringing this up plugin architectures can get ruin quick by either becoming too strict or to open, rendering it useless. With that said there are several applications already using different frameworks and architecture to perform these tasks. Get a group together, review these architecture/frameworks, and come up with a spec (otherwise we will be discussing this until the cows come home and nothing will get done).
There is a lot written about Eclipse plugin architecture good place to start.
The Architecture of Open Source Applications (Excellent coverage of Eclipse and others)
Notes on the Eclipse Plug-in Architecture
I think we should also define some base functionality. What makes sense to have out of the box. Basically a list of plugins so anyone using the editor can start using it, or using as a reference to create their own plugins.
Finally, sticking to the following principles will make DI easier.
S.O.L.I.D
A.C.I.D
Hope this helps guys - I am definitely in favor of creating tools for Monogame and making it more accessible to less experience devs.
What the editor would be able to do ? Just basic level editing, or would it be possible to use a renderer one has developped ? (my renderer, @kosmonautgamesā engine for ex, etc)
Will it offer a particles workflow ? Physics ?
Shadows ? Scene graph management ?
Texture manager ?
Model manager ?
Animation editor ?
All this with plugins ?
Yes, Iād like all of those things to be possible.
We use https://github.com/SonyWWS/LevelEditor for our level editor in Protogame. We donāt have our Protogame-specific modifications open sourced yet, but itās on the roadmap. However, this editor isnāt ideal as itās Windows-only and assumes a C++ engine (which we do some horrible things like generating C++ code to translate C# entities defined in a Protogame project and make them available in the editor).
More generally, I always wanted to support the idea of editor plugins in Protobuild that could extend Visual Studio or MonoDevelop in a cross-platform way. Hereās a video from way back when I had it working in MonoDevelop: https://www.youtube.com/watch?v=TO7UxNKS5dQ. However, this was hampered by MonoDevelop completely rewriting their project APIs for MonoDevelop 6, and the lack of support in getting the embedding MonoGame PR upstreamed. I still want to support this at some point, because I think it offers the best way forward in support editors for MonoGame when thereās such a diverse set of engines available for people to use.
However, I think in the immediate future what MonoGame really needs is a curated asset store, like Unity and Unreal. A central site that people can go to discover engines, libraries and other tools to use alongside MonoGame, because right now I feel like discovery and installation (or usage) of all of these engines and libraries is the biggest impediment to new users of MonoGame. Thereās plenty of good stuff out there, but finding out about it is hard. Once we have some kind of curated site, then we can proceed with getting all of these different engines aligned on some level in terms of installation and API surface so that they can extend or support visual editors.
The reason why Iād go with a standalone is that new IDE/editor options are up and coming like Rider and VsCode. I donāt want to force people into specific editing environments to be able to take advantage of this project. Also maintainability (ughh, MonoDevelop).
Is that PR still relevant? Iāll give it a look later. Iāve been paying attention to MG code/dependencies that ruin embedding lately, like GraphicsDevice(Manager) depending on Game and/or GameWindow. I agree itās important to support proper embedding. Like I said before Iād like this editor to run using MG, but without a Game instance.
I agree, but while it would be great to have, a fully-fledged asset store is hard to set up. I hadnāt really considered assets yet (just libs) and was thinking we could maybe make do with Nuget. But honestly I donāt have any experience with package management stuff. Having something for assets and libraries, tailored for MonoGame sounds really nice. (Not specifically for this editor). So it would be great to have you help out in developing this idea (and implementing it) @hachque
Iāve been paying attention to MG code/dependencies that ruin embedding lately, like GraphicsDevice(Manager) depending on Game and/or GameWindow.
I know its heresy but right in game1 after i create or change any of the major variables like the window the manager the device content ect, i re-reference a public static duplicate reference to all of those right in my in my utility engine. I wrap game and use that wrapper as the new base class, the base passes the reference for copying as global static references, which is just to a class named engine.
Eg Game1 : MyBase
were MyBase : Game
Mybase calls to Engine.SetReferences( this refs ectā¦);
Dunno if this idea helps in anyway.
The way i rig up my quick test projects is similar, basically the whole thing is kind of like my own plugin of classes. Of course its not meant to be anything like what your talking about but in a crude way its a similar idea.
What i think your talking about is a elegant proper way to do what i do as a sort of hack by tossing all my stuff into a usable namespace and cherry picking it.
Instead of using events i do flow control thru polling and a ui button manager itself to monitor input changes. Like a game screen but totally bypassing it.
Normally i would just add the whole project and link it to my newly created one and use the engines base. Then just use whatever class i needed camera nurbs model pathing draw math ect⦠I suppose the idea was similar.
Though im not saying you would want to hard code modes or do much of anything below only trying to put out the idea of
Just maybe grabbing Game itself and wrapping it to be used as a projects game1 : YourEngineBase in some form so that your engine plays middleman for those primary variables.
#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
//using MGU_36v;
#endregion
namespace MGU_36v
{
public class AMGame1 : BxBasicXnaUtilitysGame1Base//Game
{
BxButtonManager Buttonmanager;
//
public const int MENU_MODE = 0;
public const int MODE_1 = 1;
public const int MODE_2 = 2;
public const int MODE_3 = 3;
public const int MODE_4 = 4;
public const int MODE_5 = 5;
public const int MODE_6 = 6;
public const int MODE_7 = 7;
//
ExampleMode_1 Mode_1;
BxButtonEditorViewer Mode_2;
BxSpriteSheetEditor Mode_3;
ExampleMode_4 Mode_4;
ExampleMode_5 Mode_5;
ExampleMode_6 Mode_6;
ExampleMode_7 Mode_7;
//
public static string[] menu_string = new string[] { "0) Goto Menu", "1) mode 1 example", "2) mode 2 example", "3) mode 3 example", "4) mode 4 example", "5) mode 5 example", "6) mode 6 example", "7) mode 7 example" };
public AMGame1(): base()
{
// base will control this to ensure the reference stays in sync on device resets
// just call the engine to get the this, device, manager, or window ect
//graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content"; // or "Assets"
// title
Window.Title = "MGU_36v Engine 2013";
// initialize log
BxLog.initializeLog("Log.txt");
// set game mode to 0 for the menu
BxEngine.game_mode = 0;
// add a callback that can accept width and height as its parameters
BxEngine.Add_MethodToFire_On_WindowReSizeEvent_WH(this.onWindowsResize);
//
Buttonmanager = new BxButtonManager(BxEngine.game_mode);
Buttonmanager.createListButton("Menu", new VirtRect(.4f, .05f, .2f, .03f), new VirtRect(.4f, .05f, .2f, .6f), AMGame1.modeChange_BM, false, false, menu_string);
//
Buttonmanager.createNumericInputButton("Set FrameRate", new VirtRect(.4f, .09f, .2f, .03f), setFrameRate_BM, false, 1f);
Buttonmanager.createToggleButton("fullscreen", new VirtRect(.4f, .14f, .2f, .03f), toggleFullScreen_BM, false);
//
// extra default stuff when used
//BxEngien.constructXnaBasicManager(this, c, true);
//
Mode_1 = new ExampleMode_1(1);
BxEngine.Add_MethodToFire_On_WindowReSizeEvent_WH(Mode_1.onWindowsResize);
Mode_2 = new BxButtonEditorViewer(2);
BxEngine.Add_MethodToFire_On_WindowReSizeEvent_WH(Mode_2.onWindowsResize);
Mode_3 = new BxSpriteSheetEditor(3);
BxEngine.Add_MethodToFire_On_WindowReSizeEvent_WH(Mode_3.onWindowsResize);
Mode_4 = new ExampleMode_4(4);
BxEngine.Add_MethodToFire_On_WindowReSizeEvent_WH(Mode_4.onWindowsResize);
Mode_5 = new ExampleMode_5(5);
BxEngine.Add_MethodToFire_On_WindowReSizeEvent_WH(Mode_5.onWindowsResize);
Mode_6 = new ExampleMode_6(6);
BxEngine.Add_MethodToFire_On_WindowReSizeEvent_WH(Mode_6.onWindowsResize);
Mode_7 = new ExampleMode_7(7);
BxEngine.Add_MethodToFire_On_WindowReSizeEvent_WH(Mode_7.onWindowsResize);
}
public void onWindowsResize(int w, int h)
{
Console.WriteLine(" Game1 menu window is resizing w " + w + " h " + h);
}
protected override void Initialize()
{
BxEngine.initialize(graphics, Content, GraphicsDevice, spriteBatch, 800, 600, SurfaceFormat.Color, false, true, true);
Mode_1.initialize();
Mode_2.initialize();
Mode_3.initialize();
Mode_4.initialize();
Mode_5.initialize();
Mode_6.initialize();
Mode_7.initialize();
//
base.Initialize();
}
protected override void LoadContent()
{
base.PreLoadContent();
Mode_1.load();
Mode_2.load();
Mode_3.load();
Mode_4.load();
Mode_5.load();
Mode_6.load();
Mode_7.load();
//
base.PostLoadContent();
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
this.Exit();//exit();
//_____________________________
//
switch (BxEngine.game_mode)
{
case MENU_MODE:
// call into some other classes update that serves as the menu
// or leave game1 as the menu and call a method in this class
// i can use the Bxbutton manager to create a menu if desired
break;
case MODE_1:
Mode_1.update();
break;
case MODE_2:
Mode_2.update();
break;
case MODE_3:
Mode_3.update();
break;
case MODE_4:
Mode_4.update();
break;
case MODE_5:
Mode_5.update();
break;
case MODE_6:
Mode_6.update();
break;
case MODE_7:
Mode_7.update();
break;
}
//
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
switch (BxEngine.game_mode)
{
case MENU_MODE:
BxEngine.clearScreen(Color.White);
BxEngine.callBeginDraw();
//BxEngien.callBeginDraw(true);
//BxEngien.callBeginDraw(true,false,true);
BxDraw2d.DrawCoolText("Menu Mode", .4f, .008f, Color.Tan);
BxEngine.callEndDraw(true);
//BxEngien.callEndDraw();
break;
case MODE_1:
Mode_1.draw();
break;
case MODE_2:
Mode_2.draw();
break;
case MODE_3:
Mode_3.draw();
break;
case MODE_4:
Mode_4.draw();
break;
case MODE_5:
Mode_5.draw();
break;
case MODE_6:
Mode_6.draw();
break;
case MODE_7:
Mode_7.draw();
break;
}
//____________________________
//
base.Draw(gameTime);
//_____________________________
}
public static void modeChange_BM()
{
BxEngine.game_mode = BxButtonManager.getListButtonChoice();
}
public void setFrameRate_BM()
{
int newrate = (int)BxButtonManager.getNumericInputButtonValue();
if (newrate > 10 && newrate < 70)
{
BxEngine.setFrameRate(this, newrate, true);
}
}
public void toggleFullScreen_BM()
{
bool result = BxButtonManager.getToggleButtonStatus();
BxEngine.toggleFullScreen();
}
}
ā¦
/// <summary>
/// spacial button test for the button manager itself
/// like for if i want a button over every game object
/// i might need a new manager like that.
/// </summary>
public class ExampleMode_4
{
BxButtonManager Buttonmanager;
//
BxSpacialBucketManager bkm;
//
public ExampleMode_4(int game_mode)
{
// add a callback that can accept width and height as its parameters
//BxEngien.Add_MethodToFire_On_WindowReSizeEvent_WH(this.onWindowsResize);
//
Buttonmanager = new BxButtonManager(game_mode);
Buttonmanager.createListButton("Menu", new VirtRect(.4f, .05f, .2f, .03f), new VirtRect(.4f, .05f, .2f, .6f), modeChange_BM, false, false, new string[] { "0) Goto Menu", "1) mode 1 example", "2) mode 2 example", "3) mode 3 example", "4) mode 4 example", "5) mode 5 example", "6) mode 6 example" });
}
public void onWindowsResize(int w, int h)
{
Console.WriteLine(" ExampleMode_4 window is resizing w " + w + " h " + h);
bkm.OnResize_FM(BxEngine.client_screen_width, BxEngine.client_screen_height);
}
public void load()
{
bkm = new BxSpacialBucketManager(BxEngine.client_screen_width, BxEngine.client_screen_height, 7, 18);
bkm.AddRectangle(new VirtRect(.150f, .150f, .210f, .210f));
bkm.AddRectangle(new VirtRect(.250f, .250f, .210f, .210f));
bkm.AddRectangle(new VirtRect(.221f, .550f, .051f, .110f));
bkm.AddRectangle(new VirtRect(.850f, .850f, .130f, .130f));
bkm.AddRectangle(new VirtRect(.421f, .350f, .051f, .110f));
bkm.AddRectangle(new VirtRect(.721f, .150f, .071f, .08f));
bkm.AddRectangle(new VirtRect(.450f, .650f, .150f, .160f));
bkm.AddRectangle(new VirtRect(.220f, .270f, .310f, .260f));
bkm.AddRectangle(new VirtRect(.221f, .350f, .151f, .170f));
bkm.AddRectangle(new VirtRect(.521f, .150f, .251f, .170f));
bkm.AddRectangle(new VirtRect(.650f, .450f, .130f, .130f));
}
public void unload() { }
public void initialize() { }
public void update()
{ }
public void draw()
{
BxEngine.clearScreen(Color.DarkSlateGray);
BxEngine.callBeginDraw(true);
BxDraw2d.DrawCoolText("Example mode 4", .4f, .01f, Color.Blue);
bkm.Draw();
BxEngine.callEndDraw(true);
}
public void modeChange_BM()
{
BxEngine.game_mode = BxButtonManager.getListButtonChoice();
}
}
.
Im also trying to understand how to visualize the way plugins will actually end up being used called in a game.