5
\$\begingroup\$

I'm developing with Unity 5 and I know that there are some methods you can use like in the code below:

public class MyGameElement : MonoBehaviour 
{
    private void Awake() { }
    private void Start() { }
    private void Update() { }
    private void FixedUpdate() { }
    // and more
}

I know what they do but I find it strange that the methods can be private. However they are not called into my code I've written. Here you've an image with code lens (I use VS 2015 Professional for coding) where you can really see that it has zero references.

0 references: private void awake / 0 references private void FixedUpdate

The second 'strange' thing for me is that the methods aren't overwritten.

So my question is now is there anything that Unity has implemented into the MonoBehaviour class that the methods can call?

\$\endgroup\$
3

3 Answers 3

6
\$\begingroup\$

The methods you name are called with Unity's Messaging System. The MonoBehaviour responds to messages when recieved. Messages are sent by Unity when those events are triggered. The methods you implement, can be private, because technically, it's the Component invoking its own methods, in response to receiving a message.

I don't know if Unity implements a different internal message system from the one exposed in the API, but I doubt it.

In the docs, notice all those 'magic methods' are actually in the 'Messages' section of the MonoBehavior.

There is a nice description on Stackoverflow and more info is available in the Component.SendMessage doc.

\$\endgroup\$
1
2
\$\begingroup\$

This would be relatively trivial to perform from the mono runtime. The unity scripts are bundled into the Assembly-UnityScript.dll .NET assembly. When this is loaded by the mono runtime, options are available.

mono_set_dirs( "/Library/Frameworks/Mono.framework/Home/lib", "/Library/Frameworks/Mono.framework/Home/etc" );
mono_config_parse( nullptr );
const char* managedbinarypath = "C:/Assembly-UnityScript.dll";
MonoDomain* domain = mono_jit_init(managedbinarypath)
MonoAssembly* assembly = mono_domain_assembly_open (domain, managedbinarypath);
MonoImage* image = mono_assembly_get_image (assembly);

//you could add some internal call bindings and field bindings
mono_add_internal_call( "Namespace.Class::Method", reinterpret_cast<void*>(InternalFunction));
class = mono_class_from_name( image, "Namespace", "Class" );
native_handle_field = mono_class_get_field_from_name(class, "FieldInClass" );

//you could invoke the Main method of the Main class if it exists
MonoClass* main_class = mono_class_from_name( image, "Namespace", "MainClass" );
const bool include_namespace = true;
MonoMethodDesc* entry_point_method_desc = mono_method_desc_new("Namespace.MainClass:EntryPointMethod()", include_namespace );
MonoMethod* entry_point_method = mono_method_desc_search_in_class( entry_point_method_desc, main_class );
mono_method_desc_free( entry_point_method_desc );
mono_runtime_invoke( entry_point_method, nullptr, nullptr, nullptr );

//alternatively, you could invoke an Update method
void* iter = NULL;
MonoClass* class;
MonoMethodDesc* desc;
MonoMethod* method;
while(class = mono_image_get_classes(image, &iter))
{
    //if the class has an Update method
    desc =  mono_method_desc_new("*:Update()", false);
    method = mono_method_desc_search_in_class(desc, class);
    if (method != NULL){
        //store MonoMethod* method in array somewhere

    }
    mono_method_desc_free(desc);
}

//traverse array of update methods sometime and invoke them
mono_runtime_invoke(array[0], nullptr, nullptr, nullptr);


//finish
mono_jit_cleanup( domain );

Where mono_image_get_classes is defined:

MonoClass*
mono_image_get_classes (MonoImage *image, gpointer *iter)
{
    int num_types;
    int *index;

    if (!iter)
        return NULL;

    index = (int *) iter;

    /* skip the <Module> */
    if (!*index)
        *index = 1;

    num_types = mono_image_get_table_rows (image, MONO_TABLE_TYPEDEF);

    if (*index < num_types) {
        (*index)++;
        return mono_class_get (image, *index | MONO_TOKEN_TYPE_DEF);
    } else {
        *index = 0;
        return NULL;
    }
}
```
\$\endgroup\$
1
\$\begingroup\$

They are internal event handler methods. The engine probably calls them via Invoke("Method") though I am not sure on the internal implementation.

The important thing is that they are named exactly and that the script inherits MonoBehaviour.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .