26

(64 replies, posted in Plugins)

MEmbedFile
link
This wraps up embedding files within code, which means that plugins can more easily provide their own data. Other plugins already sort of support this manually for some of their API scripts, which get loaded when MScript initialises. MEmbedFile will allow optional scripts, which can be loaded only when required with dofile as well as embedding images, or any other data.

To use:

MEmbedFile* file = NULL
MEmbedFileGetNew(file, "file/name", fileData, fileDataSize);

if(file)
{
    file->destroy();
    file = NULL;
}

The file is kept in the virtual file system until it is destroyed and can be accessed by any of the standard Maratis file IO functions.

27

(64 replies, posted in Plugins)

MRecast
link
Currently does nothing. Just a placeholder for when it does

28

(5 replies, posted in Plugins)

Right. I have said repeatedly I don't have time to do it... but my curiosity got the better of me. I have begun
github

Right now, it does absolutely nothing. I've just made it all compile and link together into a plugin. I was considering breaking it into two separate plugins (MDetour for the nav-mesh and MRecast for the actual pathfinding, then in future maybe make a MAI that includes both, plus some standard AI stuff) but for now I'm just compiling it all into MRecast.

Before I go any further, I want to say that I still don't have a huge amount of time available right now, so I wouldn't usable results in the near future.

To make things go a bit quicker, it would be useful if people could perhaps provide some use cases for me. If possible that would be a Maratis project, with a level mesh and some sort of character. If I get a couple to work, I can add them to the project (with permission) as examples. Obviously the simple things will come first, but if I could also get some more advanced features then the plugin can (eventually) aim to accomodate them. Things such as doors and jump points.

Ideally, I'd like to be able to represent the nav mesh in some way in the editor, but I don't think there's any way (yet) to render specifically for the editor. There's also the fact that Detour will decimate the level mesh into a much simpler nav mesh. When running in the editor, it makes sense to do this on loading the level (causing a noticable loading time) however when published, ideally we'd want to load the navmesh, so I think I'm going to have to finally get around to extending the publishing system so we can build the navmesh during the publishing

29

(0 replies, posted in General)

One of the things that's been getting to me is the lack of extensibility in the editor. I've been thinking about a number of ways this could be done, but most of them would require large changes to Maratis which would probably make it lose the simplicity that makes it what it is.

Something that I thought of would maybe work is allowing external editors to be tied into Maratis. They could potentially be Maratis applications if the developer of the tools desired, but it would also allow the freedom to create the tools using whatever technology the developer thought fitted the situation best, as what usually we care about is the assets that are created, it doesn't matter if they're made within Maratis, or with a WPF tool, or written in python, or whatever. Of course this means that the tools will have to be maintained for all relevant platforms by the developer rather than the platform support provided by Maratis.

The way I would see this working from a user-experience point of view, would be something like this:
- select object
- choose relevant behavior, say AI State Machine
- Presented with dropdown list of all available state machines to choose from*
- Click button next to dropdown list, which opens external tool

*These could be maintained in code by allowing a special MVariable type to be given an array of strings. Potentially these could be (formatted?) filenames from specific folders.

The external tool will be called by Maratis with command line arguments of the file it's been asked to open. In theory developers could add file explorers if you don't pass a file to open, to allow the tools to be standalone.

Anyway, thoughts?

30

(7 replies, posted in General)

Pär wrote:

Hey, anybody care to explain how to make a simple AI system?

Yep smile
As com3d and pleedian have mentioned, the question is a bit vague. Following what pleedian mentioned, you can easily make fish AI.

For most* other AI  you will probably want pathfinding as a basis. You can find many great tutorials online about how to implement pathfinding (one picked at random). Once you can tell an object "go to X" and it finds its way without getting stuck on walls, then the fun begins.

Unfortunately there's no pathfinding support in Maratis yet. There's a great library which would add pretty much everything we could possibly need if we could get it integrated. Unfortunately I haven't got the time to do so right now. Maybe someone else might want to make a plugin? *hint hint*

