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

Cannot build MLAPI WebGL project #722

Closed
yeOldeNoob opened this issue Apr 9, 2021 · 12 comments
Closed

Cannot build MLAPI WebGL project #722

yeOldeNoob opened this issue Apr 9, 2021 · 12 comments
Assignees
Labels
good first issue Contributions are welcome. Good first issue for newcomers or first time contributors. priority:high stat:backlog Status - Issue could be considered for a future release. stat:imported Status - Issue is tracked internally at Unity type:bug Bug Report

Comments

@yeOldeNoob
Copy link

yeOldeNoob commented Apr 9, 2021

Describe the bug
After adding MLAPI to my project, WebGL builds fail.

To Reproduce
Steps to reproduce the behavior:

  1. Create a new Unity project (3D).
  2. Add the MLAPI project via the package manager (git).
  3. File->Build Settings->WebGL->Switch Platform->Build

Expected behavior
Project builds successfully.

Screenshots
See below.

Environment (please complete the following information):

  • OS: Windows 10
  • Unity Version: 2019.4.21f1 Personal
  • MLAPI Version: 0.10.0
  • MLAPI Commit:3e3aef6

Additional context
Errors (for searchability):

Library\PackageCache\com.unity.multiplayer.mlapi@3e3aef6aa0\Runtime\Transports\UNET\RelayTransport.cs(251,74): error CS0117: 'NetworkTransport' does not contain a definition for 'QueueMessageForSending'
Library\PackageCache\com.unity.multiplayer.mlapi@3e3aef6aa0\Runtime\Transports\UNET\RelayTransport.cs(266,60): error CS0117: 'NetworkTransport' does not contain a definition for 'QueueMessageForSending'
Library\PackageCache\com.unity.multiplayer.mlapi@3e3aef6aa0\Runtime\Transports\UNET\RelayTransport.cs(271,74): error CS0117: 'NetworkTransport' does not contain a definition for 'SendQueuedMessages'
Library\PackageCache\com.unity.multiplayer.mlapi@3e3aef6aa0\Runtime\Transports\UNET\RelayTransport.cs(273,60): error CS0117: 'NetworkTransport' does not contain a definition for 'SendQueuedMessages'
Error building Player because scripts had compiler errors
Build completed with a result of 'Failed' in 1 seconds (1391 ms)
UnityEngine.GUIUtility:ProcessEvent (int,intptr)
UnityEditor.BuildPlayerWindow+BuildMethodException: 5 errors
  at UnityEditor.BuildPlayerWindow+DefaultBuildMethods.BuildPlayer (UnityEditor.BuildPlayerOptions options) [0x002bf] in <208995a09fe148f5a6f6c571838c154f>:0 
  at UnityEditor.BuildPlayerWindow.CallBuildMethods (System.Boolean askForBuildLocation, UnityEditor.BuildOptions defaultBuildOptions) [0x00080] in <208995a09fe148f5a6f6c571838c154f>:0 
UnityEngine.GUIUtility:ProcessEvent (int,intptr)
@yeOldeNoob yeOldeNoob added stat:awaiting triage Status - Awaiting triage from the Netcode team. type:bug Bug Report labels Apr 9, 2021
@yeOldeNoob
Copy link
Author

mlapi_webgl_error

@yeOldeNoob yeOldeNoob changed the title Cannot build WebGL project Cannot build MLAPI WebGL project Apr 9, 2021
@will-mearns will-mearns added stat:commited Status - Commited to work on this issue. and removed stat:awaiting triage Status - Awaiting triage from the Netcode team. labels Apr 26, 2021
@TwoTenPvP TwoTenPvP added the good first issue Contributions are welcome. Good first issue for newcomers or first time contributors. label May 12, 2021
@meruiden
Copy link

I'm still having this issue, any updates on this?

@notcat
Copy link

notcat commented Aug 6, 2021

Hi, is there a possibility you could create a release version with this commit added only? This is a pretty important bug and I should not have to use the development branch to compile for WebGL.

@Saltant
Copy link

Saltant commented Aug 13, 2021

@crioseth
Copy link

Same error here, any suggestions or workarounds?

@Saltant
Copy link

Saltant commented Aug 18, 2021

Same error here, any suggestions or workarounds?

Just remove broken code from source (SendQueuedMessages, QueueMessageForSending) i dont know why mlapi devs is sleep, but remove code and problem goned.

@Awhesian
Copy link

Awhesian commented Nov 23, 2021

//Ctrl+A the entire of UNetTransport and paste in code below

#pragma warning disable 618
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using System;
using System.Collections.Generic;
using MLAPI.Exceptions;
using MLAPI.Logging;
using MLAPI.Profiling;
using MLAPI.Transports.Tasks;
using UnityEngine.Networking;

namespace MLAPI.Transports.UNET
{
public class UNetTransport : NetworkTransport, ITransportProfilerData
{
public enum SendMode
{
Immediately,
Queued
}

    private static ProfilingDataStore s_TransportProfilerData = new ProfilingDataStore();
    public static bool ProfilerEnabled;

    // Inspector / settings
    public int MessageBufferSize = 1024 * 5;
    public int MaxConnections = 100;
    public int MaxSentMessageQueueSize = 128;

    public string ConnectAddress = "127.0.0.1";
    public int ConnectPort = 7777;
    public int ServerListenPort = 7777;
    public int ServerWebsocketListenPort = 8887;
    public bool SupportWebsocket = false;

    // user-definable channels.  To add your own channel, do something of the form:
    //  #define MY_CHANNEL 0
    //  ...
    //  transport.Channels.Add(
    //     new UNetChannel()
    //       {
    //         Id = Channel.ChannelUnused + MY_CHANNEL,  <<-- must offset from reserved channel offset in MLAPI SDK
    //         Type = QosType.Unreliable
    //       }
    //  );
    public List<UNetChannel> Channels = new List<UNetChannel>();

    // Relay
    public bool UseMLAPIRelay = false;
    public string MLAPIRelayAddress = "184.72.104.138";
    public int MLAPIRelayPort = 8888;

    public SendMode MessageSendMode = SendMode.Immediately;

    // Runtime / state
    private byte[] m_MessageBuffer;
    private WeakReference m_TemporaryBufferReference;

    // Lookup / translation
    private readonly Dictionary<NetworkChannel, int> m_ChannelNameToId = new Dictionary<NetworkChannel, int>();
    private readonly Dictionary<int, NetworkChannel> m_ChannelIdToName = new Dictionary<int, NetworkChannel>();
    private int m_ServerConnectionId;
    private int m_ServerHostId;

    private SocketTask m_ConnectTask;
    public override ulong ServerClientId => GetMLAPIClientId(0, 0, true);

    protected void LateUpdate()
    {
        if (UnityEngine.Networking.NetworkTransport.IsStarted && MessageSendMode == SendMode.Queued)
        {
            if (NetworkManager.Singleton.IsServer)
            {
                for (int i = 0; i < NetworkManager.Singleton.ConnectedClientsList.Count; i++)
                {
                    SendQueued(NetworkManager.Singleton.ConnectedClientsList[i].ClientId);
                }
            }
            else
            {
                SendQueued(NetworkManager.Singleton.LocalClientId);
            }
        }
    }

    public override void Send(ulong clientId, ArraySegment<byte> data, NetworkChannel networkChannel)
    {
        if (ProfilerEnabled)
        {
            s_TransportProfilerData.Increment(ProfilerConstants.NumberOfTransportSends);
        }

        GetUNetConnectionDetails(clientId, out byte hostId, out ushort connectionId);

        int channelId = 0;

        if (m_ChannelNameToId.ContainsKey(networkChannel))
        {
            channelId = m_ChannelNameToId[networkChannel];
        }
        else
        {
            channelId = m_ChannelNameToId[NetworkChannel.Internal];
        }

        byte[] buffer;

        if (data.Offset > 0)
        {
            // UNET cant handle this, do a copy

            if (m_MessageBuffer.Length >= data.Count)
            {
                buffer = m_MessageBuffer;
            }
            else
            {
                object bufferRef = null;
                if (m_TemporaryBufferReference != null && ((bufferRef = m_TemporaryBufferReference.Target) != null) && ((byte[])bufferRef).Length >= data.Count)
                {
                    buffer = (byte[])bufferRef;
                }
                else
                {
                    buffer = new byte[data.Count];
                    m_TemporaryBufferReference = new WeakReference(buffer);
                }
            }

            Buffer.BlockCopy(data.Array, data.Offset, buffer, 0, data.Count);
        }
        else
        {
            buffer = data.Array;
        }

        if (MessageSendMode == SendMode.Queued)
        {

#if !UNITY_WEBGL
RelayTransport.QueueMessageForSending(hostId, connectionId, channelId, buffer, data.Count, out byte error);
#endif
}
else
{
RelayTransport.Send(hostId, connectionId, channelId, buffer, data.Count, out byte error);
}
}

    public void SendQueued(ulong clientId)
    {
        if (ProfilerEnabled)
        {
            s_TransportProfilerData.Increment(ProfilerConstants.NumberOfTransportSendQueues);
        }

        GetUNetConnectionDetails(clientId, out byte hostId, out ushort connectionId);

#if !UNITY_WEBGL
RelayTransport.SendQueuedMessages(hostId, connectionId, out byte error);
#endif
}

    public override NetworkEvent PollEvent(out ulong clientId, out NetworkChannel networkChannel, out ArraySegment<byte> payload, out float receiveTime)
    {
        var eventType = RelayTransport.Receive(out int hostId, out int connectionId, out int channelId, m_MessageBuffer, m_MessageBuffer.Length, out int receivedSize, out byte error);

        clientId = GetMLAPIClientId((byte)hostId, (ushort)connectionId, false);
        receiveTime = UnityEngine.Time.realtimeSinceStartup;

        var networkError = (NetworkError)error;
        if (networkError == NetworkError.MessageToLong)
        {
            byte[] tempBuffer;

            if (m_TemporaryBufferReference != null && m_TemporaryBufferReference.IsAlive && ((byte[])m_TemporaryBufferReference.Target).Length >= receivedSize)
            {
                tempBuffer = (byte[])m_TemporaryBufferReference.Target;
            }
            else
            {
                tempBuffer = new byte[receivedSize];
                m_TemporaryBufferReference = new WeakReference(tempBuffer);
            }

            eventType = RelayTransport.Receive(out hostId, out connectionId, out channelId, tempBuffer, tempBuffer.Length, out receivedSize, out error);
            payload = new ArraySegment<byte>(tempBuffer, 0, receivedSize);
        }
        else
        {
            payload = new ArraySegment<byte>(m_MessageBuffer, 0, receivedSize);
        }

        if (m_ChannelIdToName.ContainsKey(channelId))
        {
            networkChannel = m_ChannelIdToName[channelId];
        }
        else
        {
            networkChannel = NetworkChannel.Internal;
        }

        if (m_ConnectTask != null && hostId == m_ServerHostId && connectionId == m_ServerConnectionId)
        {
            if (eventType == NetworkEventType.ConnectEvent)
            {
                // We just got a response to our connect request.
                m_ConnectTask.Message = null;
                m_ConnectTask.SocketError = networkError == NetworkError.Ok ? System.Net.Sockets.SocketError.Success : System.Net.Sockets.SocketError.SocketError;
                m_ConnectTask.State = null;
                m_ConnectTask.Success = networkError == NetworkError.Ok;
                m_ConnectTask.TransportCode = (byte)networkError;
                m_ConnectTask.TransportException = null;
                m_ConnectTask.IsDone = true;

                m_ConnectTask = null;
            }
            else if (eventType == NetworkEventType.DisconnectEvent)
            {
                // We just got a response to our connect request.
                m_ConnectTask.Message = null;
                m_ConnectTask.SocketError = System.Net.Sockets.SocketError.SocketError;
                m_ConnectTask.State = null;
                m_ConnectTask.Success = false;
                m_ConnectTask.TransportCode = (byte)networkError;
                m_ConnectTask.TransportException = null;
                m_ConnectTask.IsDone = true;

                m_ConnectTask = null;
            }
        }

        if (networkError == NetworkError.Timeout)
        {
            // In UNET. Timeouts are not disconnects. We have to translate that here.
            eventType = NetworkEventType.DisconnectEvent;
        }

        // Translate NetworkEventType to NetEventType
        switch (eventType)
        {
            case NetworkEventType.DataEvent:
                return NetworkEvent.Data;
            case NetworkEventType.ConnectEvent:
                return NetworkEvent.Connect;
            case NetworkEventType.DisconnectEvent:
                return NetworkEvent.Disconnect;
            case NetworkEventType.Nothing:
                return NetworkEvent.Nothing;
            case NetworkEventType.BroadcastEvent:
                return NetworkEvent.Nothing;
        }

        return NetworkEvent.Nothing;
    }

