Skip to content
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

Unity 2018.1 and IL2CPP #227

Open
pax83 opened this issue May 4, 2018 · 76 comments
Open

Unity 2018.1 and IL2CPP #227

pax83 opened this issue May 4, 2018 · 76 comments

Comments

@pax83
Copy link

@pax83 pax83 commented May 4, 2018

API doesnot work with Unity 2018.1 and IL2CPP enabled.

NotSupportedException: To marshal a managed method, please add an attribute named 'MonoPInvokeCallback' to the method definition.
  at Steamworks.NativeMethods.ISteamClient_SetWarningMessageHook (System.IntPtr instancePtr, Steamworks.SteamAPIWarningMessageHook_t pFunction) [0x00000] in <00000000000000000000000000000000>:0 
  at Steamworks.SteamClient.SetWarningMessageHook (Steamworks.SteamAPIWarningMessageHook_t pFunction) [0x00000] in <00000000000000000000000000000000>:0 
  at SteamManager.OnEnable () [0x00000] in <00000000000000000000000000000000>:0 
  at UnityEngine.GameObject.AddComponent (System.Type componentType) [0x00000] in <00000000000000000000000000000000>:0 
  at UnityEngine.GameObject.AddComponent[T] () [0x00000] in <00000000000000000000000000000000>:0 
  at SteamManager.get_Initialized () [0x00000] in <00000000000000000000000000000000>:0 
  at UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) [0x00000] in <00000000000000000000000000000000>:0 
