BNM 2.5.0
 
Loading...
Searching...
No Matches
Example 06: Coroutine

It shows how to use coroutines.

#include <BNM/Coroutine.hpp>
#include <BNM/UnityStructures.hpp>
#include <BNM/ClassesManagement.hpp>
#include "BNM/Field.hpp"
#ifdef BNM_CLASSES_MANAGEMENT
#ifdef BNM_COROUTINE
// An example of custom instructions for IEnumerator. For example, let's make an analog of WaitForSecondsRealtime, but using std::chrono
struct CustomYieldInstruction : BNM::IL2CPP::Il2CppObject {
BNM_CustomClass(CustomYieldInstruction, BNM::CompileTimeClassBuilder(nullptr, BNM_OBFUSCATE_TMP("CustomYieldInstruction")).Build(), {}, {},
BNM::CompileTimeClassBuilder(BNM_OBFUSCATE_TMP("System.Collections"), BNM_OBFUSCATE_TMP("IEnumerator"), BNM_OBFUSCATE_TMP("mscorlib.dll")).Build());
std::chrono::time_point<std::chrono::system_clock> waitUntilTime;
void Finalize() { this->~CustomYieldInstruction(); }
bool MoveNext() { return waitUntilTime > std::chrono::system_clock::now(); }
void Reset() { waitUntilTime = {}; }
Il2CppObject *Current() { return nullptr; }
BNM_CustomMethod(Finalize, false, BNM::Defaults::Get<void>(), "Finalize");
BNM_CustomMethod(MoveNext, false, BNM::Defaults::Get<bool>(), "MoveNext");
BNM_CustomMethod(Reset, false, BNM::Defaults::Get<void>(), "Reset");
void Setup(long long seconds) {
Reset();
waitUntilTime = std::chrono::system_clock::now() + std::chrono::seconds(seconds);
}
static BNM::IL2CPP::Il2CppObject *New(long long seconds) {
auto instance = (CustomYieldInstruction *) BNM::Class(BNMCustomClass.myClass).CreateNewInstance();
instance->Setup(seconds);
return instance;
}
};
// IEnumerator Example
BNM::Coroutine::IEnumerator IEnumeratorExample() {
BNM_LOG_DEBUG("IEnumeratorExample 1");
// The code is very similar to the IEnumerator code in C#, it's just that instead of yield return, you need to use co_yield
BNM_LOG_DEBUG("IEnumeratorExample 2 (WaitForEndOfFrame)");
BNM_LOG_DEBUG("IEnumeratorExample 3 (WaitForFixedUpdate)");
BNM_LOG_DEBUG("IEnumeratorExample 4 (WaitForSeconds)");
BNM_LOG_DEBUG("IEnumeratorExample 5 (WaitForSecondsRealtime)");
co_yield CustomYieldInstruction::New(5);
BNM_LOG_DEBUG("IEnumeratorExample 6 (CustomYieldInstruction)");
// An analog of WaitWhile, but instead of il2cpp methods, it accepts C++ methods
co_yield BNM::Coroutine::WaitWhile([]() -> bool {
return thing->Alive();
});
BNM_LOG_DEBUG("'thing' мертва (dead) :_(");
// Unlike C#, it is necessary to call co_return at the end of the code
co_return;
}
BNM::Class GameObject;
BNM::Method<void *> StartCoroutine;
// Suppose there is such a class in the game
struct EnumeratorTests : public BNM::UnityEngine::MonoBehaviour {
BNM_CustomClass(EnumeratorTests, BNM::CompileTimeClassBuilder(nullptr, BNM_OBFUSCATE_TMP("EnumeratorTests")).Build(), {}, {});
void Start() {
// Creating an object for its subsequent destruction
thing = (BNM::UnityEngine::Object *) GameObject.CreateNewObjectParameters();
// You can get C# IEnumerator using .Get() or any method of casting to IEnumerator *
// BNM::Coroutine::IEnumerator *enumerator = IEnumeratorExample();
// auto enumerator = (BNM::Coroutine::IEnumerator *) IEnumeratorExample();
auto enumerator = IEnumeratorExample().Get();
auto r = StartCoroutine[this](enumerator);
BNM_LOG_DEBUG("Invoked: %p", r);
}
inline static int frames = 0;
void Update() {
frames++;
if (frames != 200) return;
BNM_LOG_DEBUG("Killing 'thing'");
Destory(thing);
}
BNM_CustomMethod(Start, false, BNM::Defaults::Get<void>(), "Start");
BNM_CustomMethod(Update, false, BNM::Defaults::Get<void>(), "Update");
};
void OnLoaded_Example_06() {
using namespace BNM;
auto coreModule = BNM::Image(BNM_OBFUSCATE("UnityEngine.CoreModule.dll"));
GameObject = BNM::Class(BNM_OBFUSCATE("UnityEngine"), BNM_OBFUSCATE("GameObject"), coreModule);
Destory = GameObject.GetParent().GetMethod(BNM_OBFUSCATE("Destroy"), 1);
StartCoroutine = BNM::Class(BNM_OBFUSCATE("UnityEngine"), BNM_OBFUSCATE("MonoBehaviour"), coreModule).GetMethod(BNM_OBFUSCATE("StartCoroutine"), {BNM_OBFUSCATE("routine")});
}
#endif // BNM_COROUTINE
#endif // BNM_CLASSES_MANAGEMENT
#define BNM_CustomMethod(_method_, _isStatic_, _type_, _name_,...)
Define info about C++ method for il2cpp.
Definition ClassesManagement.hpp:309
#define BNM_CustomClass(_class_, _targetType_, _baseType_, _owner_,...)
Define info of C++ class for il2cpp.
Definition ClassesManagement.hpp:250
#define BNM_CallCustomMethodOrigin(_method_,...)
Call method origin, if it exists.
Definition ClassesManagement.hpp:358
constexpr DefaultTypeRef Get()
Method that helps to get il2cpp class type from C++ and BNM types.
Definition Defaults.hpp:132
Main BNM namespace.
Definition BasicMonoStructures.hpp:16
Class for working with il2cpp classes.
Definition Class.hpp:29
BNM::MethodBase GetMethod(const std::string_view &name, int parameters=-1) const
Get method by name and parameters count.
BNM::IL2CPP::Il2CppObject * CreateNewObjectParameters(Parameters ...parameters) const
Create class instance.
Definition Method.hpp:127
BNM::Class GetParent() const
Get parent.
Struct for building CompileTimeClass.
Definition Class.hpp:639
CompileTimeClass Build()
Build CompileTimeClass.
Definition Class.hpp:715
Analog of C# IEnumerator that is based on C++20 coroutines to emulate work of Unity's coroutines.
Definition Coroutine.hpp:97
BNM's custom wrapper for UnityEngine.WaitForEndOfFrame.
Definition Coroutine.hpp:53
BNM's custom wrapper for UnityEngine.WaitForFixedUpdate.
Definition Coroutine.hpp:60
BNM's custom wrapper for UnityEngine.WaitForSecondsRealtime.
Definition Coroutine.hpp:74
BNM's custom wrapper for UnityEngine.WaitForSeconds.
Definition Coroutine.hpp:67
BNM's custom implementation of UnityEngine.WaitUntil.
Definition Coroutine.hpp:88
Class for working with il2cpp images.
Definition Image.hpp:19
Typed class for working with il2cpp methods.
Definition Method.hpp:20
UnityEngine.MonoBehaviour implementation.
Definition UnityStructures.hpp:72
UnityEngine.Object implementation.
Definition UnityStructures.hpp:33