Jump to content

Plugins in Leadwerks Game Engine 5


Josh

16,919 views

 Share

Internally, Leadwerks Editor uses an EventHandler class for every interface in the program. The material editor is a class extended from the EventHandler. So is the little window that has all the controls to calculate normals. So is every viewport.

The event handler class has one important function:

Event ProcessEvent(Event)

Every EventHandler has access to events as they occur. This is how all program actions are handled in the editor.

The plugin system will work by hooking into the event system. Each plugin will have a Lua script that receive events before the rest of the program sees them:

function Script:ProcessEvent(event)
	return event
end

If the plugin makes no changes to the event then it simply returns the original event. The returned event is then sent to other event handlers.

Here is an example of a plugin that would disable the close window button on the main window. Because the function returns nil the event is discarded before the main window ever evaluates it:

function Script:ProcessEvent(event)
	if event.id == EVENT_WINDOWCLOSE and event.source == editor.mainwindow then
		return nil
	else
		return event
	end
end

Here is an example of a very mean plugin that would make it so that clicking the File > Open menu item in the main window quits the program:

function Script:ProcessEvent(event)
	if event.id == EVENT_MENUEVENT then
		if event.source == editor.mainwindow then
			if event.extra == MENU_FILEOPEN then
				event.id = EVENT_WINDOWCLOSE
			end
		end
	end
  	return event
end

Okay, now let's see if we can design a plugin for something people would actually want. Let's imagine we have a new visual material design system. The exact details of how it works are not important, it's just a system that overrides the default material editor. The design system would require materials to have a special file associated with them with the extension .DESIGN. If you open the material "brick.mat" we will look for a file in the same folder called "brick.design". If the design file is found we open the material in our special editor. If the design file is missing we will just fall back to the default material editor.

Now let's see how our system can handle this:

function Script:Start()
	
	--Create our interface
	self.window = CreateWindow("Material Designer",0,0,800,600,editor.mainwindow,WINDOW_CENTER + WINDOW_TITLEBAR + WINDOW_RESIZABLE)
	
end

function Script:ProcessEvent(event)
	if event.id == EVENT_FILEOPEN

		--Check for material files being opened
		if ExtractExt(event.extra)=="mat"
      
			--Look for design file
			local designfilename = StripExt(event.extra).".design"
			if FileType( designfilename ) == 1 then
				
				--Load the design file
				local stream = ReadFile(designfilename)
				if stream ~= nil then
					
					--Display our custom material editor
					self.window:Show()
					self.window:Activate()

				else
          
					Print("Error: Failed to load design file.")
            
				end
				
				--Discard the event
				return nil
			end
		end
	end
	return event
end

As you can see, this approach is extremely powerful. The event IDs and design rarely change, if ever, so this allows a lot of flexibility and at the same time gives us the optimal compatibility as changes are made to the core editor. With this approach to plugins you can literally do anything you want in the editor.

  • Like 4
  • Thanks 1
  • Upvote 1
 Share

52 Comments


Recommended Comments



I had two solutions in mind. One would be a comment above the function that hints at what type of object each parameter should be. The other is to simply say that if the variable name contains a class name in the left-most characters, it is assumed to be of that type. This would work for variables called "entity", "world", as well as "texture2", "entity_test", etc.

The other part of this would be a static analysis routine that can figure out types based on the code:

local a = LoadModel("blahblah.mdl")
a:SetP... --we know this is a Model object!

The problem is people don't know what functions belong to what classes. I have watched a beginner struggle trying to call joint methods on an entity and not understanding what functions he could use.

This is why I floated the idea of a procedural API for Lua:
https://www.leadwerks.com/community/topic/17134-procedural-script-api/

  • Like 1
Link to comment

There are always ways to hack in types to a typeless language. As long as they aren't mandatory please.

 

 

  • Like 1
Link to comment
1 hour ago, Josh said:

One would be a comment above the function that hints at what type of object each parameter should be.

That actually doesn't sound bad. For the Leadwerks API that could result in something like this. People can use this for their own functions too, but it is not mandatory.

--pos, A vector 3 position
--global, boolean that detemines global=true or local=false 
SetPosition(pos, global)

 

1 hour ago, Josh said:

This would work for variables called "entity", "world", as well as "texture2", "entity_test", etc.

This gives me bad memories to an internship were every variable was prefixed with the datatype: (integer) i_myVar, (string)s_myVar. I personally find this really ugly. 

 

1 hour ago, Josh said:

The other part of this would be a static analysis routine that can figure out types based on the code:

That is how I did it in my post. Funny to see you would do something similar.

  • Like 1
Link to comment

I tried LuaCheck but I don't think it's very useful. It just gives a lot of confusing messages about unused variables and such, but it doesn't really do anything with object types. It's kind of cool and can prevent some problems but it's not extensive.

Link to comment

We need the following:

  • Export C++ classes to virtual machine.
  • Autocompletion / linting in IDE with recognition of the Leadwerks C++ classes.
  • Debugging.

This could be done through an external IDE or our own built-in one. I will definitely listen to any suggestions you guys have on how to achieve this. I want it to be really good.

Link to comment


Here is visual studio code with .nut files. (great extension name). A downside is the documentation part. Squirrel is not very well known it seems, despite being used in several big games.

image.thumb.png.71877fc84917b9a3bb8889762c220722.png

Link to comment

The most appealing thing to me is Squirrel was designed for exactly what we want to do, and the Lua people act like connecting with C++ classes is just sort of a detail they don't care about. I think this will play nicely with smart pointers but we need to do more research on this.

Link to comment

I’ll have to read up on that language but it’s a big decision to switch scripting languages. I would support both for a version on le before totally switching. For me the big thing will be coroutines and not being so rigid on types as that makes coding gameplay more challenging to overcome. 

Link to comment

Looks like it has coroutines! Having "true" classes as well! I'm all in, but I'm sure others might not be so thrilled.

Link to comment
1 hour ago, AggrorJorn said:

Looks like VS code is build on top of Atom. Looking at their repo https://atom.io/ it looks pretty customisable too.

As far as I know, VS code is not directly built on top of Atom. Both, however, depend on the Electron framework (https://electronjs.org/) for rendering and thus are mainly written in JS. From my experience, both are quite good editors but both are quite heavyweight. Compared to Sublime Text (which is clearly what the devs took as their inspiration, but which unfortunately is not free), they lack somewhat in responsiveness. This comes from both being JS-applications, while Sublime Text is a native application. This also reflects in the sizes with 300 MB and 200 MB vs 30 MB.

 

With that being said, I would go for VS code, since it seems more responsive than Atom and does weight less. In terms of features, both should be pretty equal and both are cross platform and open source.

  • Like 1
Link to comment

Ha! Electron is the same as Node Webkit (nw.js) which is what I said some time back was the future of writing desktop apps and here it is. Major company using it to create their IDE. I knew that was the way to go. The web stack is just an easier way to get cross platform desktop apps with better UI's. Nice to see that idea taking off. 

Link to comment
5 hours ago, Josh said:

I am also considering the Squirrel script language. It's like a cross between Lua and C++:
http://www.squirrel-lang.org/

Valve is using it for a lot of their games.

Why not python?

  • Large library set.
  • Used in physics (Sells of Leadwerks Enterprise)
  • Easy to learn
  • Supports OOP or static methods.
  • Easy integration with existing C++ library. http://www.swig.org/tutorial.html
  • Ability to pre-compile scripting code.
  • Upvote 1
Link to comment

I personally dislike Python BUT anything that uses swig to create the bindings would be the way to go so it's easier to create bindings for any language in my view. Python wouldn't be the worst decision though.

Link to comment

If you're going Squirrel, you're better off with Python... why settle for Squirrel when it's a worse version of the same thing? (Granted it is more light-weight) I think the Squirrel syntax is ugly relative to Lua or Python.

I just personally love Lua because it is really, really fast and communication with C is extremely easy.

It seems unnecessary to change something like the languages scripting language solely for the autocomplete feature. Plus could you not do a hack where you just execute the Lua file, silently ignoring errors all the time and then generate auto-complete info based on object's metatable which contains all t's methods and members. I feel like you could find a sloppy way to make this work using a separate Lua state... might not be the easiest solution, but likely easier than changing languages entirely.

Link to comment

From what I've seen with Squirrel you can basically use it like lua. It has the same idea of tables like Lua, but it also has the C++ like syntax.

Link to comment
16 minutes ago, Rick said:

From what I've seen with Squirrel you can basically use it like lua. It has the same idea of tables like Lua, but it also has the C++ like syntax.

Yeah, but it doesn't have nil... so if you do something like access an out-of-range table element, instead of returning nil it will raise an exception... having nil is also what I rely on for my Lua callback system in my engine (although null might be distinguishable from false on the stack in Squirrel too).

Squirrel looks like its come a long way since I last saw it, so I take back what i said. I'd go with Squirrel over Python. Still though, that's a big change for not a big difference. Not to mention I'm not seeing it being any easier for an auto-complete feature than Lua? You won't be creating your C++ classes in Squirrel, you'll be exposing them with t he stack, so it's not like you can parse the code files for auto-completion. If a switch has to be done thought Squirrel looks sweet.

Link to comment

Guest
Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...