UnityEngine.GameObject:AddComponent(Type)
UnityEngine.GameObject:AddComponent()
SteamManager:get_Initialized()
UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)
NotSupportedException: IL2CPP does not support marshaling delegates that point to generic methods.
  at System.Runtime.InteropServices.Marshal.StructureToPtr (System.Object structure, System.IntPtr ptr, System.Boolean fDeleteOld) [0x00000] in <00000000000000000000000000000000>:0 
  at Steamworks.Callback`1[T].BuildCCallbackBase () [0x00000] in <00000000000000000000000000000000>:0 
  at Steamworks.Callback`1[T]..ctor (Steamworks.Callback`1+DispatchDelegate[T] func, System.Boolean bGameServer) [0x00000] in <00000000000000000000000000000000>:0 
  at Steamworks.Callback`1[T].Create (Steamworks.Callback`1+DispatchDelegate[T] func) [0x00000] in <00000000000000000000000000000000>:0 
  at SteamSocialAPI+<Start>c__Iterator0.MoveNext () [0x00000] in <00000000000000000000000000000000>:0 
  at UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) [0x00000] in <00000000000000000000000000000000>:0 
 
(Filename: currently not available on il2cpp Line: -1)
@pax83

This comment has been minimized.

Copy link
Author

@pax83 pax83 commented May 8, 2018

Hi! Is any plans to fix this problem?

@rlabrecque

This comment has been minimized.

Copy link
Owner

@rlabrecque rlabrecque commented May 13, 2018

Hey @pax83, I'm honestly not sure. I'm not sure that it's even feasible to fix this right now. I'll need to talk to some Unity people about this.

@rlabrecque

This comment has been minimized.

Copy link
Owner

@rlabrecque rlabrecque commented May 13, 2018

Working on this right now!

@rlabrecque

This comment has been minimized.

Copy link
Owner

@rlabrecque rlabrecque commented May 14, 2018

This is going to be a lot bigger of a problem than I was hoping unfortunately :(

IL2CPP might be unsupported for the time being

@pax83

This comment has been minimized.

Copy link
Author

@pax83 pax83 commented May 14, 2018

It is a pity that you can not solve the problem quickly. But is there any hope that the plug-in will work with IL2CPP in the future?

@rlabrecque

This comment has been minimized.

Copy link
Owner

@rlabrecque rlabrecque commented May 14, 2018

There is definitely hope for sure, I've submitted an issue report to Unity, but I think the IL2CPP does not support marshaling delegates that point to generic methods. issue is just masking another issue.

Ultimately it might be tricky to do while maintaining the same callback API. (Which is a high priority)

@tomjohnstone

This comment has been minimized.

Copy link

@tomjohnstone tomjohnstone commented May 15, 2018

Please find attached a callback system we implemented to overcome this issue (using Steamworks.NET):

https://gist.github.com/logadmin/9788c0b40ba967b087701268641c36ce

We also implemented some code for autogenerating this code if anyone's interested.

@pax83

This comment has been minimized.

Copy link
Author

@pax83 pax83 commented May 15, 2018

@tomjohnstone thanks, I'll try it soon.

@pax83

This comment has been minimized.

Copy link
Author

@pax83 pax83 commented May 15, 2018

Unity can not compile this code. Everything hangs. :(

@rlabrecque

This comment has been minimized.

Copy link
Owner

@rlabrecque rlabrecque commented May 15, 2018

Hey @tomjohnstone Awesome! Thanks for sharing!

Do you have an example of what the callsite looks like now?

The only reason why this is a problem is not wanting to break the API compatibility with existing code. If that doesn't matter to you then something like that is definitely great!

@pax83

This comment has been minimized.

Copy link
Author

@pax83 pax83 commented May 15, 2018

Not work for me. 800+ errors like that:
Assets/Plugins/Steamworks.NET/autogen/SteamCallbacks.cs(24,30): error CS0051: Inconsistent accessibility: parameter typeSteamworks.CCallbackBaseVTable.RunCBDel' is less accessible than method Steamworks.SteamCallbackBase.BuildVTable(Steamworks.CCallbackBaseVTable.RunCBDel, Steamworks.CCallbackBaseVTable.RunCRDel, Steamworks.CCallbackBaseVTable.GetCallbackSizeBytesDel)'

and

Assets/Plugins/Steamworks.NET/autogen/SteamCallbacks.cs(56,53): error CS0234: The type or namespace nameSteamAppInstalled_t' does not exist in the namespace Steamworks'. Are you missing an assembly reference?

@tomjohnstone

This comment has been minimized.

Copy link

@tomjohnstone tomjohnstone commented May 15, 2018

You need to make those delegates public in CallbackDispatcher.cs for it to compile @pax83

Also your version of Steamworks.NET may not include SteamAppInstalled_t so just remove the callback for that type.

Note you'll also have to add the MonoPInvokeCallbackAttribute to SteamManager.SteamAPIDebugTextHook

@tomjohnstone

This comment has been minimized.

Copy link

@tomjohnstone tomjohnstone commented May 15, 2018

@rlabrecque in terms of usage it now looks something like this:

For a callback:

SteamCallbacks.SteamInventoryResultReady_t.RegisterCallback(OnInventoryResult);
SteamCallbacks.SteamInventoryResultReady_t.UnregisterCallback(OnInventoryResult);
...

private void OnInventoryResult(SteamInventoryResultReady_t result, bool failure)
{
}

Note in this case the action is permanently registered until it is deregistered.

For a call result:

System.Action<LobbyCreated_t, bool> onResult = (LobbyCreated_t callback, bool IOFailure) =>
{
    OnCreateLobbyResult(callback, IOFailure, roomName, lobbyType, maxPlayers, isVisible, isOpen);
};

SteamAPICall_t handle = SteamMatchmaking.CreateLobby(steamLobbyType, maxPlayers);
SteamCallbacks.LobbyEnter_t.RegisterCallResult(OnJoinLobbyResult, handle);

Note in this case, the action is only called once, then automatically deregistered. You can still call deregister before the callback has been made however.

@tomjohnstone

This comment has been minimized.

Copy link

@tomjohnstone tomjohnstone commented May 15, 2018

@rlabrecque I believe you could still make this work using the existing API. The generic callback types would have to look up a dictionary of static callbacks for that given type. This wasn't a requirement for our use case and it was easier to implement the version I posted.

The issue in a nutshell is that IL2CPP can only Pinvoke a callback that is static and non-generic (and marked with the MonoPInvokeCallback attribute) so that's why I had to autogenerate a unique one for each type.

@pax83

This comment has been minimized.

Copy link
Author

@pax83 pax83 commented May 16, 2018

@tomjohnstone can you send all changes in all files? In your example all classes are static, but compiler cannot use static classes in action definition like this:
private static System.Action<Steamworks.SteamAppInstalled_t> _callbackAction;

Also all classes not contains definition for k_iCallback

@tomjohnstone

This comment has been minimized.

Copy link

@tomjohnstone tomjohnstone commented May 16, 2018

@pax83 see my post above for how to use this system, it's different to the old way of doing things. What version of Steamworks.NET are you using?

@pax83

This comment has been minimized.

Copy link
Author

@pax83 pax83 commented May 16, 2018

@tomjohnstone I use latest version. And it just can not be compiled...

@tomjohnstone

This comment has been minimized.

Copy link

@tomjohnstone tomjohnstone commented May 16, 2018

@pax83 if you look at:

https://github.com/rlabrecque/Steamworks.NET/blob/master/Plugins/Steamworks.NET/autogen/SteamCallbacks.cs

You will see that all the callback types do in fact contain k_iCallback so I'm not sure why you are seeing that error.

Also are you using the new usage pattern I posted above? You no longer create callback instances you just register/deregister actions with the static classes.

@pax83

This comment has been minimized.

Copy link
Author

@pax83 pax83 commented May 17, 2018

@tomjohnstone by your link https://gist.github.com/logadmin/9788c0b40ba967b087701268641c36ce check line 73, 120, 197, ... etc, 348 entrys in total with k_iCallback.
Maybe you send not final version of SteamCallbacks.cs?

@tomjohnstone

This comment has been minimized.

Copy link

@tomjohnstone tomjohnstone commented May 17, 2018

This is not a replacement for the existing SteamCallbacks.cs just call the file something different

@pax83

This comment has been minimized.

Copy link
Author

@pax83 pax83 commented May 18, 2018

@tomjohnstone Thanks, it compiled now! I'll try build it and test.

@pax83

This comment has been minimized.

Copy link
Author

@pax83 pax83 commented May 22, 2018

Works! @tomjohnstone thanks!

@QFSW

This comment has been minimized.

Copy link

@QFSW QFSW commented May 31, 2018

Think the api will support IL2CPP anytime soon? I had submitted a bug report to Unity, turns out its a bug it ever worked in mono to begin with

@kkOne3

This comment has been minimized.

Copy link

@kkOne3 kkOne3 commented Jun 12, 2018

I'm unable to get this to work. I downloaded the file from here https://gist.github.com/logadmin/9788c0b40ba967b087701268641c36ce then renamed it to SteamCallbacksIL2CPP.cs. That got rid of all my errors and I was able to compile but when I upload my game to Steam it never gets initialised. So which files do I need to update to get this to work. Do I need to change how all the Callbacks get registered inside the SteamManager.cs, or the CallbackDispatcher.cs.
Like throw me a frickin bone here.

@ZeroByter

This comment has been minimized.

Copy link

@ZeroByter ZeroByter commented Jun 27, 2018

@kkOne3 Same thing happens to me. I don't get any errors but Steam does not initialize. What to do?

I followed all of @tomjohnstone's instructions and even did some improvisations, and the game compiled fine with no errors but Steam still doesn't initialize when launching through the Steam client.

@rlabrecque

This comment has been minimized.

Copy link
Owner

@rlabrecque rlabrecque commented Jun 27, 2018

I'm going to take another stab at this on the weekend.

@ZeroByter could you check with something like DebugView to see if there's a reason given?
https://docs.microsoft.com/en-us/sysinternals/downloads/debugview

@ZeroByter

This comment has been minimized.

Copy link

@ZeroByter ZeroByter commented Jun 27, 2018

@rlabrecque I do know by reading the output_log.txt file there is error NotSupportedException: To marshal a managed method, please add an attribute named 'MonoPInvokeCallback' to the method definition. and NotSupportedException: IL2CPP does not support marshaling delegates that point to generic methods..

After checking with DebugView, there doesn't seem to be any smoking gun as to the cause. In case I missed something here is the saved log file.

@GMMan

This comment has been minimized.

Copy link

@GMMan GMMan commented Jun 28, 2018

The Gist provided by @tomjohnstone needed a few adjustments for visibility and removed callback off the master branch of this repo, but seemed to work fine otherwise. See adjusted version here. And to summarize previous discussion, do not replace SteamCallbacks.cs, but add this file alongside.

@kkOne3 Yes, you do need to change the way you create your callbacks (inside your code, don't really need to touch SteamManager, though there is one error that needs to be corrected there), as mentioned in #227 (comment)

@ZeroByter

This comment has been minimized.

Copy link

@ZeroByter ZeroByter commented Jun 28, 2018

@GMMan Thanks a lot! Your adjusted gist script worked for me.

@rlabrecque

This comment has been minimized.

Copy link
Owner

@rlabrecque rlabrecque commented Jul 2, 2018

I looked into this more this weekend but couldn't come up with a good solution that preserves the existing API unfortunately :(

I did also find this: https://docs.microsoft.com/en-us/xamarin/ios/internals/limitations#Reverse_Callbacks

@GMMan

This comment has been minimized.

Copy link

@GMMan GMMan commented Nov 18, 2018

BTW, I'm pretty sure there's a way to hack il2cpp to sneak in a "return ECX" function (the source code for the libil2cpp is included, after all), but it'll probably be in no way user friendly to apply.

@GMMan

This comment has been minimized.

Copy link

@GMMan GMMan commented Nov 18, 2018

Still thinking about this... if we want to support Windows x86, do we want to consider abandoning the "one C++ object for each callback" approach in favor of the "one static type and one C++ object for each callback type and delegate internally" approach? I'm pretty sure the same public interface can be retained, just the implementation changed.

@ffffoooouuuurrrr

This comment has been minimized.

Copy link

@ffffoooouuuurrrr ffffoooouuuurrrr commented Nov 19, 2018

I can tidy it up and make a PR, but be aware that you're stuck making 64-bit builds on Windows if you want to use IL2CPP.

We do not support x86 so for us it'd be very interesting to take a look at that solution, if not via a PR I'd be very thankful if there was any other way of getting my hands on that. The Facepunch.Steamworks solution would of course also work but we'd like to evaluate IL2CPP on both platforms before deciding if it's worth to invest time into swapping wrappers.

@rlabrecque

This comment has been minimized.

Copy link
Owner

@rlabrecque rlabrecque commented Nov 19, 2018

I should be able to look at this again this weekend, let me know if you have any ideas @GMMan

It might be getting time to fork this into 3 branches... legacy, non-Unity C#, and Unity 2018.x+

@GMMan

This comment has been minimized.

Copy link

@GMMan GMMan commented Nov 20, 2018

Here's what I came up with on Saturday: https://github.com/GMMan/Steamworks.NET/tree/il2cpp-callback-workaround-v1

I'll see if I can get the other proposal implemented this week/end, and hold off on the PR until both are evaluated. Apologies ahead of the time for mismatching indentation; I tried to autoformat in VS but it made a mess, and VSCode apparently wasn't set up for the correct indentation style when I was recopy-and-pasting the code...

@ffffoooouuuurrrr

This comment has been minimized.

Copy link

@ffffoooouuuurrrr ffffoooouuuurrrr commented Nov 20, 2018

@GMMan - Had a go at it and was successful in removing the marshaling error, however there seems to be an issue with AOT(?) lingering:

ExecutionEngineException: Attempting to call method 'LapinerTools.Steam.Data.Internal.SteamRequestList::RemoveInactiveInternal<Steamworks.SteamUGCQueryCompleted_t>' for which no ahead of time (AOT) code was generated.
  at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in <00000000000000000000000000000000>:0 
  at System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) [0x00000] in <00000000000000000000000000000000>:0 
  at LapinerTools.Steam.Data.Internal.SteamRequestList.RemoveInactive () [0x00000] in <00000000000000000000000000000000>:0 
  at LapinerTools.Steam.SteamMainBase`1[SteamMainT].LateUpdate () [0x00000] in <00000000000000000000000000000000>:0 
  at LapinerTools.Steam.SteamWorkshopMain.LateUpdate () [0x00000] in <00000000000000000000000000000000>:0 
Rethrow as TargetInvocationException: Exception has been thrown by the target of an invocation.
  at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in <00000000000000000000000000000000>:0 
  at System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) [0x00000] in <00000000000000000000000000000000>:0 
  at LapinerTools.Steam.Data.Internal.SteamRequestList.RemoveInactive () [0x00000] in <00000000000000000000000000000000>:0 
  at LapinerTools.Steam.SteamMainBase`1[SteamMainT].LateUpdate () [0x00000] in <00000000000000000000000000000000>:0 
  at LapinerTools.Steam.SteamWorkshopMain.LateUpdate () [0x00000] in <00000000000000000000000000000000>:0 

Any ideas? This happens when downloading subscribed items for Workshop.

@rlabrecque

This comment has been minimized.

Copy link
Owner

@rlabrecque rlabrecque commented Nov 20, 2018

Wow nice that looks surprisingly simple and elegant!

@GMMan

This comment has been minimized.

Copy link

@GMMan GMMan commented Nov 20, 2018

@ffffoooouuuurrrr That looks like something's invoking reflection? Could you post the contents of LapinerTools.Steam.Data.Internal.SteamRequestList.RemoveInactive ()?

@ffffoooouuuurrrr

This comment has been minimized.

Copy link

@ffffoooouuuurrrr ffffoooouuuurrrr commented Nov 20, 2018

@ffffoooouuuurrrr That looks like something's invoking reflection? Could you post the contents of LapinerTools.Steam.Data.Internal.SteamRequestList.RemoveInactive ()?

Yeah, sorry, here it is:

	public void RemoveInactive<T>()
	{
		System.Type resultType = typeof(T);
		List<object> typedRequests;
		if (m_requests.TryGetValue(resultType, out typedRequests))
		{
			MethodInfo removeInactiveInternalMethod = this.GetType().GetMethod("RemoveInactiveInternal", BindingFlags.NonPublic | BindingFlags.Static).MakeGenericMethod(resultType);
			removeInactiveInternalMethod.Invoke(this, new object[] { typedRequests });
		}
	}
@GMMan

This comment has been minimized.

Copy link

@GMMan GMMan commented Nov 20, 2018

Yup, that's some reflection. You'll want to refactor that code to not use reflection. Looks like you could just call RemoveInactiveInternal<T>(typedRequests).

Though it also looks like the function you supplied isn't the one from the stack trace. There's a non-generic version, and you'll have to fix that too. Email me if you want more help, let's not fix poorly made Unity Store code here.

@GMMan

This comment has been minimized.

Copy link

@GMMan GMMan commented Nov 21, 2018

I was looking at the exports from steam_api.dll, and there appears to be a lot of C_{Set|Remove}Call{back|Result} functions. Maybe that can be used somehow, but would require the autogen to be updated.

Update: OK, so that will create Callback/CallResult native objects for us, but we still have to create an internal dispatch since we still can't give it a non-static delegate. And they don't give us a this value. We can already generate those objects just fine...

@derwodaso

This comment has been minimized.

Copy link

@derwodaso derwodaso commented Dec 10, 2018

What's the status of this?

@GMMan

This comment has been minimized.

Copy link

@GMMan GMMan commented Dec 10, 2018

Sorry, I've been on vacation for the past couple of weeks, and currently dealing with a bunch of projects, so it might be a while before this arrives at the top of the queue.

@Deusald

This comment has been minimized.

Copy link

@Deusald Deusald commented Jan 23, 2019

@rlabrecque @GMMan
What's the status? Is the fix in progress?

@GMMan

This comment has been minimized.

Copy link

@GMMan GMMan commented Jan 23, 2019

Unfortunately another project has taken up all my time, so the solution I've posted is the only one I'll have until the other project winds down some.

@itsmichael

This comment has been minimized.

Copy link

@itsmichael itsmichael commented Feb 17, 2019

With the SteamCallbacksIL2CPP.cs solution, the bIOFailure boolean that is passed to the callback is being set when I call SteamUserStats.GetNumberOfCurrentPlayers(); from an x86 IL2CPP build. This happens both when the build is ran directly, and when it is started from Steam.

However, when I run this code from the editor or a Mono build, the number of players is printed correctly with a count of "1" (I am the only one in the game; I have not tested with multiple players, but I assume it would increment correctly). The code also works from an x64 IL2CPP build.

No warnings or information messages are displayed through SteamUtils.SetWarningMessageHook() when running Steam with -debug_steamapi. Attempting to use SteamUtils.GetAPICallFailureReason() inside of the OnNumberOfCurrentPlayers() callback returns k_ESteamAPICallFailureInvalidHandle.

using Steamworks;
using UnityEngine;

public class SteamScript : MonoBehaviour
{
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            if (SteamManager.Initialized)
            {
                SteamAPICall_t handle = SteamUserStats.GetNumberOfCurrentPlayers();
                SteamCallbacks.NumberOfCurrentPlayers_t.RegisterCallResult(OnNumberOfCurrentPlayers, handle);
                Debug.Log("Called GetNumberOfCurrentPlayers()");
            }
        }
    }

    private void OnNumberOfCurrentPlayers(NumberOfCurrentPlayers_t pCallback, bool bIOFailure)
    {
        if (pCallback.m_bSuccess != 1 || bIOFailure)
        {
            Debug.Log("There was an error retrieving the NumberOfCurrentPlayers.");
        }
        else
        {
            Debug.Log("The number of players playing your game: " + pCallback.m_cPlayers);
        }
    }
}

This was created by following the "Getting Started" tutorial, with the only change being the addition of the SteamCallbacksIL2CPP.cs file inside of the Steamworks.NET directory, adding the MonoPInvokeCallback attribute to SteamManager.SteamAPIDebugTextHook, and using RegisterCallResult() instead of the CallResult<> system.

Does anyone know how to fix this? I am currently removing large parts of Steamworks.NET to try and isolate the problem, but because I am unfamiliar with the way that managed and unmanaged code communicate, it's been slow going.

OS: Windows 10 Pro 64-bit
Unity: Unity 2018.3.5f1 Personal
Also tested with: Unity 2018.1.9f2 Personal
Steamworks.NET: 12.0.0, with additional SteamCallbacksIL2CPP.cs file and SteamManager.cs modification

Build Type: Windows x86
Scripting Runtime Version: .NET 4.x Equivalent
Api Compatibility Level: .NET 4.x
C++ Compiler Configuration: Release

@itsmichael

This comment has been minimized.

Copy link

@itsmichael itsmichael commented Feb 18, 2019

I think I found the solution. MonoPInvokeCallback has a type parameter in most of the examples I see online, but this type parameter is missing from the definition in the SteamCallbacksIL2CPP.cs file. I changed the attribute to include a Type parameter:

    public class MonoPInvokeCallbackAttribute : Attribute
    {
        public MonoPInvokeCallbackAttribute(Type t) { }
    }

I then added the following arguments to the MonoPInvokeCallback attributes on these methods in SteamCallbacks.NumberOfCurrentPlayers_t:

            [MonoPInvokeCallback(typeof(CCallbackBaseVTable.RunCBDel))]
            private static void OnRunCallback(
// ...

            [MonoPInvokeCallback(typeof(CCallbackBaseVTable.RunCRDel))]
            private static void OnRunCallResult(
// ...

            [MonoPInvokeCallback(typeof(CCallbackBaseVTable.GetCallbackSizeBytesDel))]
            private static int OnGetCallbackSizeBytes(
// ...

So far, this has fixed the problem I ran into. I have only tested SteamUserStats.GetNumberOfCurrentPlayers(), so if I run into further issues and find a solution I'll report back in this thread to try and keep everything in one spot.

Hopefully this information is useful to the other developers in this thread.

@GMMan

This comment has been minimized.

Copy link

@GMMan GMMan commented Feb 18, 2019

@itsmichael Unity has built-in MonoPInvokeCallbackAttribute under the AOT namespace. You don't have to create your own.

@itsmichael

This comment has been minimized.

Copy link

@itsmichael itsmichael commented Feb 18, 2019

Yeah, good point. The one in SteamCallbacksIL2CPP.cs should probably be replaced with the one in AOT.

@TokyoWarfare

This comment has been minimized.

Copy link

@TokyoWarfare TokyoWarfare commented Feb 20, 2019

Hello, I'm totally lost with this. I'm using GMMan workaround and I get the
"NotsupportedException: To marshal a managed method, please add an atribute named 'MonoPinvokeCallback' to the method definition.

So, in Steam forum told me to look for the modified SteamManager here as it could be around the thread. Found none. Yet I see the modifications to be done but theese are ahead my skills and I've been messing around for a while without knowing what to modify:

"adding the MonoPInvokeCallback attribute to SteamManager.SteamAPIDebugTextHook, and using RegisterCallResult() instead of the CallResult<> system."

Ok, I've no idea on how to do this, can someone please share the file or post example of the method that needs modifications?

ALso if I use GMMan workaround do I still need the SteamCallbacksIL2CPP.cs (with the above posted modifications) ¿?¿? or this file is for before GMMan workaround?.

Ase u can see I'm totally stuck in the mud

@itsmichael

This comment has been minimized.

Copy link

@itsmichael itsmichael commented Feb 20, 2019

@TokyoWarfare GMMan's solution https://github.com/GMMan/Steamworks.NET/tree/il2cpp-callback-workaround-v1 should work as it is out of the box, without any modifications. However, it will only work on x64 machines, so you need to make sure to set your build settings to x86_64 in Unity.

If you must have x86 support, then the only solution at the moment (that I am aware of) is the SteamCallbacksIL2CPP.cs file. Unfortunately, that solution requires some modifications which could be confusing to apply if you aren't familiar with this type of programming.

I am currently working on an x86 solution that will hopefully work out of the box, but because more skilled programmers than I have already attempted this, I am unsure I will be able to post such a solution.

My recommendation, if you need a quick solution that requires no modification, is to drop support for x86 in your game and use GMMan's fork, linked above... Not the best situation to be in, but this is all a bit of a mess at the moment. Alternatively, switch to using Mono instead of IL2CPP and Steamworks.NET should work without modifications.

@TokyoWarfare

This comment has been minimized.

Copy link

@TokyoWarfare TokyoWarfare commented Feb 20, 2019

Yep that is exactly what I did, drop x86 support :D . The thing is that it does not work out of the box, I did strip my old Steamworks.net scripts and did a clean unpack of th eGMMan workaround. He even told me steammanager need a fix and according to the consold eerr, definitelly seems to need the "MonoPInvokeCallback attribute to SteamManager.SteamAPIDebugTextHook, and using RegisterCallResult() instead of the CallResult<> system." I would say If you could share your modified SteamManager or at leas the modiffied MessageHook part I could do a quick test.

edit. for clarification.
the error only is shown on the build not in editor. It build fine, it even displays Steam Overlay.
But on launch in the development console it will show the avobe err.

@itsmichael

This comment has been minimized.

Copy link

@itsmichael itsmichael commented Feb 20, 2019

Oh! Sorry, I misunderstood, and I was not aware that SteamManager.cs required modification in GMMan's solution.

First, open SteamManager.cs, which should be in Assets\Scripts\Steamworks.NET if installed in the default location. Then find this line of code:

private static void SteamAPIDebugTextHook(int nSeverity, System.Text.StringBuilder pchDebugText) {

Change it to look like this:

[AOT.MonoPInvokeCallback(typeof(SteamAPIWarningMessageHook_t))]
private static void SteamAPIDebugTextHook(int nSeverity, System.Text.StringBuilder pchDebugText) {

The error should now be gone, hopefully.

@GMMan

This comment has been minimized.

Copy link

@GMMan GMMan commented Feb 20, 2019

SteamManager is in a separate repo, which is why you'll have to apply changes to it manually.

@rlabrecque

This comment has been minimized.

Copy link
Owner

@rlabrecque rlabrecque commented Feb 21, 2019

Just to add to why it's in a separate repo: Steamworks.NET isn't Unity specific, but SteamManager is a Unity specific MonoBehavior, and it's just intended to be a starting point for user code.

@TokyoWarfare

This comment has been minimized.

Copy link

@TokyoWarfare TokyoWarfare commented Feb 21, 2019

Oh! Sorry, I misunderstood, and I was not aware that SteamManager.cs required modification in GMMan's solution.
First, open SteamManager.cs, which should be in Assets\Scripts\Steamworks.NET if installed in the default location. Then find this line of code:
private static void SteamAPIDebugTextHook(int nSeverity, System.Text.StringBuilder pchDebugText) {

Change it to look like this:
[AOT.MonoPInvokeCallback(typeof(SteamAPIWarningMessageHook_t))]
private static void SteamAPIDebugTextHook(int nSeverity, System.Text.StringBuilder pchDebugText) {

The error should now be gone, hopefully.

My HERO!!! err is gone!!! thank you all of you three for your support, help and developing such a neat tool to allow us plebs focus on the game when deploying to Steam.
If you any of three would like to play my game Tokyo Warfare Turbo send me PM and I send you DLC's keys. Cheers!!!.

@itsmichael

This comment has been minimized.

Copy link

@itsmichael itsmichael commented Feb 21, 2019

I'm glad it worked! Good luck with your Steam launch.

@itsmichael

This comment has been minimized.

Copy link

@itsmichael itsmichael commented Feb 23, 2019

I extracted the callback/callresult code in SteamCallbacksIL2CPP.cs into a static generic class CallbackHub<T>. This should allow Callback<T> and CallResult<T> instances to register their methods with it. CallbackHub<T> should be able to manage a single native object for each callback/callresult type, and route callbacks/callresults to multiple C# objects that have registered with it. This should allow the same Steamworks.NET API to be used, and not require a this pointer.

https://gist.github.com/itsmichael/688ca1aa18938f1d0b971f7dea6048c3

Unfortunately though, I have ran into a problem: I do not know how we would set k_ECallbackFlagsGameServer without setting it for all the callbacks. It's part of the native object, and because we can only have a single native object for each callback... I am unsure how this would be fixed.

EDIT: Actually... Would creating a second version of each callback/callresult static class, but for k_ECallbackFlagsGameServer, solve this problem? I am unfamiliar with how the game server works in Steamworks.

@flarb

This comment has been minimized.

Copy link

@flarb flarb commented May 31, 2019

What's the status of this in the main branch? I get these errors in my PC IL2CPP build, I'm hesitant to use the fork becase it's kind of old?:

Uploading Crash Report NotSupportedException: IL2CPP does not support marshaling delegates that point to generic methods. The generic method we're attemping to marshal is: Steamworks.CallResult1[[Steamworks.RemoteStoragePublishFileResult_t, Assembly-CSharp-firstpass, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]]::OnRunCallback
at Steamworks.CallResult1[T].BuildCCallbackBase () [0x00000] in <00000000000000000000000000000000>:0 at Steamworks.CallResult1[T].Create (Steamworks.CallResult`1+APIDispatchDelegate[T] func) [0x00000] in <00000000000000000000000000000000>:0
at SteamWorkshop.OnEnable () [0x00000] in <00000000000000000000000000000000>:0