com3D wrote:

Does anyone have first hand experience with RAICK (Ragnarok Artificial Intelligence Creation Kit) ?

Never heard of it, but I just looked it up. Looks pretty awesome, but it is pretty much a (nicer) wrapper around the existing AI functionality, so I don't think that we can (easily) just copy/paste their lua scripts into Maratis. On the other hand, it's BSD, so there's absolutely nothing wrong with anyone looking and getting "inspired" by their stuff for within Maratis.

Pär wrote:

Hey, anybody care to explain how to make a simple AI system?

quoted again because I'm getting back to the original question
State machines. Research. Learn. Love. Writing a state machine is incredibly easy. Maintaining it as it grows unfortunately is less so. Ideally, I'd like to be able to add a variable type to a behavior which opens up a custom window for manipulating the state machine associated with that behavior (I already have a prototype tool written in a 2D engine... (actually, that gives me a GREAT idea... I might run and do some testing on it in a bit))

Anyway, those are my thoughts on the situation smile I hope they were at least a little coherent smile

*Of course you could have basic AI that just moves in a straight line between waypoints which wouldn't need pathfinding, chess AI wouldn't need pathfinding, etc etc etc

31

(64 replies, posted in Plugins)

Just a quick thing I remembered. It's possible in lua to have an implicit self parameter. So if it suits your programming style, you could do the following instead for MScriptableBehavior:

MScriptableBehavior "player" = {
    -- variables go here
    speed = 3,
}

function player:update()
    -- can use variables here
    move(self.speed) -- the self parameter is passed because we declared the function with a :
end

It does mean that you have to specify variables separately from functions, not sure how much I like that. But it's up to you smile

32

(64 replies, posted in Plugins)

I haven't got around to testing the getClone yet, I'll look into that next.

Oh, and the extended MScriptableBehaviour needs MScriptExt to be updated for it to work too. I think I will add versioning into the MResource so it won't try to work (and fail painfully) with previous versions.

33

(64 replies, posted in Plugins)

Right, sorry about the delay. I've checked up on the multiple scripts issue. I have an empty project that has three scripts in it, scripts/main.lua scripts/camera.lua and behaviors/camera.lua which, with the exception of main.lua (which also has a single dofile in it) all they do is print their own name. I have a cube with the camera behaviour added to it, and all 3 scripts print. I can't produce a crash at all.

Could you please zip up a sample that crashes for you please?

Edit: I also tried using the script you provided
Update: Updated MScriptableBehaviour to include extended lua API

34

(64 replies, posted in Plugins)

Right, something really weird is going on here. I've got some other work to deal with today, but after I'm done I'll look into it

35

(64 replies, posted in Plugins)

com3D wrote:

Even if scripts are put in 2 different folders (scripts & behaviors) and the script from scripts folder is not called with a dofile

Whaaaa? I have to admit that I didn't test this, but I didn't think it would be a problem because, I _thought_ it should default to looking in the scripts folder.

com3D wrote:

Then I did the same with a second new script (ZZZ_Nistur.lua) and it makes the editor crash again. If I remove the "_Nistur" then it works fine.

Curiouser and curiouser.

Right. I have some use cases to test out. I'll get back to you with this smile

In other news, I almost have the "extended" MScriptBehaviour working. I have the lua looking like it's working, but the problem is currently that the way I'm embedding the file doesn't null terminate the file, so I'm either going to have to pass a size through to MScript when loading it, or stick a 0 byte at the end. Neither of which are particularly difficult, I just need to decide which. Null terminating would make most sense perhaps, but if I can pass through the size, because I'm using luaL_loadbuffer rather than lua_dostring then it means that I can embed compiled lua scripts in release builds which means smaller executables and (in theory) faster loading times.

The way that the extended MScriptableBehaviour will work is as follows:

MScriptableBehaviour "player" {
    health = 10,
    onBegin = function()
        self.speed = 12
    end,

    update = function()
        move(self.speed)
        if hit then
            self.health = self.health - 1
        end
    end,

    onEnd = function()
    end,
}

