Skip to content

Commit 4ff80df

Browse files
Add support for MonoBehaviour classes and their messages to the code generator
Add basic support for generic method return values to the code generator Remove MonoBehaviourUpdate and PluginUpdate Add a version Add README sections for features, performance, JSON configuration, and contributing
1 parent 815521f commit 4ff80df

11 files changed

Lines changed: 1611 additions & 374 deletions

File tree

README.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,34 @@ While IL2CPP transforms C# into C++ already, it generates a lot of overhead. The
2626

2727
This project aims to give you a viable alternative to C#. Scripting in C++ isn't right for every project, but now it's an option.
2828

29+
# Features
30+
31+
* Object-oriented API just like in C#
32+
33+
>
34+
GameObject go;
35+
Transform transform = go.GetTransform();
36+
Vector3 position(1.0f, 2.0f, 3.0f);
37+
transform.SetPosition(position);
38+
39+
* No need to reload the Unity editor when changing C++
40+
* Code generator exposes any C# API (Unity, .NET, custom DLLs) with a simple JSON config file
41+
* Handle `MonoBehaviour` messages in C++
42+
43+
>
44+
void MyScript::Start()
45+
{
46+
Debug::Log(String("MyScript has started"));
47+
}
48+
49+
* [CMake](https://cmake.org/) build system sets up any IDE project or command-line build
50+
51+
# Performance
52+
53+
[Article](http://jacksondunstan.com/articles/3952).
54+
55+
tl;dr - Most projects will not be noticeably impacted by C++ overhead and many projects will benefit from reducing garbage collection and IL2CPP overhead.
56+
2957
# Project Structure
3058

3159
When scripting in C++, C# is used only as a "binding" layer so Unity can call C++ functions and C++ functions can call the Unity API. A code generator is used to generate most of these bindings according to the needs of your project.
@@ -101,6 +129,49 @@ There's nothing to do for iOS!
101129
6. The build scripts or IDE project files are now generated in your build directory
102130
7. Build as appropriate for your generator. For example, execute `make` if you chose `Unix Makefiles` as your generator.
103131

132+
# Configuring the Code Generator
133+
134+
Open `NativeScriptTypes.json` and notice the existing examples. Add on to this file to expose more C# APIs from Unity, .NET, or custom DLLs to your C++ code.
135+
136+
The code generator supports:
137+
138+
* Class types (i.e. Classes with methods, etc. Parameters, etc. are fine.)
139+
* Constructors
140+
* Methods
141+
* Fields
142+
* Properties (getters and setters)
143+
* Generic return types
144+
* `MonoBehaviour` classes with "message" functions (except `OnAudioFilterRead`)
145+
146+
The code generator does not support (yet):
147+
148+
* Struct types
149+
* Arrays (single- or multi-dimensional)
150+
* Generic functions and types
151+
* `out` and `ref` parameters
152+
* Delegates
153+
* `MonoBehaviour` contents (e.g. fields) except for "message" functions
154+
155+
The JSON file is laid out as follows:
156+
157+
* Path - Absolute path to the DLL
158+
* Types - Array of types in the DLL to generate
159+
* Name - Name of the type including namespace (e.g. `UnityEngine.GameObject`)
160+
* Constructors - Array of constructors to generate
161+
* Types - Parameter types of the constructor including namespace
162+
* Methods - Array of methods to generate
163+
* Name - Name of the method
164+
* ParamTypes - Parameter types to the method including namespace
165+
* GenericTypes - Sets of type parameters to generate
166+
* Name - Name of the type parameter (e.g. `T`)
167+
* Type - Type to generate for the type parameter including namespace
168+
* Properties - Array of property names to generate
169+
* Fields - Array of field names to generate
170+
* MonoBehaviours
171+
* Name - Name of the `MonoBehaviour` class to generate
172+
* Namespace - Namespace to put the `MonoBehaviour` class in
173+
* Messages - Array of message names to generate (e.g. `Update`)
174+
104175
# Updating To A New Version
105176

106177
To update to a new version of this project, overwrite your Unity project's `Assets/NativeScript` directory with this project's `Unity/Assets/NativeScript` directory.
@@ -113,6 +184,10 @@ To update to a new version of this project, overwrite your Unity project's `Asse
113184

114185
[Jackson Dunstan](http://jacksondunstan.com)
115186

187+
# Contributing
188+
189+
Please feel free to fork and send [pull requests](https://github.com/jacksondunstan/UnityNativeScripting/pulls) or simply submit an [issue](https://github.com/jacksondunstan/UnityNativeScripting/issues) for features or bug fixes.
190+
116191
# License
117192

118193
All code is licensed [MIT](https://opensource.org/licenses/MIT), which means it can usually be easily used in commercial and non-commercial applications.

Unity/Assets/CppSource/Game.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,26 @@ using namespace UnityEngine;
1717
void PluginMain()
1818
{
1919
Debug::Log(String("Game booted up"));
20+
GameObject go(String("GameObject with a TestScript"));
21+
go.AddComponent<MyGame::MonoBehaviours::TestScript>();
2022
}
2123

22-
// Called for MonoBehaviour.Update
23-
void PluginUpdate()
24+
void MyGame::MonoBehaviours::TestScript::Awake()
25+
{
26+
Debug::Log(String("C++ TestScript Awake"));
27+
}
28+
29+
void MyGame::MonoBehaviours::TestScript::OnAnimatorIK(int32_t param0)
30+
{
31+
Debug::Log(String("C++ TestScript OnAnimatorIK"));
32+
}
33+
34+
void MyGame::MonoBehaviours::TestScript::OnCollisionEnter(UnityEngine::Collision param0)
35+
{
36+
Debug::Log(String("C++ TestScript OnCollisionEnter"));
37+
}
38+
39+
void MyGame::MonoBehaviours::TestScript::Update()
2440
{
2541
static int32_t numCreated = 0;
2642
if (numCreated < 10)

Unity/Assets/NativeScript/Bindings.cpp

Lines changed: 68 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -43,33 +43,21 @@ namespace Plugin
4343

4444
/*BEGIN FUNCTION POINTERS*/
4545
int32_t (*StopwatchConstructor)();
46-
4746
int64_t (*StopwatchPropertyGetElapsedMilliseconds)(int32_t thisHandle);
48-
4947
void (*StopwatchMethodStart)(int32_t thisHandle);
50-
5148
void (*StopwatchMethodReset)(int32_t thisHandle);
52-
5349
int32_t (*ObjectPropertyGetName)(int32_t thisHandle);
54-
5550
void (*ObjectPropertySetName)(int32_t thisHandle, int32_t valueHandle);
56-
5751
int32_t (*GameObjectConstructor)();
58-
52+
int32_t (*GameObjectConstructorSystemString)(int32_t nameHandle);
5953
int32_t (*GameObjectPropertyGetTransform)(int32_t thisHandle);
60-
6154
int32_t (*GameObjectMethodFindSystemString)(int32_t nameHandle);
62-
55+
int32_t (*GameObjectMethodAddComponentMyGameMonoBehavioursTestScript)(int32_t thisHandle);
6356
int32_t (*ComponentPropertyGetTransform)(int32_t thisHandle);
64-
6557
UnityEngine::Vector3 (*TransformPropertyGetPosition)(int32_t thisHandle);
66-
6758
void (*TransformPropertySetPosition)(int32_t thisHandle, UnityEngine::Vector3 value);
68-
6959
void (*DebugMethodLogSystemObject)(int32_t messageHandle);
70-
7160
System::Boolean (*AssertFieldGetRaiseExceptions)();
72-
7361
void (*AssertFieldSetRaiseExceptions)(System::Boolean value);
7462
/*END FUNCTION POINTERS*/
7563
}
@@ -185,9 +173,9 @@ namespace System
185173

186174
Stopwatch::Stopwatch()
187175
: Stopwatch(Stopwatch(Plugin::StopwatchConstructor()))
188-
{
189-
}
190-
176+
{
177+
}
178+
191179
int64_t Stopwatch::GetElapsedMilliseconds()
192180
{
193181
return Plugin::StopwatchPropertyGetElapsedMilliseconds(Handle);
@@ -229,6 +217,11 @@ namespace UnityEngine
229217
{
230218
}
231219

220+
GameObject::GameObject(System::String name)
221+
: GameObject(GameObject(Plugin::GameObjectConstructorSystemString(name.Handle)))
222+
{
223+
}
224+
232225
UnityEngine::Transform GameObject::GetTransform()
233226
{
234227
return UnityEngine::Transform(Plugin::GameObjectPropertyGetTransform(Handle));
@@ -238,6 +231,11 @@ namespace UnityEngine
238231
{
239232
return UnityEngine::GameObject(Plugin::GameObjectMethodFindSystemString(name.Handle));
240233
}
234+
235+
template<> MyGame::MonoBehaviours::TestScript GameObject::AddComponent<MyGame::MonoBehaviours::TestScript>()
236+
{
237+
return MyGame::MonoBehaviours::TestScript(Plugin::GameObjectMethodAddComponentMyGameMonoBehavioursTestScript(Handle));
238+
}
241239
}
242240

243241
namespace UnityEngine
@@ -290,6 +288,29 @@ namespace UnityEngine
290288
}
291289
}
292290
}
291+
292+
namespace UnityEngine
293+
{
294+
SYSTEM_OBJECT_LIFECYCLE_DEFINITION(Collision, System::Object)
295+
}
296+
297+
namespace UnityEngine
298+
{
299+
SYSTEM_OBJECT_LIFECYCLE_DEFINITION(Behaviour, UnityEngine::Component)
300+
}
301+
302+
namespace UnityEngine
303+
{
304+
SYSTEM_OBJECT_LIFECYCLE_DEFINITION(MonoBehaviour, UnityEngine::Behaviour)
305+
}
306+
307+
namespace MyGame
308+
{
309+
namespace MonoBehaviours
310+
{
311+
SYSTEM_OBJECT_LIFECYCLE_DEFINITION(TestScript, UnityEngine::MonoBehaviour)
312+
}
313+
}
293314
/*END METHOD DEFINITIONS*/
294315

295316
////////////////////////////////////////////////////////////////
@@ -299,20 +320,15 @@ namespace UnityEngine
299320
// Called when the plugin is initialized
300321
extern void PluginMain();
301322

302-
// Called for MonoBehaviour.Update
303-
extern void PluginUpdate();
304-
305323
////////////////////////////////////////////////////////////////
306324
// C++ functions for C# to call
307325
////////////////////////////////////////////////////////////////
308326

309327
// Init the plugin
310328
DLLEXPORT void Init(
311329
int32_t maxManagedObjects,
312-
void (*releaseObject)(
313-
int32_t handle),
314-
int32_t (*stringNew)(
315-
const char* chars),
330+
void (*releaseObject)(int32_t handle),
331+
int32_t (*stringNew)(const char* chars),
316332
/*BEGIN INIT PARAMS*/
317333
int32_t (*stopwatchConstructor)(),
318334
int64_t (*stopwatchPropertyGetElapsedMilliseconds)(int32_t thisHandle),
@@ -321,8 +337,10 @@ DLLEXPORT void Init(
321337
int32_t (*objectPropertyGetName)(int32_t thisHandle),
322338
void (*objectPropertySetName)(int32_t thisHandle, int32_t valueHandle),
323339
int32_t (*gameObjectConstructor)(),
340+
int32_t (*gameObjectConstructorSystemString)(int32_t nameHandle),
324341
int32_t (*gameObjectPropertyGetTransform)(int32_t thisHandle),
325342
int32_t (*gameObjectMethodFindSystemString)(int32_t nameHandle),
343+
int32_t (*gameObjectMethodAddComponentMyGameMonoBehavioursTestScript)(int32_t thisHandle),
326344
int32_t (*componentPropertyGetTransform)(int32_t thisHandle),
327345
UnityEngine::Vector3 (*transformPropertyGetPosition)(int32_t thisHandle),
328346
void (*transformPropertySetPosition)(int32_t thisHandle, UnityEngine::Vector3 value),
@@ -350,8 +368,10 @@ DLLEXPORT void Init(
350368
ObjectPropertyGetName = objectPropertyGetName;
351369
ObjectPropertySetName = objectPropertySetName;
352370
GameObjectConstructor = gameObjectConstructor;
371+
GameObjectConstructorSystemString = gameObjectConstructorSystemString;
353372
GameObjectPropertyGetTransform = gameObjectPropertyGetTransform;
354373
GameObjectMethodFindSystemString = gameObjectMethodFindSystemString;
374+
GameObjectMethodAddComponentMyGameMonoBehavioursTestScript = gameObjectMethodAddComponentMyGameMonoBehavioursTestScript;
355375
ComponentPropertyGetTransform = componentPropertyGetTransform;
356376
TransformPropertyGetPosition = transformPropertyGetPosition;
357377
TransformPropertySetPosition = transformPropertySetPosition;
@@ -363,8 +383,29 @@ DLLEXPORT void Init(
363383
PluginMain();
364384
}
365385

366-
// Called by MonoBehaviour.Update
367-
DLLEXPORT void MonoBehaviourUpdate()
386+
/*BEGIN MONOBEHAVIOUR MESSAGES*/
387+
DLLEXPORT void TestScriptAwake(int32_t thisHandle)
388+
{
389+
MyGame::MonoBehaviours::TestScript thiz(thisHandle);
390+
thiz.Awake();
391+
}
392+
393+
DLLEXPORT void TestScriptOnAnimatorIK(int32_t thisHandle, int32_t param0)
394+
{
395+
MyGame::MonoBehaviours::TestScript thiz(thisHandle);
396+
thiz.OnAnimatorIK(param0);
397+
}
398+
399+
DLLEXPORT void TestScriptOnCollisionEnter(int32_t thisHandle, int32_t param0Handle)
400+
{
401+
MyGame::MonoBehaviours::TestScript thiz(thisHandle);
402+
UnityEngine::Collision param0(param0Handle);
403+
thiz.OnCollisionEnter(param0);
404+
}
405+
406+
DLLEXPORT void TestScriptUpdate(int32_t thisHandle)
368407
{
369-
PluginUpdate();
408+
MyGame::MonoBehaviours::TestScript thiz(thisHandle);
409+
thiz.Update();
370410
}
411+
/*END MONOBEHAVIOUR MESSAGES*/

0 commit comments

Comments
 (0)