(Filename: currently not available on il2cpp Line: -1)

QL:3, R:8 F:1
UnityEngine.Logger:Log(LogType, Object)
PrefsData:SetResolutionAndQualityFromPrefs()

(Filename: ./Runtime/Export/Debug.bindings.h Line: 45)

Setting breakpad minidump AppID = 480
Steam_SetMinidumpSteamID: Caching Steam ID: 76561197969813193 [API loaded no]
Uploading Crash Report
NotSupportedException: To marshal a managed method, please add an attribute named 'MonoPInvokeCallback' to the method definition.
at Steamworks.NativeMethods.ISteamClient_SetWarningMessageHook (System.IntPtr instancePtr, Steamworks.SteamAPIWarningMessageHook_t pFunction) [0x00000] in <00000000000000000000000000000000>:0
at UnityEngine.GameObject.AddComponent[T] () [0x00000] in <00000000000000000000000000000000>:0
at SteamManager.get_Instance () [0x00000] in <00000000000000000000000000000000>:0
at SteamworksCalls.Start () [0x00000] in <00000000000000000000000000000000>:0
UnityEngine.GameObject:AddComponent()
SteamManager:get_Instance()
SteamworksCalls:Start()

(Filename: currently not available on il2cpp Line: -1)

Uploading Crash Report
NotSupportedException: IL2CPP does not support marshaling delegates that point to generic methods. The generic method we're attemping to marshal is: Steamworks.Callback1[[Steamworks.UserStatsReceived_t, Assembly-CSharp-firstpass, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]]::OnRunCallback at Steamworks.Callback1[T].BuildCCallbackBase () [0x00000] in <00000000000000000000000000000000>:0
at Steamworks.Callback1[T]..ctor (Steamworks.Callback1+DispatchDelegate[T] func, System.Boolean bGameServer) [0x00000] in <00000000000000000000000000000000>:0
at Steamworks.Callback1[T].Create (Steamworks.Callback1+DispatchDelegate[T] func) [0x00000] in <00000000000000000000000000000000>:0
at SteamworksCalls.Start () [0x00000] in <00000000000000000000000000000000>:0

(Filename: currently not available on il2cpp Line: -1)

REQUESTING USER STATS...1
UnityEngine.Logger:Log(LogType, Object)
SteamworksCalls:LateUpdate()

(Filename: ./Runtime/Export/Debug.bindings.h Line: 45)

Uploading Crash Report
InvalidOperationException: Handle is not pinned.
at System.Runtime.InteropServices.GCHandle.GetTarget (System.Int32 handle) [0x00000] in <00000000000000000000000000000000>:0
at Steamworks.Callback1[T].Unregister () [0x00000] in <00000000000000000000000000000000>:0 at Steamworks.Callback1[T].Dispose () [0x00000] in <00000000000000000000000000000000>:0
at Steamworks.Callback`1[T].Finalize () [0x00000] in <00000000000000000000000000000000>:0

(Filename: currently not available on il2cpp Line: -1)`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
You can’t perform that action at this time.