The system no longer passes through the object or behaviour IDs. they are stored inside the behaviour and can be retrieved with self.__id.object and self.__id.behaviour The reason behind this is that they shouldn't be used eventually (of course, initially they will be) but I'm hoping that someone will take my code and extend the lua MScriptableBehaviour and add in wrappers for all of these in the embedded script so from a behaviour you could just do something such as

self:setScale({10, 10, 10})

and you wouldn't have to worry about the IDs at all.

Anyway, a few more tests before that one gets submitted, but the script is almost all there. Just need to get the file loading to work smile

36

(64 replies, posted in Plugins)

No, sorry. That's correct. I wrote the code on June 10th but just forgot to push to github until earlier today.

Also, I'm working on extending MScriptableBehaviour a little. Got a bit distracted today, but should have a more object-like way of dealing with behaviours very soon smile

37

(64 replies, posted in Plugins)

Oops, try again, I forgot to push the changes to github. onBegin was never being called. Sorry

Note: you can't currently use MScriptableBehaviour for multiple objects like this easily. But I had a thought, you could do something like this:

Script1_objects = {}
Script1 = {
    onBegin = function(object, behaviorID)
        Script1_objects[object] = {}
        Script1_objects[object].speed = 3
    end,

    update = function(object, behaviorID)
        -- do something with Script1_objects[object].speed
    end,
}

I'll try and make this a bit "friendlier" but right now there's not much else I can do

38

(46 replies, posted in General)

While working on the plugins recently, I was thinking that something which is missing from Maratis is an easy way to make popups. Game popups should be done using whatever UI solution is chosen for the main game UI, but in some situations it's both neater, and more reassuring to a user, to provide them with an OS popup.

The use case that I have for this is build a macro for asserts into Maratis which can in debug builds, display a popup which could in theory even trigger an interrupt (INT 3) to give a (possibly) relevant callstack to any attached debugger.

In theory my thoughts would be that it would look as follows:

char* assertOptions =
{
    "Ignore",
    "Break",
    NULL
};

void assertCallback(const char* button)
{
    if(strcmp(button, "Break") == 0)
        __asm int 3;
}

#ifdef DEBUG
# define MAssert(test, msg) \
    if(!(test)) \
        MEngine::getInstance()->displayPopup(msg, assertOptions, assertCallback);
#else/*!DEBUG*/
# define MAssert(test, msg) {}
#endif/*DEBUG*/

Note: not tested this code at all. Just a sample of how I'd imagine it working

39

(64 replies, posted in Plugins)

MScriptExt
link
Extensions to internal MScript system. Almost no changes have been made at this stage. The one enhancement is that, if run with MEvent it will send the event MScriptInit* which can be used by plugins to extend the lua environment by adding scripts after the base environment has been created but before the main script has been loaded.

*name not consistent with other events. Need to decide what to use

MEvent should now fire off "publish" which will be translated through to lua as "editor.publish". MScriptExt now has an editor script which should be automatically loaded and will allow the following:

local test_publish_event_function = function()
    print("test publish event function")
end

local test_publish_event_table =
{
    publish = function()
        print("test publish event function")
    end
}

editor.publish_event(test_publish_event_function)
editor.publish_event(test_publish_event_table)

Also, MScriptExt will search for all lua files within editor/ and load them (NOTE: currently this does this even when not running in editor, so it might be best to add if isEditor() then ... end around any editor scripts) This means that things such as publish events, which don't need to be published themselves, can be placed in editor scripts. Editor scripts can also be added to plugins to allow for flexibility to package their data however they see best.

Changelog
22.07.13 Added editor scripts and supported publish events
11.07.13 Updated to use luaL_loadbuffer within ::parse and added MResource interface

40

(64 replies, posted in Plugins)

com3D wrote:

Very excellent job ! Many thanks for sharing.

No problem smile I'm just hoping that other people can start adding to this list soon.

com3D wrote:

we can't pass variables from onBegin to update

Hrmmm, that's interesting. Can you send me a sample that shows this that I can test? I'm assuming it's something weird with how lua handles scopes. The behaviour doesn't actually have an object (and, therefore, data) associated with it. I haven't yet found how you can use more object oriented stuff when calling lua, although, now I have MScriptExt and embedded scripts working, I can relatively easily do this on the lua side I think...

com3D wrote:

I'll try MSaveFile asap and give you feedback.

MSaveFile is actually the only plugin that doesn't actually need Maratis, so I've added a small testsuite to it. This doesn't mean it's bug free by ANY means, but if you find any bugs, it'd be good to be able to reproduce this in the testsuite so we can make sure it doesn't happen again. I'll also try to add testsuites to the other plugins at some point maybe, but it will require stubbing out a lot of Maratis functionality to even get them to link.

com3D wrote:

PS: you should take holidays more often!

Haha. I actually did half of this stuff before my holiday, and half on the journey here. I've been doing this thing called "relaxing" this week mainly big_smile

As a slight aside, most of the plugins have two different build targets, a dynamic lib (so it can be used as a plugin directly) and a static lib which I am currently fiddling with linking into a über-lib, but would also (in theory) work for non-dynamic platforms, such as iOS. The plugins will have to be initialised/destroyed manually though from within the game

41

(64 replies, posted in Plugins)

MSaveFile
link
Simple save file system.

MSaveFile* save = NULL;
MSaveFileGetNew(save, "file.sav", M_SAVE_FILE_MODE_BINARY);
if(save)
{
    save->setInt("some.key", 1);
    save->setFloat("some.other.key", 44.32f);
    save->setString("some.other.other.key", "something");

    int valInt = 0;
    float valFloat = 0.0f;
    char valStr[256];
    save->getInt("some.key", valInt);
    save->getFloat("some.other.key", valFloat);
    save->getString("some.other.other.key", valStr);

    save->destroy();
}
save = saveFileOpen("file.sav", "M_SAVE_FILE_MODE_BINARY")
if save ~= nil then
    saveFileSetInt(save, "some.key", 1)
    saveFileSetFloat(save, "some.other.key", 44.32)
    saveFileSetString(save, "some.other.other.key", "something")

    valInt = saveFileGetInt(save, "some.key")
    valFloat = saveFileGetFloat(save, "some.other.key")
    valString = saveFileGetString(save, "some.other.other.key")

    saveFileClose(save)
end

The file will automatically be loaded when opened and saved when closed. You can force save/loading by using MSaveFile::save/MSaveFile::load or saveFileSave/saveFileLoad
The mode must be specified when the save file is opened. The choices are:
M_SAVE_FILE_MODE_TEXT - will save in text (XML) format
M_SAVE_FILE_MODE_BINARY - will save in binary fomat
M_SAVE_FILE_MODE_ANY - will save in the existing format, or binary if no file exists
Specifying the mode will not affect loading the save file, it is possible to open an XML savefile with M_SAVE_FILE_MODE_BINARY and vice versa. When the file is saved the next time it will be overwritten with the specified format.

Optional libraries: MEvent, MScriptExt
MSaveFile contains embedded lua which it can add to the lua environment if the project contains both MEvent and MScriptExt plugins. It extends the lua functionality.

save = MSaveFile("file.sav")

save:setInt("some.key", 1)
save:setFloat("some.other.key", 44.32)
save:setString("some.other.other.key", "something")

valInt = save:getInt("some.key")
valFloat = save:getFloat("some.other.key")
valString = save:getString("some.other.other.key")

save:close()

Note: you can also use save:set which will allow you to pass any object, if it's a number or a string, it will save it directly as above, but can also save any table by looping recursively through its children. There is no matching working get function as MSaveFile doesn't yet allow iterating through the values

TODO:

  • Give a default directory to save in

  • Serialise tables in/out in lua

  • Add savefile versioning

  • Change flat binary files into hierarchical ones

42

(64 replies, posted in Plugins)

