-
Notifications
You must be signed in to change notification settings - Fork 335
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[$50 Bounty] RP completely broken with il2cpp (Unity 2018.2 Stable): Needs dll marshaling #243
Comments
The keyword is |
Responded to the closed issue without seeing this open first. Sure, if il2cpp is the new standard in Unity, we definitely need to come up with a fix and ship a new version. No problem. If the static class method implementation in the closed issue is a valid fix, I'm more than happy to accept a PR that does as much. It won't break any existing implementations, as the native stuff here is pretty well abstracted from what actually "happens" in JS land in Discord, but I do sense some unknowns around how this plays with older Unity versions, which many folks will still use. Plenty of folks asking questions around VS2010 oddities when it comes to our newer game SDK 😛 |
Thread Merge
Alas, I'm not good, either. I tried a few things, but failed. Something to do with turning the callbacks into static callbacks tagged with (for ErrorCallback's example) Cross Compatible? Yes!I read that it's cross-compatible. Steamworks.net had to do the same thing and confirms cross-compatability: Perhaps see here for clues @ rlabrecque/Steamworks.NET#227 and https://gist.github.com/GMMan/7a8a475b703363d2911fd20f238caef0 Then the importdll[] tags probably have to be changed to something similar, too. Maybe? I tried researching, but I wasn't even familiar with dll madness to begin with :P I mostly use native C# libraries, personally. Anyone able to come to the rescue? |
💰 Bounty!$50 PayPal to whoever first posts the correct il2cpp-friendly solution below (that I can confirm works). 🔍 Hints:
💡 If you complete the bounty...
|
I'd like to point out that IL2CPP is the new standard for UWP builds only - "standalone" windows builds using mono/.net are not being deprecated. See the section about it at https://blogs.unity3d.com/2018/07/10/2018-2-is-now-available/ |
@pipliz thank you for that documentation. That's mainly what I'm referring to. Unity deprecating .NET altogether seemed a bit fishy to me :p I think we can definitely come up with a solve for folks who want to make the switch, and just ensure it doesn't break other stuff. |
Ah, my bad -- I updated OP |
More leads:
I still can't figure it out. I've never directly dealt with dlls. I've tried several combos, but I can't get it to work. I'm just doing trial+error because I don't understand dll importing to begin with, so it's very foreign to me. I'm willing to bet an experienced dev would only need 15 minutes to fix this, from what I researched. |
Based on the solution offered in #186, this seems like something that is handled more in the use of the methods, rather than the underlying source code. That is to say, handled in Perhaps @mdsitton would be able to share with us a bit more of his code, but in the meantime, I am trying to finagle the example to get it working. EDIT: I do not know that for sure, but trying to parse his short response, that's what I am assuming. I could be, and most certainly am, wrong. |
It has to do with the initial DLL callback -- it must be a static callback and handled as a non-delegate (ending with This file should be the culprit: https://github.com/discordapp/discord-rpc/blob/master/examples/button-clicker/Assets/DiscordRpc.cs So we have this (of 7 funcs); I'm just going to use ready examples: [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void ReadyCallback(ref DiscordUser connectedUser);
public struct EventHandlers
{
public ReadyCallback readyCallback;
}
[DllImport("discord-rpc", EntryPoint = "Discord_Initialize", CallingConvention = CallingConvention.Cdecl)]
public static extern void Initialize(string applicationId, ref EventHandlers handlers, bool autoRegister, string optionalSteamId); This needs to changed to look something like this (again, I'm still getting that error, but for directions sake): // DiscordRpc.cs
using AOT;
public delegate void OnReadyInfo(ref DiscordUser connectedUser);
[MonoPInvokeCallback(typeof(OnReadyInfo))]
public static void ReadyCallback(ref DiscordUser connectedUser)
{
UnityEngine.Debug.Log("[DiscordRpc] @ ReadyCallback");
}
public struct EventHandlers
{
public ReadyCallback readyCallback; // Unchanged?
}
// From the examples I've seen, I don't think this line is the issue -- but the callback, rather.
[DllImport("discord-rpc", EntryPoint = "Discord_Initialize", CallingConvention = CallingConvention.Cdecl)]
public static extern void Initialize(string applicationId, ref EventHandlers handlers, bool autoRegister, string optionalSteamId); The actual err does occur at // DiscordController.cs
void OnEnable()
{
handlers = new DiscordRpc.EventHandlers(); // << This is where the il2cpp err happens: Inside DiscordRpc. Stacktrace will only show it's from DiscordController because the parent starts at OnEnable.
handlers.onReadyInfo = ReadyCallback;
[...]
} AOT Requirements TL;DR Seem to Be:
|
Porting a recent comment over from #186 from @joshpeterson
|
I think this is on the right track.
This is correct. This code is trying to get a function pointer to the managed method These two requirements are correct. The method which will be called back from native code needs to be a static method and it needs to have the
I'm not entirely sure what this requirement means. Based on the code above though, I think you need one modification: // DiscordRpc.cs
using AOT;
public delegate void OnReadyInfo(ref DiscordUser connectedUser);
[MonoPInvokeCallback(typeof(OnReadyInfo))]
public static void ReadyCallback(ref DiscordUser connectedUser)
{
UnityEngine.Debug.Log("[DiscordRpc] @ ReadyCallback");
}
public struct EventHandlers
{
// I think this is the change we need.
// public ReadyCallback readyCallback; // Unchanged?
public OnReadyInfo readyCallback; // The type of this field should be OnReadyInfo
}
// From the examples I've seen, I don't think this line is the issue -- but the callback, rather.
[DllImport("discord-rpc", EntryPoint = "Discord_Initialize", CallingConvention = CallingConvention.Cdecl)]
public static extern void Initialize(string applicationId, ref EventHandlers handlers, bool autoRegister, string optionalSteamId); If this does not fix the issue, can you provide more details about what the error is? Thanks! |
Hi josh! Thanks a ton for this helpful info and for chiming in. Based on your and Dylan's notes this definitely seems like a change we need to make. No problem at all there. The second piece will be updating the example code in public class GameManager {
private static GameManager instance = null;
public static GameManager Instance {
get
{
if (instance == null)
{
instance = new GameManager();
}
return instance;
}
}
public UnityEngine.Events.UnityEvent onConnect;
public UnityEngine.Events.UnityEvent onDisconnect;
public UnityEngine.Events.UnityEvent hasResponded;
} And changing the invokes to: public static void ReadyCallback(ref DiscordRpc.DiscordUser connectedUser)
{
Debug.Log(string.Format("Discord: connected to {0}#{1}: {2}", connectedUser.username, connectedUser.discriminator, connectedUser.userId));
GameManager.Instance.onConnect.Invoke();
} This makes the compiler happy, but seems to cause some runtime crashes in the player. Starting the player will result in a freeze after EDIT: I realize this is now an implementation issue rather than a native code issue, but if we've got the example up, we need to make sure it's as easy as Open -> Play for people learning. |
Can confirm that public static void ReadyCallback(ref DiscordRpc.DiscordUser connectedUser)
{
Debug.Log(string.Format("Discord: connected to {0}#{1}: {2}", connectedUser.username, connectedUser.discriminator, connectedUser.userId));
GameManager.Instance.onConnect.Invoke();
} This works successfully and the Debug Log is printed: public static void ReadyCallback(ref DiscordRpc.DiscordUser connectedUser)
{
Debug.Log(string.Format("Discord: connected to {0}#{1}: {2}", connectedUser.username, connectedUser.discriminator, connectedUser.userId));
// GameManager.Instance.onConnect.Invoke();
} |
I'm curious about the specific errors you get when calling |
It actually isn't throwing any errors on my end; the Unity player freezes up and needs to be force quit. Perhaps there's some logging I can attach? |
Is there any information in the Unity player log? |
Not much from what I've seen, but here's a couple videos. Not working when invoking events: https://gfycat.com/ShrillDigitalAnglerfish Sorry for the gfycat links; github doesn't like mp4 embeds apparently! If there's some logging I can attach that I might be missing, would love to know. I'm a Unity newbie for the most part. My changes are also reflected in #249 if anyone would like to pull it down themself. |
Think I found my own issue. The callbacks in |
@dylanh724 could you pull down my PR and see if it fixes the issue for you? It works on my machine for il2cpp and Mono, but would love a second confirmation before merging. |
@msciotti Thanks for progressing on this! I copy+pasted your Works fine in editor, However, I was unable to get this working in a standalone build, getting the same error: NotSupportedException: IL2CPP does not support marshaling delegates that point to instance methods to native code.
at DiscordController.OnEnable () [0x00000] in <00000000000000000000000000000000>:0 What's your build info? Mine is:
|
This didn't get auto-closed with the PR, so closing. |
I'm a little late to the party, but glad this issue was figured out eventually 👍 |
Is there an official solution here now? I am still getting the My solution after trying around a bit was the following (not sure if that all makes sense but it seems to work): In DiscordRpc.cs: // public EventHandlers are set from the DiscordController.cs instead of passing in the handlers when initializing:
public static EventHandlers Callbacks;
[MonoPInvokeCallback(typeof(OnReadyInfo))]
public static void ReadyCallback(ref DiscordUser connectedUser) { Callbacks.readyCallback(ref connectedUser); }
public delegate void OnReadyInfo(ref DiscordUser connectedUser);
[ ... ]
public static void Initialize(string applicationId, bool autoRegister, string optionalSteamId)
{
EventHandlers eventHandlers = new EventHandlers();
// asign the static methods above, which invoke the Callbacks
eventHandlers.readyCallback += DiscordRpc.ReadyCallback;
eventHandlers.disconnectedCallback += DiscordRpc.DisconnectedCallback;
eventHandlers.errorCallback += DiscordRpc.ErrorCallback;
eventHandlers.joinCallback += DiscordRpc.JoinCallback;
eventHandlers.spectateCallback += DiscordRpc.SpectateCallback;
eventHandlers.requestCallback += DiscordRpc.RequestCallback;
InitializeInternal(applicationId, ref eventHandlers, autoRegister, optionalSteamId);
}
[ ... ] In DiscordController.cs I replaced the OnEnable() with this:
|
@derwodaso Hm, the example as-is in the repo works fine for me? Here are my steps:
I get my ready callback with my userid in it: This does not work for you? |
You must make a build with il2cpp.
It stays c# in the editor
Provenance : Courrier pour Windows 10
De : Mason Sciotti
Envoyé le :vendredi 7 décembre 2018 19:48
À : discordapp/discord-rpc
Cc : franckmolto; Mention
Objet :Re: [discordapp/discord-rpc] [$50 Bounty] RP completely broken withil2cpp (Unity 2018.2 Stable): Needs dll marshaling (#243)
@derwodaso Hm, the example as-is in the repo works fine for me? Here are my steps:
1. Get the repo fresh (git reset --hard HEAD && git pull && git clean -xdf)
2. python build.py
3. Open unity -> button-clicker
4. Swap to il2cpp compiler -> restart
5. Press play
I get my ready callback with my userid in it:
This does not work for you?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
Garanti sans virus. www.avg.com
|
@franckmolto is correct, the problem only occurs in the build. The editor worked right away. Also I got the relevant DLL's directly (most recent), not building them. Might that be another issue @msciotti? |
Hm, OK can confirm, I didn't realize it was failing on a built app. @derwodaso if your changes work and you'd like to PR them, I'm happy to review and test and merge. |
@msciotti done! Did some minor changes to my previous version to keep the signature of the Initialize method the same. So no changes are required in DiscordController.cs. |
Reviving this issue:
#186
Background
Unity 2018.2 now only builds il2cpp for Windows UWP and now also gives the option for il2cpp builds for Windows & Mac standalone (which is definitely the future for security+performance) -- this version is not a beta. Very soon, you'll see tons of people raising this issue: a permanent fix in a newer version with cross-compatibility would be ideal~
The Issue
The answer within the #186 was not explained in detail for those not too familiar with DLL madness (very little interaction with DLL's from Unity users).
I found where to put this attribute, but don't know what to do with the errors that follow.
@mdsitton was the original person that answered #186 and @franckmolto seemed to resolve it from that answer: Any of you guys up to sharing your result?
Bugs reported from logs
Original Code
So you have this @ DiscordRpc:
Suggested Change from #186
If you change it to this:
So you have this @ DiscordRpc:
It starts getting confusing, starting with ErrorCallback not being a type
Cross-Compatibility
From my research (someone else can confirm), converting to dll marshaling using the
[MonoPInvokeCallback]
attribute and static callbacks has claims of cross-compatibility, exampled at steamworks.net and facepunch.steamworks repo's (or a quick Google search).The text was updated successfully, but these errors were encountered: