When making C++ plugins in Unity it is easier to use Debug.Log
to quickly view variable values but this function is only available from C# side. This makes it very hard to debug C++ plugin since Unity's debugger does not support that. std::cout
is not an option since it doesn't show in the Editor.
I looked inside the Unity C++ API located at <UnityInstallationDirecory>\Editor\Data\PluginAPI
but didn't find anything about logging in the API.
Any suggestions on how to display in the Editor log from C++?
To view a debug log, from Setup, enter Debug Logs in the Quick Find box, then select Debug Logs. Then click View next to the debug log that you want to examine. Click Download to download the log as an XML file. Debug logs have the following limits.
Use Debug. Log to print informational messages that help you debug your application. For example, you could print a message containing a GameObject.name and information about the object's current state.
A debug log can record database operations, system processes, and errors that occur when executing a transaction or running unit tests. Debug logs can contain information about: Database changes. HTTP callouts.
Print() essentially calls Debug. Log() so there are no major differences. One thing to remember though is that Print() is inherited from the MonoBehaviour class so if you create a class that doesn't inherit from it(this is first done in the BowlMaster) then Print() will no longer work.
This can be done with a callback function. Send a pointer to a function to from C# to C++ store it in a temporary variable. Put Debug.Log
inside that callback function and allow it to receive strings as a pointer(IntPtr
).
When this function is called from C++, convert the IntPtr
to string with Marshal.PtrToStringAnsi
.
To make it work on iOS you have to use the MonoPInvokeCallback
attribute on the callback function.
C# (Attach to an empty GameObject):
using AOT;
using System;
using System.Runtime.InteropServices;
using UnityEngine;
public class DebugCPP : MonoBehaviour
{
// Use this for initialization
void OnEnable()
{
RegisterDebugCallback(OnDebugCallback);
}
//------------------------------------------------------------------------------------------------
[DllImport("DebugLogPlugin", CallingConvention = CallingConvention.Cdecl)]
static extern void RegisterDebugCallback(debugCallback cb);
//Create string param callback delegate
delegate void debugCallback(IntPtr request, int color, int size);
enum Color { red, green, blue, black, white, yellow, orange };
[MonoPInvokeCallback(typeof(debugCallback))]
static void OnDebugCallback(IntPtr request, int color, int size)
{
//Ptr to string
string debug_string = Marshal.PtrToStringAnsi(request, size);
//Add Specified Color
debug_string =
String.Format("{0}{1}{2}{3}{4}",
"<color=",
((Color)color).ToString(),
">",
debug_string,
"</color>"
);
UnityEngine.Debug.Log(debug_string);
}
}
C++ (DebugCPP.h
):
#pragma once
#include<stdio.h>
#include <string>
#include <stdio.h>
#include <sstream>
#define DLLExport __declspec(dllexport)
extern "C"
{
//Create a callback delegate
typedef void(*FuncCallBack)(const char* message, int color, int size);
static FuncCallBack callbackInstance = nullptr;
DLLExport void RegisterDebugCallback(FuncCallBack cb);
}
//Color Enum
enum class Color { Red, Green, Blue, Black, White, Yellow, Orange };
class Debug
{
public:
static void Log(const char* message, Color color = Color::Black);
static void Log(const std::string message, Color color = Color::Black);
static void Log(const int message, Color color = Color::Black);
static void Log(const char message, Color color = Color::Black);
static void Log(const float message, Color color = Color::Black);
static void Log(const double message, Color color = Color::Black);
static void Log(const bool message, Color color = Color::Black);
private:
static void send_log(const std::stringstream &ss, const Color &color);
};
C++ (DebugCPP.cpp
):
#include "DebugCPP.h"
#include<stdio.h>
#include <string>
#include <stdio.h>
#include <sstream>
//-------------------------------------------------------------------
void Debug::Log(const char* message, Color color) {
if (callbackInstance != nullptr)
callbackInstance(message, (int)color, (int)strlen(message));
}
void Debug::Log(const std::string message, Color color) {
const char* tmsg = message.c_str();
if (callbackInstance != nullptr)
callbackInstance(tmsg, (int)color, (int)strlen(tmsg));
}
void Debug::Log(const int message, Color color) {
std::stringstream ss;
ss << message;
send_log(ss, color);
}
void Debug::Log(const char message, Color color) {
std::stringstream ss;
ss << message;
send_log(ss, color);
}
void Debug::Log(const float message, Color color) {
std::stringstream ss;
ss << message;
send_log(ss, color);
}
void Debug::Log(const double message, Color color) {
std::stringstream ss;
ss << message;
send_log(ss, color);
}
void Debug::Log(const bool message, Color color) {
std::stringstream ss;
if (message)
ss << "true";
else
ss << "false";
send_log(ss, color);
}
void Debug::send_log(const std::stringstream &ss, const Color &color) {
const std::string tmp = ss.str();
const char* tmsg = tmp.c_str();
if (callbackInstance != nullptr)
callbackInstance(tmsg, (int)color, (int)strlen(tmsg));
}
//-------------------------------------------------------------------
//Create a callback delegate
void RegisterDebugCallback(FuncCallBack cb) {
callbackInstance = cb;
}
Usage from C++:
Debug::Log("Hellow Red", Color::Red);
Debug::Log("Hellow Green", Color::Green);
Debug::Log("Hellow Blue", Color::Blue);
Debug::Log("Hellow Black", Color::Black);
Debug::Log("Hellow White", Color::White);
Debug::Log("Hellow Yellow", Color::Yellow);
Debug::Log("Hellow Orange", Color::Orange);
Debug::Log(true, Color::Black);
Debug::Log(false, Color::Red);
Output from the Editor:
Now, you can easily implement Debug.LogWarning
and Debug.LogError
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With