    public override SocketTasks StartClient()
    {
        var socketTask = SocketTask.Working;

        m_ServerHostId = RelayTransport.AddHost(new HostTopology(GetConfig(), 1), false);
        m_ServerConnectionId = RelayTransport.Connect(m_ServerHostId, ConnectAddress, ConnectPort, 0, out byte error);

        var connectError = (NetworkError)error;

        switch (connectError)
        {
            case NetworkError.Ok:
                socketTask.Success = true;
                socketTask.TransportCode = error;
                socketTask.SocketError = System.Net.Sockets.SocketError.Success;
                socketTask.IsDone = false;

                // We want to continue to wait for the successful connect
                m_ConnectTask = socketTask;
                break;
            default:
                socketTask.Success = false;
                socketTask.TransportCode = error;
                socketTask.SocketError = System.Net.Sockets.SocketError.SocketError;
                socketTask.IsDone = true;
                break;
        }

        return socketTask.AsTasks();
    }

    public override SocketTasks StartServer()
    {
        var topology = new HostTopology(GetConfig(), MaxConnections);

        if (SupportWebsocket)
        {
            if (!UseMLAPIRelay)
            {
                int websocketHostId = UnityEngine.Networking.NetworkTransport.AddWebsocketHost(topology, ServerWebsocketListenPort);
            }
            else
            {
                if (NetworkLog.CurrentLogLevel <= LogLevel.Error) NetworkLog.LogError("Cannot create websocket host when using MLAPI relay");
            }
        }

        int normalHostId = RelayTransport.AddHost(topology, ServerListenPort, true);

        return SocketTask.Done.AsTasks();
    }

    public override void DisconnectRemoteClient(ulong clientId)
    {
        GetUNetConnectionDetails(clientId, out byte hostId, out ushort connectionId);

        RelayTransport.Disconnect((int)hostId, (int)connectionId, out byte error);
    }

    public override void DisconnectLocalClient()
    {
        RelayTransport.Disconnect(m_ServerHostId, m_ServerConnectionId, out byte error);
    }

    public override ulong GetCurrentRtt(ulong clientId)
    {
        GetUNetConnectionDetails(clientId, out byte hostId, out ushort connectionId);

        if (UseMLAPIRelay)
        {
            return 0;
        }
        else
        {
            return (ulong)UnityEngine.Networking.NetworkTransport.GetCurrentRTT((int)hostId, (int)connectionId, out byte error);
        }
    }

    public override void Shutdown()
    {
        m_ChannelIdToName.Clear();
        m_ChannelNameToId.Clear();
        UnityEngine.Networking.NetworkTransport.Shutdown();
    }

    public override void Init()
    {
        UpdateRelay();

        m_MessageBuffer = new byte[MessageBufferSize];

        s_TransportProfilerData.Clear();

        UnityEngine.Networking.NetworkTransport.Init();
    }

    public ulong GetMLAPIClientId(byte hostId, ushort connectionId, bool isServer)
    {
        if (isServer)
        {
            return 0;
        }
        else
        {
            return ((ulong)connectionId | (ulong)hostId << 16) + 1;
        }
    }

    public void GetUNetConnectionDetails(ulong clientId, out byte hostId, out ushort connectionId)
    {
        if (clientId == 0)
        {
            hostId = (byte)m_ServerHostId;
            connectionId = (ushort)m_ServerConnectionId;
        }
        else
        {
            hostId = (byte)((clientId - 1) >> 16);
            connectionId = (ushort)((clientId - 1));
        }
    }

    public ConnectionConfig GetConfig()
    {
        var connectionConfig = new ConnectionConfig();

        // MLAPI built-in channels
        for (int i = 0; i < MLAPI_CHANNELS.Length; i++)
        {
            int channelId = AddMLAPIChannel(MLAPI_CHANNELS[i].Delivery, connectionConfig);

            m_ChannelIdToName.Add(channelId, MLAPI_CHANNELS[i].Channel);
            m_ChannelNameToId.Add(MLAPI_CHANNELS[i].Channel, channelId);
        }

        // Custom user-added channels
        for (int i = 0; i < Channels.Count; i++)
        {
            int channelId = AddUNETChannel(Channels[i].Type, connectionConfig);

            if (m_ChannelNameToId.ContainsKey(Channels[i].Id))
            {
                throw new InvalidChannelException($"Channel {channelId} already exists");
            }

            m_ChannelIdToName.Add(channelId, Channels[i].Id);
            m_ChannelNameToId.Add(Channels[i].Id, channelId);
        }

        connectionConfig.MaxSentMessageQueueSize = (ushort)MaxSentMessageQueueSize;

        return connectionConfig;
    }