MScriptableBehaviour
link
Creating behaviours from within lua. Create a behaviors folder within the project and add scripts within that. Inside the script needs to be a table with the same name as the script. They can have the following functions: onBegin, update, onEnd

eg player.lua

player = {
    onBegin = function(obj, bh)
    end,
    update = function(obj, bh)
    end,
    onEnd = function(obj, bh)
    end,
}

obj - the object reference for passing to any of the standard Maratis lua functions
bh - behaviour ID for use with the standard Maratis lua functions (right now, useless)

Optional libraries: MEvent, MScriptExt
If MEvent and MScriptExt plugins are also included in a project with MScriptableBehaviour, a more object oriented API is available:

MScriptableBehavior "player" {
    speed = 3,

    onBegin = function(self)
    end,

    update = function(self)
        -- do something with self.speed
    end,

    onEnd = function(self)
    end,
}

Using this, each object has instance variables (within self) and if required, the object ID can be accessed by self.__id.object

TODO:

  • Don't load the script once per instance using it

  • Expose variables between lua and C++ (so that lua variables show up in the editor)

Changelog
11.07.13 - Added embedded lua for extended API

43

(64 replies, posted in Plugins)

MEvent
link
Simple message system for use in Maratis. Overrides MGame so no other "games" can be added, but will send the following messages:
update - when the game gets an update call
lateUpdate - after the game has finished updating
preRender - before the game draws anything each frame
render - during the frame drawing
postRender - after everything else has drawn

To get the messages, create a class that inherits from MEventListener and use the MEventListenerDeclare macro. The event listener should implement void onEvent(const char*). Event listeners will not be fired in a fixed order, so you cannot guarantee which object will receive postRender first.

To broadcast messages, use:

MEventSend("SomeMessage")

TODO:

  • Change events to support ints/enums for faster checking

  • Lua support

  • Allow filtering of events so not every object gets every message

  • Support multiple broadcasters maybe?

Changelog
09.07.2013 - Fixed MEventListener so you can actually link to it properly

44

(64 replies, posted in Plugins)

I figured that it would be a good idea to move the plugin discussion here. These plugins currently only work on the Github branch but I'm going to polish up the plugin system and commit it to the official repository soon.

I'll update this post with any new plugins I add, or anyone else wishes me to add here

MEvent Nistur
description
Requirements - none
Optional - none

MScriptableBehaviour Nistur
description
Requirements - none
Optional - MEvent, MScriptExt

MSaveFile Nistur
description
Requirements - none
Optional - MEvent, MScriptExt

MScriptExt Nistur*
description
Requirements - none
Optional - MEvent

MRecast Nistur
description
Requirements - none
Optional - none

MEmbedFile Nistur
description
Requirements - none
Optional - none

*extension of Maratis internal functionality written by Anaël

45

(46 replies, posted in General)

com3D wrote:

we can later expose options/variables in the editor to fine-tweak the behavior

The point I was trying to make was that the "clickable" behaviour was simple and quite generic, but the reaction was not necessarily so easy. As Anaël said though, a linear move is simple enough. Neither the click detection nor the response need any more code, but I agree, it would be the kind of thing that is pretty much generic enough to add built in support for this.

com3D wrote:

Procedural animation is really exciting stuff.
There are some sources in C provided in the archive file, are they for the editor only?

I would go so far as to say procedural anything is exciting. Most of it isn't necessarily useful for release (some is, of course) but it can be a great way to quickly create huge amounts of content with relatively small amounts of effort. There's also the great feature that it would allow people with little to no artistic skill (like me) to create things that are at least vaguely acceptable to populate a game, if the procedural assets then get saved using a standard asset system, artists can then go in and replace the assets, knowing the correct scale, format etc to get dropped into the game and "just work"

46

(46 replies, posted in General)

Ok, that makes sense. I still think that for 2D systems we shouldn't bed to do any raycasts at all. We should look into exposing MGui and using mouse positions, or use a different GUI solution.