    public int AddMLAPIChannel(NetworkDelivery type, ConnectionConfig config)
    {
        switch (type)
        {
            case NetworkDelivery.Unreliable:
                return config.AddChannel(QosType.Unreliable);
            case NetworkDelivery.Reliable:
                return config.AddChannel(QosType.Reliable);
            case NetworkDelivery.ReliableSequenced:
                return config.AddChannel(QosType.ReliableSequenced);
            case NetworkDelivery.ReliableFragmentedSequenced:
                return config.AddChannel(QosType.ReliableFragmentedSequenced);
            case NetworkDelivery.UnreliableSequenced:
                return config.AddChannel(QosType.UnreliableSequenced);
        }

        return 0;
    }

    public int AddUNETChannel(QosType type, ConnectionConfig config)
    {
        switch (type)
        {
            case QosType.Unreliable:
                return config.AddChannel(QosType.Unreliable);
            case QosType.UnreliableFragmented:
                return config.AddChannel(QosType.UnreliableFragmented);
            case QosType.UnreliableSequenced:
                return config.AddChannel(QosType.UnreliableSequenced);
            case QosType.Reliable:
                return config.AddChannel(QosType.Reliable);
            case QosType.ReliableFragmented:
                return config.AddChannel(QosType.ReliableFragmented);
            case QosType.ReliableSequenced:
                return config.AddChannel(QosType.ReliableSequenced);
            case QosType.StateUpdate:
                return config.AddChannel(QosType.StateUpdate);
            case QosType.ReliableStateUpdate:
                return config.AddChannel(QosType.ReliableStateUpdate);
            case QosType.AllCostDelivery:
                return config.AddChannel(QosType.AllCostDelivery);
            case QosType.UnreliableFragmentedSequenced:
                return config.AddChannel(QosType.UnreliableFragmentedSequenced);
            case QosType.ReliableFragmentedSequenced:
                return config.AddChannel(QosType.ReliableFragmentedSequenced);
        }

        return 0;
    }

    private void UpdateRelay()
    {
        RelayTransport.Enabled = UseMLAPIRelay;
        RelayTransport.RelayAddress = MLAPIRelayAddress;
        RelayTransport.RelayPort = (ushort)MLAPIRelayPort;
    }

    public void BeginNewTick()
    {
        s_TransportProfilerData.Clear();
    }

    public IReadOnlyDictionary<string, int> GetTransportProfilerData()
    {
        return s_TransportProfilerData.GetReadonly();
    }
}

}
#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
#pragma warning restore 618

@theomonnom
Copy link

theomonnom commented Mar 10, 2022

Unity-Technologies/multiplayer-community-contributions#136
Since the last version, this is unusable on WebGL

@ashwinimurt
Copy link
Contributor

Tracked in our backlog MTT-3061

@ashwinimurt ashwinimurt added stat:backlog Status - Issue could be considered for a future release. and removed stat:commited Status - Commited to work on this issue. labels Mar 30, 2022
@ashwinimurt ashwinimurt added the stat:awaiting triage Status - Awaiting triage from the Netcode team. label Aug 1, 2022
@ashwinimurt
Copy link
Contributor

ashwinimurt commented Aug 1, 2022

Does not work with recent NGO. Linking duplicate issue: #1962 and
Tracked in our backlog MTT-4088

@ashwinimurt ashwinimurt added the stat:imported Status - Issue is tracked internally at Unity label Aug 1, 2022
@ashwinimurt ashwinimurt self-assigned this Aug 22, 2022
@ashwinimurt ashwinimurt added priority:high and removed stat:awaiting triage Status - Awaiting triage from the Netcode team. labels Aug 22, 2022
@jeffreyrainy
Copy link
Contributor

Netcode for GameObjects building on WebGL is now possible, after
#2199

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue Contributions are welcome. Good first issue for newcomers or first time contributors. priority:high stat:backlog Status - Issue could be considered for a future release. stat:imported Status - Issue is tracked internally at Unity type:bug Bug Report
Projects
None yet
Development

No branches or pull requests