With regards to the point and click. The two use cases you gave seem similar but are quite different. They would both use a raycast to find where to move to, but then one relies on path finding, the other just does a simple lerp. Might be worth looking into making a clickable behaviour but then the reaction would have to be bespoke, or at best different for your use cases.

47

(46 replies, posted in General)

After yet more thoughts, I've had a couple more ideas. Still nothing final, just a few more things to throw into the mix.

I've been looking into the libs and tools made by Eskil Steenberg during the development of his semi-mmo game Love. Much as I said that it might be best to wait until MGui has been updated, it might be interesting to make a plugin for his "Seduce" GUI system. I realise this does OpenGL rendering directly internally but as the majority of Maratis rendering is done using OpenGL, and ones that don't (ie. iOS) don't support plugins yet anyway, I don't think this is a huge issue Another thing would be to see whether we could leverage the verse support and hook it into the Maratis asset system which would not only get Maratis an asset server system, but also in theory we could then have a more direct connection with all the tools that support the verse protocol. There's also the pretty interesting animation system but I think, as that's a standalone application right now, hooking that up might prove more difficult.

48

(46 replies, posted in General)

I've had a think about what you've suggested.

Firstly, I don't really understand what you mean about physics for scene layers. Regarding menus though, I think we should wait to see what can be done with the revamped MGui before trying to do something else along the same lines.

Fullscreen lua function should be pretty simple I believe. I don't see any problem with this.

Point and click, you mean... 3D picking? Like selection in the editor?

Path finding, I think would be best to put this functionality into a plugin rather than having it in the engine itself. I was thinking that Recast might be a good choice for this. We used it successfully for a mobile project a while back. I can look into this if people are interested...

49

(46 replies, posted in General)

com3D wrote:

Great news for us !

No promises, I'm going to visit my family-in-law. But I don't imagine I can survive 3 weeks without coding so there should be some progress.

I'll have a look at the wish list, but I definitely don't want to step on Anael's toes with regard to things like the the revamped GUI system. The stuff that wasn't mentioned by Anael are predominantly documentation work. I will try to look into updating the wiki, but it doesn't quite have the required things needed to satisfy my code withdrawal symptoms tongue

Anyway, if you have any requests to have their feasibility tested in the community repository, give me a shout. Oh, and feel free to stick issues into github if anyone finds bugs, I'll probably forget about them otherwise smile

50

(46 replies, posted in General)

anael wrote:

It just cannot work with a portable oriented virtual system,
a complex implementation will require handling with lua natively,
you will need the lua state to do complex thing.

I don't think I understand what you mean by this. I realise that the cloning and rings support in lua is a fairly intensive solution, I'm just throwing ideas out to see if anything makes sense to try to make the engine more extensible.

anael wrote:

The only solution I see would be for example to make MScriptContext a dynamic library that can be accessed directly
(or let's say a Common with also bulletContext and few other major implementations)
so the lua context could be used natively.

I don't see why Common needs to be exposed at all. MEngine::setScriptContext can be accessed outside of Maratis/MaratisPlayer, so, for example, an extended MScript plugin can, on plugin start, replace the MScriptContext within MEngine. If the extended context uses the MResource system, it means you can then access it from within, say, the MSaveFile plugin, doing something as follows

MScriptExtended* script = MScriptExtendedGet(); // this is a macro similar to the MSaveFileGetNew
if(script)
    script->addInitEnvironmentCallback(loadScripts);
//...
void loadScripts()
{
    // this would only be called if we're using MScriptExtended
     MScriptExtended* script = (MScriptExtended*)MEngine::getInstance()->getScriptContext();
    if(script)
        script->parse(embeddedScript);
}

As long as this is documented so developers know of this, that means that you can have a standard 'C-like' interface using the standard MScript, and just allow extended features if the extended script plugin is being used.

anael wrote:

But this is a big structure modification, so it need to be planned carefully,
there is things to go before and validated/tested step by step

I totally agree, that is why I wanted to put some suggestions out there so we can decide on the best solution going forward