Giter VIP home page Giter VIP logo

epiconlinetransport's Introduction

EpicOnlineTransport for Mirror

Hi! This is our Epic Online Services (EOS) transport for Mirror. We developed it for our game Nimoyd, it is still under development, but already working without any problems.

Video Tutorials

Dependencies

Setting Up Epic Online Services and Obtaining API Keys

  1. Login to the Epic Games Dev Portal with an Epic Games Account
  2. Create a new Product
  3. Go to Product Settings -> Clients and add a new Client Policy
  4. Name your Client Policy and set the Client Policy Type to Peer2Peer, then Save & Exit
  5. Add a new Client
  6. Name your Client and set the Client Policy to the Client Policy you just created, then Save & Exit
  7. Go to Epic Account Services -> Configure Application
  8. Set Application Name to what you want your users to see when signing in with the Account Portal, then Save Draft
  9. Go to Permissions and set all permissions to Required, then Save
  10. Go to Clients and set the Client to the Client you just created, then Save
  11. Go back, then click Back to Organization
  12. Go to SDK -> SDK Credentials -> Get Credentials
  13. Copy and paste all of your credentials into the EOS API Key Asset once your project is set up

Installation

  1. Visit the Mirror Asset Store Page and add Mirror to My Assets
  2. Import Mirror with Package Manager (Window -> Package Manager -> Packages: My Assets -> Mirror -> Download)
  3. Download the latest master branch, unpack it and copy the Plugin and the Mirror folder into your project (merge with already existing folders).
  4. Attach an EOSSDKComponent to a GameObject in your Scene
  5. Right click in the Project View and create an EOS API Key Asset (Create -> EOS -> API Key)
  6. Fill out all the SDK keys on the EOS API Key Asset, you can find them in the Epic Online Services Dev Portal (SDK -> SDK Credentials -> Get Credentials)
  7. Move the EOS API Key Asset into the 'Api Keys' slot on the EOSSDKComponent
  8. Attach a NetworkManager to a GameObject in your Scene
  9. Attach an EosTransport component to the same GameObject as the NetworkManager
  10. Move the EosTransport component into the 'Transport' slot on the NetworkManager
  11. (Optional) Add an EOSLobbyUI component, a NetworkManagerHUD component, or a NetworkDiscoveryHUD component to test that the transport is working properly
  12. Change the Auth Interface Credential Type and Connect Interface Credential Types on the EOSSDKComponent to suit the needs of your project

Building for Android

  1. Install the Android Module through Unity Hub
  2. Switch platform to Android in Build Settings
  3. In Unity -> Edit -> Project Settings... -> Player -> Android -> Other Settings -> Identification set Minimum API Level to Android 6.0 'Marshmallow' (API Level 23) as required by the EOS Android SDK
  4. (Optional) Install Android Logcat through Package Manager to see logs when running on Android device over USB (Window -> Package Manager -> Packages: Unity Registry -> Android Logcat -> Install) then open with Alt+6 or Window -> Analysis -> Android Logcat

Testing multiplayer on one device

Running multiple instances of your game on one device for testing requires you to have multiple epic accounts. Even if your game doesn't use epic accounts you will need them for testing.

  1. Add all epic accounts you want to test with to your organization in the dev portal
  2. On the EOSSDKComponent under User Login set Auth Interface Login to true
  3. Choose 'Developer' as Auth Interface Credential Type
  4. Choose 'Epic' as Connect Interface Credential Type
  5. Open the epic transport folder with a file explorer and go into the DevAuthTool folder
  6. Create a folder that ends with ~ e.g. Tool~, this makes unity ignore this folder
  7. Unzip the dev auth tool for your OS (Mac/Win) into the folder you created in step 5.
  8. Run the dev auth tool
  9. Enter a port in the dev auth tool
  10. Login to your epic account and give the credential a name
  11. Repeat step 9 for as many accounts you want to use
  12. On the EOSSDKComponent set the port to the one you used in the dev auth tool
  13. On the EOSSDKCOmponent set Dev Auth Tool Credential Name to the named you chose in the tool

Note: In the editor after logging in with the dev auth tool you cant change the credential name as the sdk stays initialized even after finish playing. You either have to restart unity or the dev auth tool. For builds it is useful to set delayed initialization on the EOSSDKComponent to true and then provide a user input field to set the dev tool credential name and then calling EOSSDKComponent.Initialize().

Connecting to other users

You need the epic online product id to connect to another user, you can get it by calling:

EOSSDKComponent.LocalUserProductId
or
EOSSDKComponent.LocalUserProductIdString

The string variant can be sent to other users to connect.

Lobbies

You can quickly add lobbies to your game using the pre-built EOSLobbyUI script. The EOSLobbyUI extends the EOSLobby script which has methods for handling lobby creation, joining, finding, and leaving and has many events that you can subscribe to. To make the EOSLobbyUI work, create a GameObject, and add the script. If you don't have an EOSSDKComponent present in the scene, make sure to add it to the GameObject. If you prefer to create your own UI for lobbies, you can reference the EOSLobbyUI script.

NOTE: The EOSLobby script creates lobbies with the host address predefined. You can get the host address from the JoinLobbySucceeded event so you can establish a connection using Mirror.

EOSLobbyUI Features

The EOSLobbyUI allows for a fast implementation of lobbies in your project and it is also an example of what you can do. Here are the features:

  • Creating a lobby with a name
  • Lobby list that displays the name and player count
  • Joining
  • Leaving (If the owner of the lobby leaves, then the lobby will be destroyed)

Credits

Big thanks to erikas-taroza aka TypicalEgg for his help in improving and extending this transport!

epiconlinetransport's People

Contributors

creepyant avatar danieltizon avatar danieltizondev avatar erikas-taroza avatar fakebyte avatar friendly-banana avatar jeremyeastham avatar liam-harrison avatar molder72 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

epiconlinetransport's Issues

Object referance not set to an instance of an object

I keep getting this error

NullReferenceException: Object reference not set to an instance of an object EpicTransport.EOSSDKComponent.Tick () (at Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDKComponent.cs:147) EpicTransport.EosTransport.ServerEarlyUpdate () (at Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EosTransport.cs:106) Mirror.NetworkServer.NetworkEarlyUpdate () (at Assets/Mirror/Runtime/NetworkServer.cs:1717) Mirror.NetworkLoop.NetworkEarlyUpdate () (at Assets/Mirror/Runtime/NetworkLoop.cs:193)

EosTransport should call OnClientDisconnected when client disconnects

Talking about these lines: https://github.com/FakeByte/EpicOnlineTransport/blob/master/Mirror/Runtime/Transport/EpicOnlineTransport/EosTransport.cs#L160-L163

ClientDisconnect should call OnClientDisconnected, which will call NetworkClient.OnTransportDisconnected, which will removes transport handlers, which clients need to remove anything registered in AddTransportHandlers.

An easy fix would be these lines:

public override void ClientDisconnect()
{
    if (!ClientActive()) return;
    Shutdown();
    OnClientDisconnected();
}

Is there a reason not to call OnClientDisconnected here?

Send failed LimitExceeded

Hi,

I start using it for a 10 player multiplayer p2p game and I have found an error on the library about the package size that are send from server. I think the limit that supports Epic Online is 1170 bytes (I have not found in the documentation), but the max package size that is send is 1178. This is because although it is set the maximun package size to 1169, when the Packet class is converted to bytes, it uses the data (1169 bytes) + id (4 bytes) + fragment (4 bytes) + more fragments (1 byte), resulting in 1178 bytes (the sum can be shown in Packet class).

The solution should be to change the maximun size to 1159, having the next line in EosTransport class:

public int GetMaxSinglePacketSize(int channelId) => P2PInterface.MaxPacketSize - 10;

Thanks.

Absolute file path for libraryPath in EOSSDKComponent.cs

in order to create a unity package I need that this path is absolute, in this way can its work when is place in Asset folder, and in my case when move in Packages folder.

please,
in file EOSSDKComponent.cs

add in line 7
using System.IO;

overwrite line 211
from
var libraryPath = "Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/" + Config.LibraryName;
To
var libraryPath = Path.GetFullPath(Path.Combine("Packages/vis2k.mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/", Config.LibraryName));

thank you

Feature Request: Console Support

I'm currently developing a project and since EOS is meant to be cross platform. I was wondering if this was Cross platform too or only compatible with PC and Android.

No EOS Keys in create menu

I wanted to give this awesome package a go but when I imported there was no EPS key option on the create menu.

When I relaunched it had to enter safe mode, Keep in mind I only have this and Mirror installed.

I'm sure it's just a compatibility issue with my Unity / mirror version so I was wondering what mirror and Unity version the creator is using for their game. Thanks in advance!

Playerprefab doesent spawn, but why?

When I host the player prefab doesn't spawn, and I don't know why.
That is the NetworkManager code:
`using System;
using System.Collections.Generic;
using System.Linq;
using kcp2k;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.Serialization;

namespace Mirror
{
public enum PlayerSpawnMethod { Random, RoundRobin }
public enum NetworkManagerMode { Offline, ServerOnly, ClientOnly, Host }

[DisallowMultipleComponent]
[AddComponentMenu("Network/Network Manager")]
[HelpURL("https://mirror-networking.gitbook.io/docs/components/network-manager")]
public class NetworkManager : MonoBehaviour
{
    /// <summary>Enable to keep NetworkManager alive when changing scenes.</summary>
    // This should be set if your game has a single NetworkManager that exists for the lifetime of the process. If there is a NetworkManager in each scene, then this should not be set.</para>
    [Header("Configuration")]
    [FormerlySerializedAs("m_DontDestroyOnLoad")]
    [Tooltip("Should the Network Manager object be persisted through scene changes?")]
    public bool dontDestroyOnLoad = true;

    /// <summary>Multiplayer games should always run in the background so the network doesn't time out.</summary>
    [FormerlySerializedAs("m_RunInBackground")]
    [Tooltip("Multiplayer games should always run in the background so the network doesn't time out.")]
    public bool runInBackground = true;

    /// <summary>Should the server auto-start when 'Server Build' is checked in build settings</summary>
    [Tooltip("Should the server auto-start when 'Server Build' is checked in build settings")]
    [FormerlySerializedAs("startOnHeadless")]
    public bool autoStartServerBuild = true;

    /// <summary>Server Update frequency, per second. Use around 60Hz for fast paced games like Counter-Strike to minimize latency. Use around 30Hz for games like WoW to minimize computations. Use around 1-10Hz for slow paced games like EVE.</summary>
    [Tooltip("Server Update frequency, per second. Use around 60Hz for fast paced games like Counter-Strike to minimize latency. Use around 30Hz for games like WoW to minimize computations. Use around 1-10Hz for slow paced games like EVE.")]
    public int serverTickRate = 30;

    /// <summary>Automatically switch to this scene upon going offline (on start / on disconnect / on shutdown).</summary>
    [Header("Scene Management")]
    [Scene]
    [FormerlySerializedAs("m_OfflineScene")]
    [Tooltip("Scene that Mirror will switch to when the client or server is stopped")]
    public string offlineScene = "";

    /// <summary>Automatically switch to this scene upon going online (after connect/startserver).</summary>
    [Scene]
    [FormerlySerializedAs("m_OnlineScene")]
    [Tooltip("Scene that Mirror will switch to when the server is started. Clients will recieve a Scene Message to load the server's current scene when they connect.")]
    public string onlineScene = "";

    // transport layer
    [Header("Network Info")]
    [Tooltip("Transport component attached to this object that server and client will use to connect")]
    [SerializeField]
    protected Transport transport;

    /// <summary>Server's address for clients to connect to.</summary>
    [FormerlySerializedAs("m_NetworkAddress")]
    [Tooltip("Network Address where the client should connect to the server. Server does not use this for anything.")]
    public string networkAddress = "localhost";

    /// <summary>The maximum number of concurrent network connections to support.</summary>
    [FormerlySerializedAs("m_MaxConnections")]
    [Tooltip("Maximum number of concurrent connections.")]
    public int maxConnections = 100;

    [Header("Authentication")]
    [Tooltip("Authentication component attached to this object")]
    public NetworkAuthenticator authenticator;

    /// <summary>The default prefab to be used to create player objects on the server.</summary>
    // Player objects are created in the default handler for AddPlayer() on
    // the server. Implementing OnServerAddPlayer overrides this behaviour.
    [Header("Player Object")]
    [FormerlySerializedAs("m_PlayerPrefab")]
    [Tooltip("Prefab of the player object. Prefab must have a Network Identity component. May be an empty game object or a full avatar.")]
    public GameObject playerPrefab;

    /// <summary>Enable to automatically create player objects on connect and on scene change.</summary>
    [FormerlySerializedAs("m_AutoCreatePlayer")]
    [Tooltip("Should Mirror automatically spawn the player after scene change?")]
    public bool autoCreatePlayer = true;

    /// <summary>Where to spawn players.</summary>
    [FormerlySerializedAs("m_PlayerSpawnMethod")]
    [Tooltip("Round Robin or Random order of Start Position selection")]
    public PlayerSpawnMethod playerSpawnMethod;

    /// <summary>Prefabs that can be spawned over the network need to be registered here.</summary>
    [FormerlySerializedAs("m_SpawnPrefabs"), HideInInspector]
    public List<GameObject> spawnPrefabs = new List<GameObject>();

    /// <summary>List of transforms populated by NetworkStartPositions</summary>
    public static List<Transform> startPositions = new List<Transform>();
    public static int startPositionIndex;

    /// <summary>The one and only NetworkManager</summary>
    public static NetworkManager singleton { get; internal set; }

    /// <summary>Number of active player objects across all connections on the server.</summary>
    public int numPlayers => NetworkServer.connections.Count(kv => kv.Value.identity != null);

    /// <summary>True if the server is running or client is connected/connecting.</summary>
    public bool isNetworkActive => NetworkServer.active || NetworkClient.active;

    // TODO remove this
    // internal for tests
    internal static NetworkConnection clientReadyConnection;

    /// <summary>True if the client loaded a new scene when connecting to the server.</summary>
    // This is set before OnClientConnect is called, so it can be checked
    // there to perform different logic if a scene load occurred.
    protected bool clientLoadedScene;

    // helper enum to know if we started the networkmanager as server/client/host.
    // -> this is necessary because when StartHost changes server scene to
    //    online scene, FinishLoadScene is called and the host client isn't
    //    connected yet (no need to connect it before server was fully set up).
    //    in other words, we need this to know which mode we are running in
    //    during FinishLoadScene.
    public NetworkManagerMode mode { get; private set; }

    // virtual so that inheriting classes' OnValidate() can call base.OnValidate() too
    public virtual void OnValidate()
    {
        // always >= 0
        maxConnections = Mathf.Max(maxConnections, 0);

        if (playerPrefab != null && playerPrefab.GetComponent<NetworkIdentity>() == null)
        {
            Debug.LogError("NetworkManager - Player Prefab must have a NetworkIdentity.");
            playerPrefab = null;
        }

        // This avoids the mysterious "Replacing existing prefab with assetId ... Old prefab 'Player', New prefab 'Player'" warning.
        if (playerPrefab != null && spawnPrefabs.Contains(playerPrefab))
        {
            Debug.LogWarning("NetworkManager - Player Prefab should not be added to Registered Spawnable Prefabs list...removed it.");
            spawnPrefabs.Remove(playerPrefab);
        }
    }

    // virtual so that inheriting classes' Reset() can call base.Reset() too
    // Reset only gets called when the component is added or the user resets the component
    // Thats why we validate these things that only need to be validated on adding the NetworkManager here
    // If we would do it in OnValidate() then it would run this everytime a value changes
    public virtual void Reset()
    {
        // make sure someone doesn't accidentally add another NetworkManager
        // need transform.root because when adding to a child, the parent's
        // Reset isn't called.
        foreach (NetworkManager manager in transform.root.GetComponentsInChildren<NetworkManager>())
        {
            if (manager != this)
            {
                Debug.LogError($"{name} detected another component of type {typeof(NetworkManager)} in its hierarchy on {manager.name}. There can only be one, please remove one of them.");
                // return early so that transport component isn't auto-added
                // to the duplicate NetworkManager.
                return;
            }
        }

        // add transport if there is none yet. makes upgrading easier.
        if (transport == null)
        {

#if UNITY_EDITOR
// RecordObject needs to be called before we make the change
UnityEditor.Undo.RecordObject(gameObject, "Added default Transport");
#endif

            transport = GetComponent<Transport>();

            // was a transport added yet? if not, add one
            if (transport == null)
            {
                transport = gameObject.AddComponent<KcpTransport>();
                Debug.Log("NetworkManager: added default Transport because there was none yet.");
            }
        }
    }

    // virtual so that inheriting classes' Awake() can call base.Awake() too
    public virtual void Awake()
    {
        // Don't allow collision-destroyed second instance to continue.
        if (!InitializeSingleton()) return;

        Debug.Log("Mirror | mirror-networking.com | discord.gg/N9QVxbM");

        // Set the networkSceneName to prevent a scene reload
        // if client connection to server fails.
        networkSceneName = offlineScene;

        // setup OnSceneLoaded callback
        SceneManager.sceneLoaded += OnSceneLoaded;
    }

    // virtual so that inheriting classes' Start() can call base.Start() too
    public virtual void Start()
    {
        // headless mode? then start the server
        // can't do this in Awake because Awake is for initialization.
        // some transports might not be ready until Start.
        //
        // (tick rate is applied in StartServer!)

#if UNITY_SERVER
if (autoStartServerBuild)
{
StartServer();
}
#endif
}

    // virtual so that inheriting classes' LateUpdate() can call base.LateUpdate() too
    public virtual void LateUpdate()
    {
        UpdateScene();
    }

    // keep the online scene change check in a separate function
    bool IsServerOnlineSceneChangeNeeded()
    {
        // Only change scene if the requested online scene is not blank, and is not already loaded
        return !string.IsNullOrWhiteSpace(onlineScene) && !IsSceneActive(onlineScene) && onlineScene != offlineScene;
    }

    public static bool IsSceneActive(string scene)
    {
        Scene activeScene = SceneManager.GetActiveScene();
        return activeScene.path == scene || activeScene.name == scene;
    }

    // full server setup code, without spawning objects yet
    void SetupServer()
    {
        // Debug.Log("NetworkManager SetupServer");
        InitializeSingleton();

        if (runInBackground)
            Application.runInBackground = true;

        if (authenticator != null)
        {
            authenticator.OnStartServer();
            authenticator.OnServerAuthenticated.AddListener(OnServerAuthenticated);
        }

        ConfigureHeadlessFrameRate();

        // start listening to network connections
        NetworkServer.Listen(maxConnections);

        // call OnStartServer AFTER Listen, so that NetworkServer.active is
        // true and we can call NetworkServer.Spawn in OnStartServer
        // overrides.
        // (useful for loading & spawning stuff from database etc.)
        //
        // note: there is no risk of someone connecting after Listen() and
        //       before OnStartServer() because this all runs in one thread
        //       and we don't start processing connects until Update.
        OnStartServer();

        // this must be after Listen(), since that registers the default message handlers
        RegisterServerMessages();
    }

    /// <summary>Starts the server, listening for incoming connections.</summary>
    public void StartServer()
    {
        if (NetworkServer.active)
        {
            Debug.LogWarning("Server already started.");
            return;
        }

        mode = NetworkManagerMode.ServerOnly;

        // StartServer is inherently ASYNCHRONOUS (=doesn't finish immediately)
        //
        // Here is what it does:
        //   Listen
        //   if onlineScene:
        //       LoadSceneAsync
        //       ...
        //       FinishLoadSceneServerOnly
        //           SpawnObjects
        //   else:
        //       SpawnObjects
        //
        // there is NO WAY to make it synchronous because both LoadSceneAsync
        // and LoadScene do not finish loading immediately. as long as we
        // have the onlineScene feature, it will be asynchronous!

        SetupServer();

        // scene change needed? then change scene and spawn afterwards.
        if (IsServerOnlineSceneChangeNeeded())
        {
            ServerChangeScene(onlineScene);
        }
        // otherwise spawn directly
        else
        {
            NetworkServer.SpawnObjects();
        }
    }

    /// <summary>Starts the client, connects it to the server with networkAddress.</summary>
    public void StartClient()
    {
        if (NetworkClient.active)
        {
            Debug.LogWarning("Client already started.");
            return;
        }

        mode = NetworkManagerMode.ClientOnly;

        InitializeSingleton();

        if (runInBackground)
            Application.runInBackground = true;

        if (authenticator != null)
        {
            authenticator.OnStartClient();
            authenticator.OnClientAuthenticated.AddListener(OnClientAuthenticated);
        }

        // In case this is a headless client...
        ConfigureHeadlessFrameRate();

        RegisterClientMessages();

        if (string.IsNullOrWhiteSpace(networkAddress))
        {
            Debug.LogError("Must set the Network Address field in the manager");
            return;
        }
        // Debug.Log($"NetworkManager StartClient address:{networkAddress}");

        NetworkClient.Connect(networkAddress);

        OnStartClient();
    }

    /// <summary>Starts the client, connects it to the server via Uri</summary>
    public void StartClient(Uri uri)
    {
        if (NetworkClient.active)
        {
            Debug.LogWarning("Client already started.");
            return;
        }

        mode = NetworkManagerMode.ClientOnly;

        InitializeSingleton();

        if (runInBackground)
            Application.runInBackground = true;

        if (authenticator != null)
        {
            authenticator.OnStartClient();
            authenticator.OnClientAuthenticated.AddListener(OnClientAuthenticated);
        }

        RegisterClientMessages();

        // Debug.Log($"NetworkManager StartClient address:{uri}");
        networkAddress = uri.Host;

        NetworkClient.Connect(uri);

        OnStartClient();
    }

    /// <summary>Starts a network "host" - a server and client in the same application.</summary>
    public void StartHost()
    {
        if (NetworkServer.active || NetworkClient.active)
        {
            Debug.LogWarning("Server or Client already started.");
            return;
        }

        mode = NetworkManagerMode.Host;

        // StartHost is inherently ASYNCHRONOUS (=doesn't finish immediately)
        //
        // Here is what it does:
        //   Listen
        //   ConnectHost
        //   if onlineScene:
        //       LoadSceneAsync
        //       ...
        //       FinishLoadSceneHost
        //           FinishStartHost
        //               SpawnObjects
        //               StartHostClient      <= not guaranteed to happen after SpawnObjects if onlineScene is set!
        //                   ClientAuth
        //                       success: server sends changescene msg to client
        //   else:
        //       FinishStartHost
        //
        // there is NO WAY to make it synchronous because both LoadSceneAsync
        // and LoadScene do not finish loading immediately. as long as we
        // have the onlineScene feature, it will be asynchronous!

        // setup server first
        SetupServer();

        // call OnStartHost AFTER SetupServer. this way we can use
        // NetworkServer.Spawn etc. in there too. just like OnStartServer
        // is called after the server is actually properly started.
        OnStartHost();

        // scene change needed? then change scene and spawn afterwards.
        // => BEFORE host client connects. if client auth succeeds then the
        //    server tells it to load 'onlineScene'. we can't do that if
        //    server is still in 'offlineScene'. so load on server first.
        if (IsServerOnlineSceneChangeNeeded())
        {
            // call FinishStartHost after changing scene.
            finishStartHostPending = true;
            ServerChangeScene(onlineScene);
            print("ServerChangeScene sucessfully");
        }
        // otherwise call FinishStartHost directly
        else
        {
            FinishStartHost();
        }
    }

    // This may be set true in StartHost and is evaluated in FinishStartHost
    bool finishStartHostPending;

    // FinishStartHost is guaranteed to be called after the host server was
    // fully started and all the asynchronous StartHost magic is finished
    // (= scene loading), or immediately if there was no asynchronous magic.
    //
    // note: we don't really need FinishStartClient/FinishStartServer. the
    //       host version is enough.
    void FinishStartHost()
    {
        // ConnectHost needs to be called BEFORE SpawnObjects:
        // https://github.com/vis2k/Mirror/pull/1249/
        // -> this sets NetworkServer.localConnection.
        // -> localConnection needs to be set before SpawnObjects because:
        //    -> SpawnObjects calls OnStartServer in all NetworkBehaviours
        //       -> OnStartServer might spawn an object and set [SyncVar(hook="OnColorChanged")] object.color = green;
        //          -> this calls SyncVar.set (generated by Weaver), which has
        //             a custom case for host mode (because host mode doesn't
        //             get OnDeserialize calls, where SyncVar hooks are usually
        //             called):
        //
        //               if (!SyncVarEqual(value, ref color))
        //               {
        //                   if (NetworkServer.localClientActive && !getSyncVarHookGuard(1uL))
        //                   {
        //                       setSyncVarHookGuard(1uL, value: true);
        //                       OnColorChangedHook(value);
        //                       setSyncVarHookGuard(1uL, value: false);
        //                   }
        //                   SetSyncVar(value, ref color, 1uL);
        //               }
        //
        //          -> localClientActive needs to be true, otherwise the hook
        //             isn't called in host mode!
        //
        // TODO call this after spawnobjects and worry about the syncvar hook fix later?
        NetworkClient.ConnectHost();

        // server scene was loaded. now spawn all the objects
        NetworkServer.SpawnObjects();

        // connect client and call OnStartClient AFTER server scene was
        // loaded and all objects were spawned.
        // DO NOT do this earlier. it would cause race conditions where a
        // client will do things before the server is even fully started.
        //Debug.Log("StartHostClient called");
        StartHostClient();
    }

    void StartHostClient()
    {
        //Debug.Log("NetworkManager ConnectLocalClient");

        if (authenticator != null)
        {
            authenticator.OnStartClient();
            authenticator.OnClientAuthenticated.AddListener(OnClientAuthenticated);
        }

        networkAddress = "localhost";
        NetworkServer.ActivateHostScene();
        RegisterClientMessages();

        // ConnectLocalServer needs to be called AFTER RegisterClientMessages
        // (https://github.com/vis2k/Mirror/pull/1249/)
        NetworkClient.ConnectLocalServer();

        OnStartClient();
    }

    /// <summary>This stops both the client and the server that the manager is using.</summary>
    public void StopHost()
    {
        OnStopHost();

        // calling OnTransportDisconnected was needed to fix
        // https://github.com/vis2k/Mirror/issues/1515
        // so that the host client receives a DisconnectMessage
        // TODO reevaluate if this is still needed after all the disconnect
        //      fixes, and try to put this into LocalConnection.Disconnect!
        NetworkServer.OnTransportDisconnected(NetworkConnection.LocalConnectionId);

        StopClient();
        StopServer();
    }

    /// <summary>Stops the server from listening and simulating the game.</summary>
    public void StopServer()
    {
        // return if already stopped to avoid recursion deadlock
        if (!NetworkServer.active)
            return;

        if (authenticator != null)
        {
            authenticator.OnServerAuthenticated.RemoveListener(OnServerAuthenticated);
            authenticator.OnStopServer();
        }

        // Get Network Manager out of DDOL before going to offline scene
        // to avoid collision and let a fresh Network Manager be created.
        // IMPORTANT: .gameObject can be null if StopClient is called from
        //            OnApplicationQuit or from tests!
        if (gameObject != null
            && gameObject.scene.name == "DontDestroyOnLoad"
            && !string.IsNullOrWhiteSpace(offlineScene)
            && SceneManager.GetActiveScene().path != offlineScene)
            SceneManager.MoveGameObjectToScene(gameObject, SceneManager.GetActiveScene());

        OnStopServer();

        //Debug.Log("NetworkManager StopServer");
        NetworkServer.Shutdown();

        // set offline mode BEFORE changing scene so that FinishStartScene
        // doesn't think we need initialize anything.
        mode = NetworkManagerMode.Offline;

        if (!string.IsNullOrWhiteSpace(offlineScene))
        {
            ServerChangeScene(offlineScene);
        }

        startPositionIndex = 0;

        networkSceneName = "";
    }

    /// <summary>Stops and disconnects the client.</summary>
    public void StopClient()
    {
        if (mode == NetworkManagerMode.Offline)
            return;

        if (authenticator != null)
        {
            authenticator.OnClientAuthenticated.RemoveListener(OnClientAuthenticated);
            authenticator.OnStopClient();
        }

        // Get Network Manager out of DDOL before going to offline scene
        // to avoid collision and let a fresh Network Manager be created.
        // IMPORTANT: .gameObject can be null if StopClient is called from
        //            OnApplicationQuit or from tests!
        if (gameObject != null
            && gameObject.scene.name == "DontDestroyOnLoad"
            && !string.IsNullOrWhiteSpace(offlineScene)
            && SceneManager.GetActiveScene().path != offlineScene)
            SceneManager.MoveGameObjectToScene(gameObject, SceneManager.GetActiveScene());

        OnStopClient();

        //Debug.Log("NetworkManager StopClient");

        // set offline mode BEFORE changing scene so that FinishStartScene
        // doesn't think we need initialize anything.
        // set offline mode BEFORE NetworkClient.Disconnect so StopClient
        // only runs once.
        mode = NetworkManagerMode.Offline;

        // shutdown client
        NetworkClient.Disconnect();
        NetworkClient.Shutdown();

        // If this is the host player, StopServer will already be changing scenes.
        // Check loadingSceneAsync to ensure we don't double-invoke the scene change.
        // Check if NetworkServer.active because we can get here via Disconnect before server has started to change scenes.
        if (!string.IsNullOrWhiteSpace(offlineScene) && !IsSceneActive(offlineScene) && loadingSceneAsync == null && !NetworkServer.active)
        {
            ClientChangeScene(offlineScene, SceneOperation.Normal);
        }

        networkSceneName = "";
    }

    // called when quitting the application by closing the window / pressing
    // stop in the editor. virtual so that inheriting classes'
    // OnApplicationQuit() can call base.OnApplicationQuit() too
    public virtual void OnApplicationQuit()
    {
        // stop client first
        // (we want to send the quit packet to the server instead of waiting
        //  for a timeout)
        if (NetworkClient.isConnected)
        {
            StopClient();
            //Debug.Log("OnApplicationQuit: stopped client");
        }

        // stop server after stopping client (for proper host mode stopping)
        if (NetworkServer.active)
        {
            StopServer();
            //Debug.Log("OnApplicationQuit: stopped server");
        }

        // Call ResetStatics to reset statics and singleton
        ResetStatics();
    }

    /// <summary>Set the frame rate for a headless builds. Override to disable or modify.</summary>
    // useful for dedicated servers.
    // useful for headless benchmark clients.
    public virtual void ConfigureHeadlessFrameRate()
    {

#if UNITY_SERVER
Application.targetFrameRate = serverTickRate;
// Debug.Log($"Server Tick Rate set to {Application.targetFrameRate} Hz.");
#endif
}

    bool InitializeSingleton()
    {
        if (singleton != null && singleton == this)
            return true;

        if (dontDestroyOnLoad)
        {
            if (singleton != null)
            {
                Debug.LogWarning("Multiple NetworkManagers detected in the scene. Only one NetworkManager can exist at a time. The duplicate NetworkManager will be destroyed.");
                Destroy(gameObject);

                // Return false to not allow collision-destroyed second instance to continue.
                return false;
            }
            //Debug.Log("NetworkManager created singleton (DontDestroyOnLoad)");
            singleton = this;
            if (Application.isPlaying)
            {
                // Force the object to scene root, in case user made it a child of something
                // in the scene since DDOL is only allowed for scene root objects
                transform.SetParent(null);
                DontDestroyOnLoad(gameObject);
            }
        }
        else
        {
            //Debug.Log("NetworkManager created singleton (ForScene)");
            singleton = this;
        }

        // set active transport AFTER setting singleton.
        // so only if we didn't destroy ourselves.
        Transport.activeTransport = transport;
        return true;
    }

    void RegisterServerMessages()
    {
        NetworkServer.OnConnectedEvent = OnServerConnectInternal;
        NetworkServer.OnDisconnectedEvent = OnServerDisconnect;
        NetworkServer.OnErrorEvent = OnServerError;
        NetworkServer.RegisterHandler<AddPlayerMessage>(OnServerAddPlayerInternal);

        // Network Server initially registers its own handler for this, so we replace it here.
        NetworkServer.ReplaceHandler<ReadyMessage>(OnServerReadyMessageInternal);
    }

    void RegisterClientMessages()
    {
        NetworkClient.OnConnectedEvent = OnClientConnectInternal;
        NetworkClient.OnDisconnectedEvent = OnClientDisconnectInternal;
        NetworkClient.OnErrorEvent = OnClientError;
        NetworkClient.RegisterHandler<NotReadyMessage>(OnClientNotReadyMessageInternal);
        NetworkClient.RegisterHandler<SceneMessage>(OnClientSceneInternal, false);

        if (playerPrefab != null)
            NetworkClient.RegisterPrefab(playerPrefab);

        foreach (GameObject prefab in spawnPrefabs.Where(t => t != null))
            NetworkClient.RegisterPrefab(prefab);
    }

    // This is the only way to clear the singleton, so another instance can be created.
    // RuntimeInitializeOnLoadMethod -> fast playmode without domain reload
    [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
    public static void ResetStatics()
    {
        // call StopHost if we have a singleton
        if (singleton)
            singleton.StopHost();

        // reset all statics
        startPositions.Clear();
        startPositionIndex = 0;
        clientReadyConnection = null;
        loadingSceneAsync = null;
        networkSceneName = string.Empty;

        // and finally (in case it isn't null already)...
        singleton = null;
    }

    // virtual so that inheriting classes' OnDestroy() can call base.OnDestroy() too
    public virtual void OnDestroy()
    {
        //Debug.Log("NetworkManager destroyed");
    }

    /// <summary>The name of the current network scene.</summary>
    // set by NetworkManager when changing the scene.
    // new clients will automatically load this scene.
    // Loading a scene manually won't set it.
    public static string networkSceneName { get; protected set; } = "";

    public static AsyncOperation loadingSceneAsync;

    /// <summary>Change the server scene and all client's scenes across the network.</summary>
    // Called automatically if onlineScene or offlineScene are set, but it
    // can be called from user code to switch scenes again while the game is
    // in progress. This automatically sets clients to be not-ready during
    // the change and ready again to participate in the new scene.
    public virtual void ServerChangeScene(string newSceneName)
    {
        if (string.IsNullOrWhiteSpace(newSceneName))
        {
            Debug.LogError("ServerChangeScene empty scene name");
            return;
        }

        if (NetworkServer.isLoadingScene && newSceneName == networkSceneName)
        {
            Debug.LogError($"Scene change is already in progress for {newSceneName}");
            return;
        }

        // Debug.Log($"ServerChangeScene {newSceneName}");
        NetworkServer.SetAllClientsNotReady();
        networkSceneName = newSceneName;

        // Let server prepare for scene change
        OnServerChangeScene(newSceneName);

        // set server flag to stop processing messages while changing scenes
        // it will be re-enabled in FinishLoadScene.
        NetworkServer.isLoadingScene = true;

        loadingSceneAsync = SceneManager.LoadSceneAsync(newSceneName);

        // ServerChangeScene can be called when stopping the server
        // when this happens the server is not active so does not need to tell clients about the change
        if (NetworkServer.active)
        {
            // notify all clients about the new scene
            NetworkServer.SendToAll(new SceneMessage { sceneName = newSceneName });
        }

        startPositionIndex = 0;
        startPositions.Clear();
    }

    // This is only set in ClientChangeScene below...never on server.
    // We need to check this in OnClientSceneChanged called from FinishLoadSceneClientOnly
    // to prevent AddPlayer message after loading/unloading additive scenes
    SceneOperation clientSceneOperation = SceneOperation.Normal;

    internal void ClientChangeScene(string newSceneName, SceneOperation sceneOperation = SceneOperation.Normal, bool customHandling = false)
    {
        if (string.IsNullOrWhiteSpace(newSceneName))
        {
            Debug.LogError("ClientChangeScene empty scene name");
            return;
        }

        //Debug.Log($"ClientChangeScene newSceneName: {newSceneName} networkSceneName{networkSceneName}");

        // Let client prepare for scene change
        OnClientChangeScene(newSceneName, sceneOperation, customHandling);

        // After calling OnClientChangeScene, exit if server since server is already doing
        // the actual scene change, and we don't need to do it for the host client
        if (NetworkServer.active)
            return;

        // set client flag to stop processing messages while loading scenes.
        // otherwise we would process messages and then lose all the state
        // as soon as the load is finishing, causing all kinds of bugs
        // because of missing state.
        // (client may be null after StopClient etc.)
        // Debug.Log("ClientChangeScene: pausing handlers while scene is loading to avoid data loss after scene was loaded.");
        NetworkClient.isLoadingScene = true;

        // Cache sceneOperation so we know what was requested by the
        // Scene message in OnClientChangeScene and OnClientSceneChanged
        clientSceneOperation = sceneOperation;

        // scene handling will happen in overrides of OnClientChangeScene and/or OnClientSceneChanged
        // Do not call FinishLoadScene here. Custom handler will assign loadingSceneAsync and we need
        // to wait for that to finish. UpdateScene already checks for that to be not null and isDone.
        if (customHandling)
            return;

        switch (sceneOperation)
        {
            case SceneOperation.Normal:
                loadingSceneAsync = SceneManager.LoadSceneAsync(newSceneName);
                break;
            case SceneOperation.LoadAdditive:
                // Ensure additive scene is not already loaded on client by name or path
                // since we don't know which was passed in the Scene message
                if (!SceneManager.GetSceneByName(newSceneName).IsValid() && !SceneManager.GetSceneByPath(newSceneName).IsValid())
                    loadingSceneAsync = SceneManager.LoadSceneAsync(newSceneName, LoadSceneMode.Additive);
                else
                {
                    Debug.LogWarning($"Scene {newSceneName} is already loaded");

                    // Reset the flag that we disabled before entering this switch
                    NetworkClient.isLoadingScene = false;
                }
                break;
            case SceneOperation.UnloadAdditive:
                // Ensure additive scene is actually loaded on client by name or path
                // since we don't know which was passed in the Scene message
                if (SceneManager.GetSceneByName(newSceneName).IsValid() || SceneManager.GetSceneByPath(newSceneName).IsValid())
                    loadingSceneAsync = SceneManager.UnloadSceneAsync(newSceneName, UnloadSceneOptions.UnloadAllEmbeddedSceneObjects);
                else
                {
                    Debug.LogWarning($"Cannot unload {newSceneName} with UnloadAdditive operation");

                    // Reset the flag that we disabled before entering this switch
                    NetworkClient.isLoadingScene = false;
                }
                break;
        }

        // don't change the client's current networkSceneName when loading additive scene content
        if (sceneOperation == SceneOperation.Normal)
            networkSceneName = newSceneName;
    }

    // support additive scene loads:
    //   NetworkScenePostProcess disables all scene objects on load, and
    //   * NetworkServer.SpawnObjects enables them again on the server when
    //     calling OnStartServer
    //   * NetworkClient.PrepareToSpawnSceneObjects enables them again on the
    //     client after the server sends ObjectSpawnStartedMessage to client
    //     in SpawnObserversForConnection. this is only called when the
    //     client joins, so we need to rebuild scene objects manually again
    // TODO merge this with FinishLoadScene()?
    void OnSceneLoaded(Scene scene, LoadSceneMode mode)
    {
        if (mode == LoadSceneMode.Additive)
        {
            if (NetworkServer.active)
            {
                // TODO only respawn the server objects from that scene later!
                NetworkServer.SpawnObjects();
                // Debug.Log($"Respawned Server objects after additive scene load: {scene.name}");
            }
            if (NetworkClient.active)
            {
                NetworkClient.PrepareToSpawnSceneObjects();
                // Debug.Log($"Rebuild Client spawnableObjects after additive scene load: {scene.name}");
            }
        }
    }

    void UpdateScene()
    {
        if (loadingSceneAsync != null && loadingSceneAsync.isDone)
        {
            //Debug.Log($"ClientChangeScene done readyConn {clientReadyConnection}");

            // try-finally to guarantee loadingSceneAsync being cleared.
            // fixes https://github.com/vis2k/Mirror/issues/2517 where if
            // FinishLoadScene throws an exception, loadingSceneAsync would
            // never be cleared and this code would run every Update.
            try
            {
                FinishLoadScene();
            }
            finally
            {
                loadingSceneAsync.allowSceneActivation = true;
                loadingSceneAsync = null;
            }
        }
    }

    protected void FinishLoadScene()
    {
        // NOTE: this cannot use NetworkClient.allClients[0] - that client may be for a completely different purpose.

        // process queued messages that we received while loading the scene
        //Debug.Log("FinishLoadScene: resuming handlers after scene was loading.");
        NetworkServer.isLoadingScene = false;
        NetworkClient.isLoadingScene = false;

        // host mode?
        if (mode == NetworkManagerMode.Host)
        {
            FinishLoadSceneHost();
        }
        // server-only mode?
        else if (mode == NetworkManagerMode.ServerOnly)
        {
            FinishLoadSceneServerOnly();
        }
        // client-only mode?
        else if (mode == NetworkManagerMode.ClientOnly)
        {
            FinishLoadSceneClientOnly();
        }
        // otherwise we called it after stopping when loading offline scene.
        // do nothing then.
    }

    // finish load scene part for host mode. makes code easier and is
    // necessary for FinishStartHost later.
    // (the 3 things have to happen in that exact order)
    void FinishLoadSceneHost()
    {
        // debug message is very important. if we ever break anything then
        // it's very obvious to notice.
        //Debug.Log("Finished loading scene in host mode.");

        if (clientReadyConnection != null)
        {

#pragma warning disable 618
// obsolete method calls new method because it's not empty
OnClientConnect(clientReadyConnection);
#pragma warning restore 618
clientLoadedScene = true;
clientReadyConnection = null;
}

        // do we need to finish a StartHost() call?
        // then call FinishStartHost and let it take care of spawning etc.
        if (finishStartHostPending)
        {
            finishStartHostPending = false;
            FinishStartHost();

            // call OnServerSceneChanged
            OnServerSceneChanged(networkSceneName);

            // DO NOT call OnClientSceneChanged here.
            // the scene change happened because StartHost loaded the
            // server's online scene. it has nothing to do with the client.
            // this was not meant as a client scene load, so don't call it.
            //
            // otherwise AddPlayer would be called twice:
            // -> once for client OnConnected
            // -> once in OnClientSceneChanged
        }
        // otherwise we just changed a scene in host mode
        else
        {
            // spawn server objects
            NetworkServer.SpawnObjects();

            // call OnServerSceneChanged
            OnServerSceneChanged(networkSceneName);

            if (NetworkClient.isConnected)
            {
                // let client know that we changed scene

#pragma warning disable 618
// obsolete method calls new method because it's not empty
OnClientSceneChanged(NetworkClient.connection);
#pragma warning restore 618
}
}
}

    // finish load scene part for server-only. . makes code easier and is
    // necessary for FinishStartServer later.
    void FinishLoadSceneServerOnly()
    {
        // debug message is very important. if we ever break anything then
        // it's very obvious to notice.
        //Debug.Log("Finished loading scene in server-only mode.");

        NetworkServer.SpawnObjects();
        OnServerSceneChanged(networkSceneName);
    }

    // finish load scene part for client-only. makes code easier and is
    // necessary for FinishStartClient later.
    void FinishLoadSceneClientOnly()
    {
        // debug message is very important. if we ever break anything then
        // it's very obvious to notice.
        //Debug.Log("Finished loading scene in client-only mode.");

        if (clientReadyConnection != null)
        {

#pragma warning disable 618
// obsolete method calls new method because it's not empty
OnClientConnect(clientReadyConnection);
#pragma warning restore 618
clientLoadedScene = true;
clientReadyConnection = null;
}

        if (NetworkClient.isConnected)
        {

#pragma warning disable 618
// obsolete method calls new method because it's not empty
OnClientSceneChanged(NetworkClient.connection);
#pragma warning restore 618
}
}

    /// <summary>
    /// Registers the transform of a game object as a player spawn location.
    /// <para>This is done automatically by NetworkStartPosition components, but can be done manually from user script code.</para>
    /// </summary>
    /// <param name="start">Transform to register.</param>
    // Static because it's called from NetworkStartPosition::Awake
    // and singleton may not exist yet
    public static void RegisterStartPosition(Transform start)
    {
        // Debug.Log($"RegisterStartPosition: {start.gameObject.name} {start.position}");
        startPositions.Add(start);

        // reorder the list so that round-robin spawning uses the start positions
        // in hierarchy order.  This assumes all objects with NetworkStartPosition
        // component are siblings, either in the scene root or together as children
        // under a single parent in the scene.
        startPositions = startPositions.OrderBy(transform => transform.GetSiblingIndex()).ToList();
    }

    /// <summary>Unregister a Transform from start positions.</summary>
    // Static because it's called from NetworkStartPosition::OnDestroy
    // and singleton may not exist yet
    public static void UnRegisterStartPosition(Transform start)
    {
        //Debug.Log($"UnRegisterStartPosition: {start.name} {start.position}");
        startPositions.Remove(start);
    }

    /// <summary>Get the next NetworkStartPosition based on the selected PlayerSpawnMethod.</summary>
    public Transform GetStartPosition()
    {
        // first remove any dead transforms
        startPositions.RemoveAll(t => t == null);

        if (startPositions.Count == 0)
            return null;

        if (playerSpawnMethod == PlayerSpawnMethod.Random)
        {
            return startPositions[UnityEngine.Random.Range(0, startPositions.Count)];
        }
        else
        {
            Transform startPosition = startPositions[startPositionIndex];
            startPositionIndex = (startPositionIndex + 1) % startPositions.Count;
            return startPosition;
        }
    }

    void OnServerConnectInternal(NetworkConnectionToClient conn)
    {
        //Debug.Log("NetworkManager.OnServerConnectInternal");

        if (authenticator != null)
        {
            // we have an authenticator - let it handle authentication
            authenticator.OnServerAuthenticate(conn);
        }
        else
        {
            // authenticate immediately
            OnServerAuthenticated(conn);
        }
    }

    // called after successful authentication
    // TODO do the NetworkServer.OnAuthenticated thing from x branch
    void OnServerAuthenticated(NetworkConnectionToClient conn)
    {
        //Debug.Log("NetworkManager.OnServerAuthenticated");

        // set connection to authenticated
        conn.isAuthenticated = true;

        // proceed with the login handshake by calling OnServerConnect
        if (networkSceneName != "" && networkSceneName != offlineScene)
        {
            SceneMessage msg = new SceneMessage() { sceneName = networkSceneName };
            conn.Send(msg);
        }

        OnServerConnect(conn);
    }

    void OnServerReadyMessageInternal(NetworkConnectionToClient conn, ReadyMessage msg)
    {
        //Debug.Log("NetworkManager.OnServerReadyMessageInternal");
        OnServerReady(conn);
    }

    void OnServerAddPlayerInternal(NetworkConnectionToClient conn, AddPlayerMessage msg)
    {
        //Debug.Log("NetworkManager.OnServerAddPlayer");

        if (autoCreatePlayer && playerPrefab == null)
        {
            Debug.LogError("The PlayerPrefab is empty on the NetworkManager. Please setup a PlayerPrefab object.");
            return;
        }

        if (autoCreatePlayer && playerPrefab.GetComponent<NetworkIdentity>() == null)
        {
            Debug.LogError("The PlayerPrefab does not have a NetworkIdentity. Please add a NetworkIdentity to the player prefab.");
            return;
        }

        if (conn.identity != null)
        {
            Debug.LogError("There is already a player for this connection.");
            return;
        }

        OnServerAddPlayer(conn);
    }

    void OnClientConnectInternal()
    {
        //Debug.Log("NetworkManager.OnClientConnectInternal");

        if (authenticator != null)
        {
            // we have an authenticator - let it handle authentication
            authenticator.OnClientAuthenticate();
        }
        else
        {
            // authenticate immediately
            OnClientAuthenticated();
        }
    }

    // called after successful authentication
    void OnClientAuthenticated()
    {
        //Debug.Log("NetworkManager.OnClientAuthenticated");

        // set connection to authenticated
        NetworkClient.connection.isAuthenticated = true;

        // proceed with the login handshake by calling OnClientConnect
        if (string.IsNullOrWhiteSpace(onlineScene) || onlineScene == offlineScene || IsSceneActive(onlineScene))
        {
            clientLoadedScene = false;

#pragma warning disable 618
// obsolete method calls new method because it's not empty
OnClientConnect(NetworkClient.connection);
#pragma warning restore 618
}
else
{
// will wait for scene id to come from the server.
clientLoadedScene = true;
clientReadyConnection = NetworkClient.connection;
}
}

    void OnClientDisconnectInternal()
    {
        //Debug.Log("NetworkManager.OnClientDisconnectInternal");

#pragma warning disable 618
// obsolete method calls new method because it's not empty
OnClientDisconnect(NetworkClient.connection);
#pragma warning restore 618
}

    void OnClientNotReadyMessageInternal(NotReadyMessage msg)
    {
        //Debug.Log("NetworkManager.OnClientNotReadyMessageInternal");
        NetworkClient.ready = false;

#pragma warning disable 618
OnClientNotReady(NetworkClient.connection);
#pragma warning restore 618
OnClientNotReady();

        // NOTE: clientReadyConnection is not set here! don't want OnClientConnect to be invoked again after scene changes.
    }

    void OnClientSceneInternal(SceneMessage msg)
    {
        //Debug.Log("NetworkManager.OnClientSceneInternal");

        // This needs to run for host client too. NetworkServer.active is checked there
        if (NetworkClient.isConnected)
        {
            ClientChangeScene(msg.sceneName, msg.sceneOperation, msg.customHandling);
        }
    }

    /// <summary>Called on the server when a new client connects.</summary>
    public virtual void OnServerConnect(NetworkConnectionToClient conn) {}

    /// <summary>Called on the server when a client disconnects.</summary>
    // Called by NetworkServer.OnTransportDisconnect!
    public virtual void OnServerDisconnect(NetworkConnectionToClient conn)
    {
        // by default, this function destroys the connection's player.
        // can be overwritten for cases like delayed logouts in MMOs to
        // avoid players escaping from PvP situations by logging out.
        NetworkServer.DestroyPlayerForConnection(conn);
        //Debug.Log("OnServerDisconnect: Client disconnected.");
    }

    /// <summary>Called on the server when a client is ready (= loaded the scene)</summary>
    public virtual void OnServerReady(NetworkConnectionToClient conn)
    {
        if (conn.identity == null)
        {
            // this is now allowed (was not for a while)
            //Debug.Log("Ready with no player object");
        }
        NetworkServer.SetClientReady(conn);
    }

    /// <summary>Called on server when a client requests to add the player. Adds playerPrefab by default. Can be overwritten.</summary>
    // The default implementation for this function creates a new player object from the playerPrefab.
    public virtual void OnServerAddPlayer(NetworkConnectionToClient conn)
    {
        Transform startPos = GetStartPosition();
        GameObject player = startPos != null
            ? Instantiate(playerPrefab, startPos.position, startPos.rotation)
            : Instantiate(playerPrefab);

        // instantiating a "Player" prefab gives it the name "Player(clone)"
        // => appending the connectionId is WAY more useful for debugging!
        player.name = $"{playerPrefab.name} [connId={conn.connectionId}]";
        NetworkServer.AddPlayerForConnection(conn, player);
    }

    /// <summary>Called on server when transport raises an exception. NetworkConnection may be null.</summary>
    public virtual void OnServerError(NetworkConnectionToClient conn, Exception exception) {}

    /// <summary>Called from ServerChangeScene immediately before SceneManager.LoadSceneAsync is executed</summary>
    public virtual void OnServerChangeScene(string newSceneName) {}

    /// <summary>Called on server after a scene load with ServerChangeScene() is completed.</summary>
    public virtual void OnServerSceneChanged(string sceneName) {}

    /// <summary>Called on the client when connected to a server. By default it sets client as ready and adds a player.</summary>
    public virtual void OnClientConnect()
    {
        // OnClientConnect by default calls AddPlayer but it should not do
        // that when we have online/offline scenes. so we need the
        // clientLoadedScene flag to prevent it.
        if (!clientLoadedScene)
        {
            // Ready/AddPlayer is usually triggered by a scene load completing.
            // if no scene was loaded, then Ready/AddPlayer it here instead.
            if (!NetworkClient.ready)
                NetworkClient.Ready();

            if (autoCreatePlayer)
                NetworkClient.AddPlayer();
        }
    }

    // Deprecated 2021-12-11
    [Obsolete("Remove the NetworkConnection parameter in your override and use NetworkClient.connection instead.")]
    public virtual void OnClientConnect(NetworkConnection conn) => OnClientConnect();

    /// <summary>Called on clients when disconnected from a server.</summary>
    public virtual void OnClientDisconnect()
    {
        if (mode == NetworkManagerMode.Offline)
            return;

        StopClient();
    }

    // Deprecated 2021-12-11
    [Obsolete("Remove the NetworkConnection parameter in your override and use NetworkClient.connection instead.")]
    public virtual void OnClientDisconnect(NetworkConnection conn) => OnClientDisconnect();

    /// <summary>Called on client when transport raises an exception.</summary>
    public virtual void OnClientError(Exception exception) {}

    /// <summary>Called on clients when a servers tells the client it is no longer ready, e.g. when switching scenes.</summary>
    public virtual void OnClientNotReady() {}

    // Deprecated 2021-12-11
    [Obsolete("Remove the NetworkConnection parameter in your override and use NetworkClient.connection instead.")]
    public virtual void OnClientNotReady(NetworkConnection conn) {}

    /// <summary>Called from ClientChangeScene immediately before SceneManager.LoadSceneAsync is executed</summary>
    // customHandling: indicates if scene loading will be handled through overrides
    public virtual void OnClientChangeScene(string newSceneName, SceneOperation sceneOperation, bool customHandling) {}

    /// <summary>Called on clients when a scene has completed loaded, when the scene load was initiated by the server.</summary>
    // Scene changes can cause player objects to be destroyed. The default
    // implementation of OnClientSceneChanged in the NetworkManager is to
    // add a player object for the connection if no player object exists.
    public virtual void OnClientSceneChanged()
    {
        // always become ready.
        if (!NetworkClient.ready) NetworkClient.Ready();

        // Only call AddPlayer for normal scene changes, not additive load/unload
        if (clientSceneOperation == SceneOperation.Normal && autoCreatePlayer && NetworkClient.localPlayer == null)
        {
            // add player if existing one is null
            NetworkClient.AddPlayer();
        }
    }

    // Deprecated 2021-12-11
    [Obsolete("Remove the NetworkConnection parameter in your override and use NetworkClient.connection instead.")]
    public virtual void OnClientSceneChanged(NetworkConnection conn) => OnClientSceneChanged();

    // Since there are multiple versions of StartServer, StartClient and
    // StartHost, to reliably customize their functionality, users would
    // need override all the versions. Instead these callbacks are invoked
    // from all versions, so users only need to implement this one case.

    /// <summary>This is invoked when a host is started.</summary>
    public virtual void OnStartHost() {}

    /// <summary>This is invoked when a server is started - including when a host is started.</summary>
    public virtual void OnStartServer() {}

    /// <summary>This is invoked when the client is started.</summary>
    public virtual void OnStartClient() {}

    /// <summary>This is called when a server is stopped - including when a host is stopped.</summary>
    public virtual void OnStopServer() {}

    /// <summary>This is called when a client is stopped.</summary>
    public virtual void OnStopClient() {}

    /// <summary>This is called when a host is stopped.</summary>
    public virtual void OnStopHost() {}
}

}
`

Can somebody please help me?

There was an error while joining a lobby. Error: LobbyLobbyAlreadyExists

Joining a lobby using the EOSLobby script gives the error mentioned in the title:
"There was an error while joining a lobby. Error: LobbyLobbyAlreadyExists"

Creating a lobby works and I can even get the info from the created lobby it's just that you can't join any lobbies. Even after creating the lobby it doesn't make the host join.

Object reference not set an instance of an object

I followed the instructions, then I started my game, and there are some Errors:
Epic Manager: Category - LogEOSConnect Message - DeviceId access credentials already exist for the current user profile on the local device. UnityEngine.Debug:LogError (object) EpicTransport.Logger:EpicDebugLog (Epic.OnlineServices.Logging.LogMessage) (at Assets/Mirror/Runtime/Transport/EpicOnlineTransport/Logger.cs:16) EpicTransport.EOSSDKComponent/<>c:<InitializeImplementation>b__71_0 (Epic.OnlineServices.Logging.LogMessage) (at Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDKComponent.cs:208) Epic.OnlineServices.Logging.LoggingInterface:LogMessageFuncInternalImplementation (intptr) (at Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/Generated/Logging/LoggingInterface.cs:52) Epic.OnlineServices.Connect.ConnectInterface:CreateDeviceId (Epic.OnlineServices.Connect.CreateDeviceIdOptions,object,Epic.OnlineServices.Connect.OnCreateDeviceIdCallback) (at Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/Generated/Connect/ConnectInterface.cs:381) EpicTransport.EOSSDKComponent:InitializeImplementation () (at Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDKComponent.cs:265) EpicTransport.EOSSDKComponent:Initialize () (at Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDKComponent.cs:277) EpicTransport.EOSSDKComponent:Awake () (at Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDKComponent.cs:185)

and

EpicTransport.Logger:EpicDebugLog (Epic.OnlineServices.Logging.LogMessage) (at Assets/Mirror/Runtime/Transport/EpicOnlineTransport/Logger.cs:16) EpicTransport.EOSSDKComponent/<>c:<InitializeImplementation>b__71_0 (Epic.OnlineServices.Logging.LogMessage) (at Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDKComponent.cs:208) Epic.OnlineServices.Logging.LoggingInterface:LogMessageFuncInternalImplementation (intptr) (at Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/Generated/Logging/LoggingInterface.cs:52) Epic.OnlineServices.Platform.PlatformInterface:Tick () (at Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/Generated/Platform/PlatformInterface.cs:738) EpicTransport.EOSSDKComponent:Tick () (at Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDKComponent.cs:147) EpicTransport.EosTransport:ServerEarlyUpdate () (at Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EosTransport.cs:106) Mirror.NetworkServer:NetworkEarlyUpdate () (at Assets/Mirror/Runtime/NetworkServer.cs:1698) Mirror.NetworkLoop:NetworkEarlyUpdate () (at Assets/Mirror/Runtime/NetworkLoop.cs:193)

After I created a lobby the console spams this:
NullReferenceException: Object reference not set to an instance of an object EpicTransport.EOSSDKComponent.InitializeImplementation () (at Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDKComponent.cs:192) EpicTransport.EOSSDKComponent.Initialize () (at Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDKComponent.cs:277) EpicTransport.EOSSDKComponent.Awake () (at Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDKComponent.cs:185) UnityEngine.GameObject:AddComponent() EpicTransport.EOSSDKComponent:get_Instance() (at Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDKComponent.cs:138) EpicTransport.EOSSDKComponent:GetP2PInterface() (at Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDKComponent.cs:83) EpicTransport.Common:Receive(ProductUserId&, SocketId&, Byte[]&, Byte) (at Assets/Mirror/Runtime/Transport/EpicOnlineTransport/Common.cs:144) EpicTransport.Common:ReceiveData() (at Assets/Mirror/Runtime/Transport/EpicOnlineTransport/Common.cs:188) EpicTransport.EosTransport:ServerEarlyUpdate() (at Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EosTransport.cs:124) Mirror.NetworkServer:NetworkEarlyUpdate() (at Assets/Mirror/Runtime/NetworkServer.cs:1698) Mirror.NetworkLoop:NetworkEarlyUpdate() (at Assets/Mirror/Runtime/NetworkLoop.cs:193)

Can somebody help me?

Try use EOS_DevAuthTool but OnAuthInterfaceLogin no response

Hi,

I try use EOS_DevAuthTool but OnAuthInterfaceLogin no response.

1.Open EOS_DevAuthTool.exe and add a CredentialI.
2.Send Login use LoginCredentialType.Developer and CredentialId
EOS.GetAuthInterface().Login(loginOptions, null, OnAuthInterfaceLogin);
3.Browser open and comple then close
4.I see EOS_DevAuthTool.exe the CredentialI Last use time update.
5.Seems Editor not receive response, so OnAuthInterfaceLogin no response.

=============================================
After about 10 minutes
OnLoginCallbackInternalImplementation()
callback a Login returned AuthPinGrantExpired

Transform

Hello, before EOS Transform i was using in my Network Manager the kcp transform from Mirror, i followed the readme so i replace it with the eos transform. When i want to sincronize objects i just put a "Network Transform" or a "Rigidbody transform".
I can create lobbies and join them, players sees each other, but movement for non-host players are weird, before it wasn't.
Should i remove my Network transform or Rigidbody transform or something? Maybe replace it with Eos transform?

Thanks for the help!

Error multiple plugins

I opened a brand new project and got this error :

Multiple plugins with the same name 'eossdk' (found at 'Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/Android/libs/arm64-v8a/libEOSSDK.so' and 'Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/Android/libs/armeabi-v7a/libEOSSDK.so'). That means one or more plugins are set to be compatible with Editor. Only one plugin at the time can be used by Editor.

Do I ignore it or leave it as is ?

Login plainly fails if Persistent Auth token has expired or does not exist

In the current implementation of Auth interface, if Persistent Auth does not find a valid token to authenticate the user, the account login straight up fails. The developer is required to change the Auth type manually and authenticate once, and then switch back to the Persistent Auth type for the subsequent runs of the game.
This could be handled by the Persistent Auth login functionality by providing an alternate default login method (Account Portal, for example) for that specific login, so that the subsequent Persistent Authentication calls can go through.
This will make the Persistent Auth functionality more robust.

Freezing when leaving runtime.

When I leave runtime unity hangs at 0 % CPU, I think it is waiting for eos services to close but it never does. I have to restart unity every time. It only happends when I have the EOSSDKComponent enabled with valid IDs.

Required Formal Parameter Error

In the newest version of Mirror, I am getting this error. I'm wondering if there is a fix for this or if the repo is going to get an update to fix it?

Assets\Mirror\Runtime\Transport\EpicOnlineTransport\Server.cs(25,77): error CS7036: There is no argument given that corresponds to the required formal parameter 'arg3' of 'Action<int, TransportError, string>.Invoke(int, TransportError, string)'

EpicOnlineTransport v1.5.0 not working with newest Mirror version

Created a blank unity project, added the newest Mirror version (67.1.0) and added the newest EOT version (1.5.0), but getting these errors:

Assets\Mirror\Runtime\Transport\EpicOnlineTransport\EosTransport.cs(156,30): error CS0115: 'EosTransport.ClientSend(int, ArraySegment<byte>)': no suitable method found to override

Assets\Mirror\Runtime\Transport\EpicOnlineTransport\EosTransport.cs(216,30): error CS0115: 'EosTransport.ServerSend(int, int, ArraySegment<byte>)': no suitable method found to override

Assets\Mirror\Runtime\Transport\EpicOnlineTransport\EosTransport.cs(286,29): error CS0115: 'EosTransport.GetMaxBatchSize(int)': no suitable method found to override

Assets\Mirror\Runtime\Transport\EpicOnlineTransport\EosTransport.cs(16,18): error CS0534: 'EosTransport' does not implement inherited abstract member 'Transport.ClientSend(ArraySegment<byte>, int)'

Assets\Mirror\Runtime\Transport\EpicOnlineTransport\EosTransport.cs(16,18): error CS0534: 'EosTransport' does not implement inherited abstract member 'Transport.ServerSend(int, ArraySegment<byte>, int)'

Can I work around these somehow?

Undefined symbol Error while building for iOS

Hi, now I'm developing a Unity game with EpicOnlineTransport. I built the project with X-code in Unity for iOS build, and there were no errors so far. However, an error occurred in the process of building from X-code to a real phone. The error code is as follows. Do you have any idea how to solve this?

Undefined symbol: _EOS_UnerInfo_CopyUserInfo

In addition to this error message, Undefined symbol: EOS ~~ About 100 errors appeared. I need help please.

Failed to subclass window. Disabling overlay rendering

Getting this error(multiple times) when starting empty scene in empty project
Epic Manager: Category - LogEOSOverlay Message - Failed to subclass window. Disabling overlay rendering
this causes not working neither unity editor ui nor lobby gui

Object reference not set to instance of an object

I know that someone else has already mentioned this error, but making the EOS SDK a DDOL object didn't fix my problem. I keep on getting this error:
NullReferenceException: Object reference not set to an instance of an object EpicTransport.EOSSDKComponent.Tick () (at Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDKComponent.cs:147) EpicTransport.EosTransport.ServerEarlyUpdate () (at Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EosTransport.cs:90) Mirror.NetworkServer.NetworkEarlyUpdate () (at Assets/Mirror/Core/NetworkServer.cs:1918) Mirror.NetworkLoop.NetworkEarlyUpdate () (at Assets/Mirror/Core/NetworkLoop.cs:192)

No suitable method found to override

Unity: 2020.3.24.f1

I get 5 errors these are the errors

Assets\Mirror\Runtime\Transport\EpicOnlineTransport\EosTransport.cs(156,30): error CS0115: 'EosTransport.ClientSend(int, ArraySegment<byte>)': no suitable method found to override
Assets\Mirror\Runtime\Transport\EpicOnlineTransport\EosTransport.cs(216,30): error CS0115: 'EosTransport.ServerSend(int, int, ArraySegment<byte>)': no suitable method found to override
Assets\Mirror\Runtime\Transport\EpicOnlineTransport\EosTransport.cs(286,29): error CS0115: 'EosTransport.GetMaxBatchSize(int)': no suitable method found to override
Assets\Mirror\Runtime\Transport\EpicOnlineTransport\EosTransport.cs(16,18): error CS0534: 'EosTransport' does not implement inherited abstract member 'Transport.ServerSend(int, ArraySegment<byte>, int)'
Assets\Mirror\Runtime\Transport\EpicOnlineTransport\EosTransport.cs(16,18): error CS0534: 'EosTransport' does not implement inherited abstract member 'Transport.ClientSend(ArraySegment<byte>, int)'

NetworkManager offline/online scene leads to impossible connection

Hello, using the EOSLobbyUI and tried to join/leave the same lobby multiple times as a client, but it doesn't seems to work in these conditions:
- NetworkManager offline scene set to none and online scene set
- NetworkManager online scene set to none and offline scene set
- NetworkManager offline and online scene set

I can add that it's (sometimes) possible to connect once (in the last case) but never more (timed out, even when set at 55sec).

I'm working on a windows 64bits with Mirror 66.0.9

EOS not initialized (Linux)

After configure everything, I'm getting this message:

EOS not initialized. Server could not be started
Epic Manager: Category - LogEOS Message - Updating Platform SDK Config, Time: 1.6
Epic Manager: Category - LogEOS Message - SDK Config Platform Update Request Successful, Time: 1.9
Epic Manager: Category - LogEOSAnalytics Message - Start Session (User: ...)
Epic Manager: Unknown log processing. Category - LogEOSAnalytics Message - Record Event: EOSSDK.HTTP.Complete <Redacted>
Epic Manager: Category - LogEOS Message - Updating Product SDK Config, Time: 1.9
Epic Manager: Unknown log processing. Category - LogEOSAnalytics Message - Record Event: EOSSDK.HTTP.Complete <Redacted>
Epic Manager: Unknown log processing. Category - LogEOSConnect Message - ConnectClientAuthTask Success
Epic Manager: Unknown log processing. Category - LogEOSAnalytics Message - Record Event: EOSSDK.HTTP.Complete <Redacted>
Epic Manager: Category - LogEOS Message - SDK Config Product Update Request Successful, Time: 2.1
Epic Manager: Category - LogEOS Message - SDK Config Data - Watermark: 8322246731
Epic Manager: Category - LogEOS Message - ScheduleNextSDKConfigDataUpdate - Time: 2.133228, Update Interval: 358.460602
Epic Manager: Unknown log processing. Category - LogEOSAnalytics Message - Record Event: EOSSDK.HTTP.Complete <Redacted>
Epic Manager: Category - LogEOSMessaging Message - Attempting connection to Stomp. LocalUserId=[000...19a] Url=[<Redacted>]
Connect Interface Login succeeded
EOS User Product ID: xxxxxxxxxxx
Epic Manager: Unknown log processing. Category - LogEOSP2P Message - Using Port Range 7777-7876 for P2P traffic
Epic Manager: Unknown log processing. Category - LogEOSAnalytics Message - Record Event: EOSSDK.HTTP.Complete <Redacted>
Epic Manager: Unknown log processing. Category - LogEOSP2P Message - Applying updated RTC Configuration
Epic Manager: Category - LogEOSMessaging Message - Succesfully connected to Stomp. LocalUserId=[000...19a]
Epic Manager: Unknown log processing. Category - LogEOSMessaging Message - Stomp subscribed to topic /xxxxxxxxxxxx/account/xxxxxxxxxx

I have double checked that every product configuration has been correctly applied. And everything was working perfectly with Mirror (kcp transport) before start doing these changes.

Any idea what could be wrong?

Thanks!

error CS7036: There is no argument given that corresponds to the required formal parameter

Error in Unity:
error2
In Server.cs. I have the definition for the OnServerError action also pulled up.
error

Few things I've taken note here.

One, The second argument does not take an Exception object. Instead, it asks for a TransportError enum. Also, OnServerError also requires a third argument, which is not provided. The third argument is a string, so I assume that's meant for an error message?

Build Errors when Compiling for Android

Unity Version: 2020.3.15f2 (LTS)
Mirror Version: v44.0.2 (latest)
EpicOnlineTransport Version: v1.5.0 (latest)
JDK Version: OpenJDK 1.8.0_152 (installed with Unity)
Gradle Version: 4.0.1 (?) (installed with Unity)
Android SDK/NDK/Build Tools Version: Unknown (installed with Unity)
OS Version: Windows 10 Home 21H1, Build 19043.1110, Windows Feature Experience Pack 120.2212.3530

I cannot get a blank Android project to build. Building for Windows works without issue.

Steps to Reproduce:

  1. Create a blank 2D Unity project
  2. Import entire EpicOnlineTransport.unitypackage
  3. Import entire Mirror package from Package Manager
  4. Switch platform to Android in Build Settings
  5. Attempt Build
  6. Notice the following errors:
Found plugins with same names and architectures, Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/Android/libs/armeabi-v7a/libEOSSDK.so () and Assets/Mirror/Runtime/Transport/EpicOnlineTransport/EOSSDK/Android/libs/arm64-v8a/libEOSSDK.so (). Assign different architectures or delete the duplicate.
UnityEditor.AndroidPluginImporterExtension:CheckFileCollisions (string)
UnityEditorInternal.PluginsHelper:CheckFileCollisions (UnityEditor.BuildTarget)
UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)
Plugins colliding with each other.
Build completed with a result of 'Failed' in 10 seconds (10174 ms)
UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)
UnityEditor.BuildPlayerWindow+BuildMethodException: 2 errors
  at UnityEditor.BuildPlayerWindow+DefaultBuildMethods.BuildPlayer (UnityEditor.BuildPlayerOptions options) [0x002ca] in <44c3723143904fb88deebc993c7bb491>:0 
  at UnityEditor.BuildPlayerWindow.CallBuildMethods (System.Boolean askForBuildLocation, UnityEditor.BuildOptions defaultBuildOptions) [0x00080] in <44c3723143904fb88deebc993c7bb491>:0 
UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)
  1. Fix build errors by changing CPU in the Import Settings of Assets\Mirror\Runtime\Transport\EpicOnlineTransport\EOSSDK\Android\libs\arm64-v8a\libEOSSDK.so to ARM64
  2. Observe that the build fails again with different errors:
Starting a Gradle Daemon, 1 incompatible and 2 stopped Daemons could not be reused, use --status for details

> Configure project :launcher
WARNING: The option setting 'android.enableR8=false' is deprecated.
It will be removed in version 5.0 of the Android Gradle plugin.
You will no longer be able to disable R8
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\build-tools\30.0.2\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platform-tools\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platforms\android-29\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\tools\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\build-tools\30.0.2\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platform-tools\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platforms\android-29\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\tools\package.xml. Probably the SDK is read-only

> Task :unityLibrary:preBuild UP-TO-DATE
> Task :launcher:preBuild UP-TO-DATE
> Task :launcher:preReleaseBuild UP-TO-DATE
> Task :unityLibrary:preReleaseBuild UP-TO-DATE
> Task :unityLibrary:compileReleaseAidl NO-SOURCE
> Task :unityLibrary:packageReleaseRenderscript NO-SOURCE
> Task :unityLibrary:compileReleaseRenderscript NO-SOURCE
> Task :unityLibrary:generateReleaseResValues
> Task :unityLibrary:generateReleaseResources
> Task :launcher:generateReleaseBuildConfig
> Task :launcher:compileReleaseAidl NO-SOURCE
> Task :launcher:compileReleaseRenderscript NO-SOURCE
> Task :launcher:generateReleaseResValues
> Task :launcher:generateReleaseResources
> Task :launcher:createReleaseCompatibleScreenManifests
> Task :launcher:extractDeepLinksRelease
> Task :launcher:prepareLintJar
> Task :launcher:mergeReleaseShaders
> Task :unityLibrary:packageReleaseResources
> Task :unityLibrary:extractDeepLinksRelease
> Task :launcher:checkReleaseDuplicateClasses
> Task :launcher:javaPreCompileRelease
> Task :unityLibrary:processReleaseManifest
> Task :unityLibrary:generateReleaseBuildConfig
> Task :unityLibrary:parseReleaseLocalResources

> Task :launcher:processReleaseManifest FAILED

See http://g.co/androidstudio/manifest-merger for more information about the manifest merger.


> Task :launcher:mergeReleaseResources
> Task :unityLibrary:compileReleaseLibraryResources
> Task :unityLibrary:prepareLintJarForPublish
> Task :unityLibrary:javaPreCompileRelease
> Task :unityLibrary:generateReleaseRFile
> Task :launcher:desugarReleaseFileDependencies
21 actionable tasks: 21 executed

UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)
C:\Users\user\Documents\Unity Projects\EOS Android Test\Temp\gradleOut\launcher\src\main\AndroidManifest.xml Error:
	uses-sdk:minSdkVersion 19 cannot be smaller than version 23 declared in library [:eos-sdk:] C:\Users\user\.gradle\caches\transforms-2\files-2.1\db5e8cb5ac6b3801ae923af60d09d5e4\eos-sdk\AndroidManifest.xml as the library might be using APIs not available in 19
	Suggestion: use a compatible library with a minSdk of at most 19,
		or increase this project's minSdk version to at least 23,
		or use tools:overrideLibrary="com.epicgames.mobile.eossdk" to force usage (may lead to runtime failures)

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':launcher:processReleaseManifest'.
> Manifest merger failed : uses-sdk:minSdkVersion 19 cannot be smaller than version 23 declared in library [:eos-sdk:] C:\Users\user\.gradle\caches\transforms-2\files-2.1\db5e8cb5ac6b3801ae923af60d09d5e4\eos-sdk\AndroidManifest.xml as the library might be using APIs not available in 19
  	Suggestion: use a compatible library with a minSdk of at most 19,
  		or increase this project's minSdk version to at least 23,
  		or use tools:overrideLibrary="com.epicgames.mobile.eossdk" to force usage (may lead to runtime failures)

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 15s
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8

UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)
CommandInvokationFailure: Gradle build failed. 
C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\OpenJDK\bin\java.exe -classpath "C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\Tools\gradle\lib\gradle-launcher-6.1.1.jar" org.gradle.launcher.GradleMain "-Dorg.gradle.jvmargs=-Xmx4096m" "assembleRelease"

stderr[
C:\Users\user\Documents\Unity Projects\EOS Android Test\Temp\gradleOut\launcher\src\main\AndroidManifest.xml Error:
	uses-sdk:minSdkVersion 19 cannot be smaller than version 23 declared in library [:eos-sdk:] C:\Users\user\.gradle\caches\transforms-2\files-2.1\db5e8cb5ac6b3801ae923af60d09d5e4\eos-sdk\AndroidManifest.xml as the library might be using APIs not available in 19
	Suggestion: use a compatible library with a minSdk of at most 19,
		or increase this project's minSdk version to at least 23,
		or use tools:overrideLibrary="com.epicgames.mobile.eossdk" to force usage (may lead to runtime failures)

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':launcher:processReleaseManifest'.
> Manifest merger failed : uses-sdk:minSdkVersion 19 cannot be smaller than version 23 declared in library [:eos-sdk:] C:\Users\user\.gradle\caches\transforms-2\files-2.1\db5e8cb5ac6b3801ae923af60d09d5e4\eos-sdk\AndroidManifest.xml as the library might be using APIs not available in 19
  	Suggestion: use a compatible library with a minSdk of at most 19,
  		or increase this project's minSdk version to at least 23,
  		or use tools:overrideLibrary="com.epicgames.mobile.eossdk" to force usage (may lead to runtime failures)

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 15s
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
]
stdout[
Starting a Gradle Daemon, 1 incompatible and 2 stopped Daemons could not be reused, use --status for details

> Configure project :launcher
WARNING: The option setting 'android.enableR8=false' is deprecated.
It will be removed in version 5.0 of the Android Gradle plugin.
You will no longer be able to disable R8
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\build-tools\30.0.2\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platform-tools\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platforms\android-29\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\tools\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\build-tools\30.0.2\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platform-tools\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platforms\android-29\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\tools\package.xml. Probably the SDK is read-only

> Task :unityLibrary:preBuild UP-TO-DATE
> Task :launcher:preBuild UP-TO-DATE
> Task :launcher:preReleaseBuild UP-TO-DATE
> Task :unityLibrary:preReleaseBuild UP-TO-DATE
> Task :unityLibrary:compileReleaseAidl NO-SOURCE
> Task :unityLibrary:packageReleaseRenderscript NO-SOURCE
> Task :unityLibrary:compileReleaseRenderscript NO-SOURCE
> Task :unityLibrary:generateReleaseResValues
> Task :unityLibrary:generateReleaseResources
> Task :launcher:generateReleaseBuildConfig
> Task :launcher:compileReleaseAidl NO-SOURCE
> Task :launcher:compileReleaseRenderscript NO-SOURCE
> Task :launcher:generateReleaseResValues
> Task :launcher:generateReleaseResources
> Task :launcher:createReleaseCompatibleScreenManifests
> Task :launcher:extractDeepLinksRelease
> Task :launcher:prepareLintJar
> Task :launcher:mergeReleaseShaders
> Task :unityLibrary:packageReleaseResources
> Task :unityLibrary:extractDeepLinksRelease
> Task :launcher:checkReleaseDuplicateClasses
> Task :launcher:javaPreCompileRelease
> Task :unityLibrary:processReleaseManifest
> Task :unityLibrary:generateReleaseBuildConfig
> Task :unityLibrary:parseReleaseLocalResources

> Task :launcher:processReleaseManifest FAILED

See http://g.co/androidstudio/manifest-merger for more information about the manifest merger.


> Task :launcher:mergeReleaseResources
> Task :unityLibrary:compileReleaseLibraryResources
> Task :unityLibrary:prepareLintJarForPublish
> Task :unityLibrary:javaPreCompileRelease
> Task :unityLibrary:generateReleaseRFile
> Task :launcher:desugarReleaseFileDependencies
21 actionable tasks: 21 executed
]
exit code: 1
UnityEditor.Android.Command.WaitForProgramToRun (UnityEditor.Utils.Program p, UnityEditor.Android.Command+WaitingForProcessToExit waitingForProcessToExit, System.String errorMsg) (at <f5a27061d5634be188a0593af20cb363>:0)
UnityEditor.Android.Command.Run (System.Diagnostics.ProcessStartInfo psi, UnityEditor.Android.Command+WaitingForProcessToExit waitingForProcessToExit, System.String errorMsg) (at <f5a27061d5634be188a0593af20cb363>:0)
UnityEditor.Android.Command.Run (System.String command, System.String args, System.String workingdir, UnityEditor.Android.Command+WaitingForProcessToExit waitingForProcessToExit, System.String errorMsg) (at <f5a27061d5634be188a0593af20cb363>:0)
UnityEditor.Android.AndroidJavaTools.RunJava (System.String args, System.String workingdir, System.Action`1[T] progress, System.String error) (at <f5a27061d5634be188a0593af20cb363>:0)
UnityEditor.Android.GradleWrapper.Run (UnityEditor.Android.AndroidJavaTools javaTools, System.String workingdir, System.String task, System.Action`1[T] progress) (at <f5a27061d5634be188a0593af20cb363>:0)
Rethrow as GradleInvokationException: Gradle build failed
UnityEditor.Android.GradleWrapper.Run (UnityEditor.Android.AndroidJavaTools javaTools, System.String workingdir, System.String task, System.Action`1[T] progress) (at <f5a27061d5634be188a0593af20cb363>:0)
UnityEditor.Android.PostProcessor.Tasks.BuildGradleProject.Execute (UnityEditor.Android.PostProcessor.PostProcessorContext context) (at <f5a27061d5634be188a0593af20cb363>:0)
UnityEditor.Android.PostProcessor.PostProcessRunner.RunAllTasks (UnityEditor.Android.PostProcessor.PostProcessorContext context) (at <f5a27061d5634be188a0593af20cb363>:0)
Rethrow as BuildFailedException: Exception of type 'UnityEditor.Build.BuildFailedException' was thrown.
UnityEditor.Android.PostProcessor.CancelPostProcess.AbortBuild (System.String title, System.String message, System.Exception ex) (at <f5a27061d5634be188a0593af20cb363>:0)
UnityEditor.Android.PostProcessor.PostProcessRunner.RunAllTasks (UnityEditor.Android.PostProcessor.PostProcessorContext context) (at <f5a27061d5634be188a0593af20cb363>:0)
UnityEditor.Android.PostProcessAndroidPlayer.PostProcess (UnityEditor.BuildTarget target, System.String stagingAreaData, System.String stagingArea, System.String playerPackage, System.String installPath, System.String companyName, System.String productName, UnityEditor.BuildOptions options, UnityEditor.RuntimeClassRegistry usedClassRegistry, UnityEditor.Build.Reporting.BuildReport report) (at <f5a27061d5634be188a0593af20cb363>:0)
UnityEditor.Android.AndroidBuildPostprocessor.PostProcess (UnityEditor.Modules.BuildPostProcessArgs args, UnityEditor.BuildProperties& outProperties) (at <f5a27061d5634be188a0593af20cb363>:0)
UnityEditor.PostprocessBuildPlayer.Postprocess (UnityEditor.BuildTargetGroup targetGroup, UnityEditor.BuildTarget target, System.String installPath, System.String companyName, System.String productName, System.Int32 width, System.Int32 height, UnityEditor.BuildOptions options, UnityEditor.RuntimeClassRegistry usedClassRegistry, UnityEditor.Build.Reporting.BuildReport report) (at <44c3723143904fb88deebc993c7bb491>:0)
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr, Boolean&)
Build completed with a result of 'Failed' in 127 seconds (126513 ms)
UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)
UnityEditor.BuildPlayerWindow+BuildMethodException: 4 errors
  at UnityEditor.BuildPlayerWindow+DefaultBuildMethods.BuildPlayer (UnityEditor.BuildPlayerOptions options) [0x002ca] in <44c3723143904fb88deebc993c7bb491>:0 
  at UnityEditor.BuildPlayerWindow.CallBuildMethods (System.Boolean askForBuildLocation, UnityEditor.BuildOptions defaultBuildOptions) [0x00080] in <44c3723143904fb88deebc993c7bb491>:0 
UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)
  1. Adjust the Minimum API Level in Project Settings > Player > Android > Other Settings > Identification to Android 6.0 'Marshmallow' (API Level 23)
  2. Attempt Build again
  3. The build fails again with the following errors:
A failure occured while executing
com.android.build.gradle.internal.tasks.Workers$ActionFacade
See the Console for details.
Starting a Gradle Daemon, 1 incompatible Daemon could not be reused, use --status for details

> Configure project :launcher
WARNING: The option setting 'android.enableR8=false' is deprecated.
It will be removed in version 5.0 of the Android Gradle plugin.
You will no longer be able to disable R8
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\build-tools\30.0.2\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platform-tools\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platforms\android-29\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\tools\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\build-tools\30.0.2\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platform-tools\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platforms\android-29\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\tools\package.xml. Probably the SDK is read-only

> Task :launcher:preBuild UP-TO-DATE
> Task :unityLibrary:preBuild UP-TO-DATE
> Task :unityLibrary:preReleaseBuild UP-TO-DATE
> Task :launcher:preReleaseBuild UP-TO-DATE
> Task :unityLibrary:compileReleaseAidl NO-SOURCE
> Task :unityLibrary:packageReleaseRenderscript NO-SOURCE
> Task :launcher:generateReleaseBuildConfig UP-TO-DATE
> Task :launcher:compileReleaseAidl NO-SOURCE
> Task :unityLibrary:compileReleaseRenderscript NO-SOURCE
> Task :launcher:compileReleaseRenderscript NO-SOURCE
> Task :unityLibrary:generateReleaseResValues UP-TO-DATE
> Task :unityLibrary:generateReleaseResources UP-TO-DATE
> Task :launcher:javaPreCompileRelease UP-TO-DATE
> Task :launcher:generateReleaseResValues UP-TO-DATE
> Task :launcher:generateReleaseResources UP-TO-DATE
> Task :launcher:createReleaseCompatibleScreenManifests UP-TO-DATE
> Task :launcher:extractDeepLinksRelease UP-TO-DATE
> Task :unityLibrary:packageReleaseResources UP-TO-DATE
> Task :launcher:prepareLintJar UP-TO-DATE
> Task :unityLibrary:extractDeepLinksRelease UP-TO-DATE
> Task :launcher:mergeReleaseResources UP-TO-DATE
> Task :launcher:mergeReleaseShaders UP-TO-DATE
> Task :launcher:checkReleaseDuplicateClasses UP-TO-DATE
> Task :launcher:desugarReleaseFileDependencies UP-TO-DATE
> Task :launcher:compileReleaseShaders NO-SOURCE
> Task :launcher:generateReleaseAssets UP-TO-DATE
> Task :launcher:processReleaseJavaRes NO-SOURCE
> Task :launcher:collectReleaseDependencies UP-TO-DATE
> Task :launcher:sdkReleaseDependencyData UP-TO-DATE
> Task :launcher:mergeExtDexRelease UP-TO-DATE
> Task :launcher:mergeReleaseJniLibFolders UP-TO-DATE
> Task :launcher:validateSigningRelease UP-TO-DATE
> Task :unityLibrary:compileReleaseLibraryResources UP-TO-DATE
> Task :unityLibrary:parseReleaseLocalResources UP-TO-DATE
> Task :unityLibrary:generateReleaseBuildConfig UP-TO-DATE
> Task :unityLibrary:javaPreCompileRelease UP-TO-DATE
> Task :unityLibrary:prepareLintJarForPublish UP-TO-DATE
> Task :unityLibrary:mergeReleaseShaders UP-TO-DATE
> Task :unityLibrary:compileReleaseShaders NO-SOURCE
> Task :unityLibrary:generateReleaseAssets UP-TO-DATE
> Task :unityLibrary:packageReleaseAssets
> Task :unityLibrary:processReleaseJavaRes NO-SOURCE
> Task :unityLibrary:bundleLibResRelease NO-SOURCE
> Task :unityLibrary:mergeReleaseJniLibFolders UP-TO-DATE
> Task :unityLibrary:mergeReleaseNativeLibs UP-TO-DATE
> Task :launcher:mergeReleaseAssets
> Task :launcher:mergeReleaseJavaResource UP-TO-DATE
> Task :unityLibrary:stripReleaseDebugSymbols UP-TO-DATE
> Task :unityLibrary:copyReleaseJniLibsProjectOnly UP-TO-DATE
> Task :unityLibrary:processReleaseManifest
> Task :launcher:mergeReleaseNativeLibs UP-TO-DATE
> Task :unityLibrary:generateReleaseRFile UP-TO-DATE
> Task :unityLibrary:compileReleaseJavaWithJavac UP-TO-DATE
> Task :unityLibrary:bundleLibCompileToJarRelease UP-TO-DATE
> Task :unityLibrary:bundleLibRuntimeToJarRelease UP-TO-DATE
> Task :launcher:processReleaseManifest
> Task :launcher:processReleaseResources FAILED
39 actionable tasks: 5 executed, 34 up-to-date

UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)
FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':launcher:processReleaseResources'.
> A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade
   > Android resource linking failed
     C:\Users\user\.gradle\caches\transforms-2\files-2.1\db5e8cb5ac6b3801ae923af60d09d5e4\eos-sdk\res\layout\activity_eos_web_auth.xml:9: AAPT: error: attribute layout_constraintBottom_toBottomOf (aka com.company.eostest:layout_constraintBottom_toBottomOf) not found.
         
     C:\Users\user\.gradle\caches\transforms-2\files-2.1\db5e8cb5ac6b3801ae923af60d09d5e4\eos-sdk\res\layout\activity_eos_web_auth.xml:9: AAPT: error: attribute layout_constraintEnd_toEndOf (aka com.company.eostest:layout_constraintEnd_toEndOf) not found.
         
     C:\Users\user\.gradle\caches\transforms-2\files-2.1\db5e8cb5ac6b3801ae923af60d09d5e4\eos-sdk\res\layout\activity_eos_web_auth.xml:9: AAPT: error: attribute layout_constraintStart_toStartOf (aka com.company.eostest:layout_constraintStart_toStartOf) not found.
         
     C:\Users\user\.gradle\caches\transforms-2\files-2.1\db5e8cb5ac6b3801ae923af60d09d5e4\eos-sdk\res\layout\activity_eos_web_auth.xml:9: AAPT: error: attribute layout_constraintTop_toTopOf (aka com.company.eostest:layout_constraintTop_toTopOf) not found.
         

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 12s
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8

UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)
CommandInvokationFailure: Gradle build failed. 
C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\OpenJDK\bin\java.exe -classpath "C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\Tools\gradle\lib\gradle-launcher-6.1.1.jar" org.gradle.launcher.GradleMain "-Dorg.gradle.jvmargs=-Xmx4096m" "assembleRelease"

stderr[

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':launcher:processReleaseResources'.
> A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade
   > Android resource linking failed
     C:\Users\user\.gradle\caches\transforms-2\files-2.1\db5e8cb5ac6b3801ae923af60d09d5e4\eos-sdk\res\layout\activity_eos_web_auth.xml:9: AAPT: error: attribute layout_constraintBottom_toBottomOf (aka com.company.eostest:layout_constraintBottom_toBottomOf) not found.
         
     C:\Users\user\.gradle\caches\transforms-2\files-2.1\db5e8cb5ac6b3801ae923af60d09d5e4\eos-sdk\res\layout\activity_eos_web_auth.xml:9: AAPT: error: attribute layout_constraintEnd_toEndOf (aka com.company.eostest:layout_constraintEnd_toEndOf) not found.
         
     C:\Users\user\.gradle\caches\transforms-2\files-2.1\db5e8cb5ac6b3801ae923af60d09d5e4\eos-sdk\res\layout\activity_eos_web_auth.xml:9: AAPT: error: attribute layout_constraintStart_toStartOf (aka com.company.eostest:layout_constraintStart_toStartOf) not found.
         
     C:\Users\user\.gradle\caches\transforms-2\files-2.1\db5e8cb5ac6b3801ae923af60d09d5e4\eos-sdk\res\layout\activity_eos_web_auth.xml:9: AAPT: error: attribute layout_constraintTop_toTopOf (aka com.company.eostest:layout_constraintTop_toTopOf) not found.
         

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 12s
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
]
stdout[
Starting a Gradle Daemon, 1 incompatible Daemon could not be reused, use --status for details

> Configure project :launcher
WARNING: The option setting 'android.enableR8=false' is deprecated.
It will be removed in version 5.0 of the Android Gradle plugin.
You will no longer be able to disable R8
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\build-tools\30.0.2\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platform-tools\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platforms\android-29\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\tools\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\build-tools\30.0.2\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platform-tools\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\platforms\android-29\package.xml. Probably the SDK is read-only
Exception while marshalling C:\Program Files\Unity\Hub\Editor\2020.3.15f2\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\tools\package.xml. Probably the SDK is read-only

> Task :launcher:preBuild UP-TO-DATE
> Task :unityLibrary:preBuild UP-TO-DATE
> Task :unityLibrary:preReleaseBuild UP-TO-DATE
> Task :launcher:preReleaseBuild UP-TO-DATE
> Task :unityLibrary:compileReleaseAidl NO-SOURCE
> Task :unityLibrary:packageReleaseRenderscript NO-SOURCE
> Task :launcher:generateReleaseBuildConfig UP-TO-DATE
> Task :launcher:compileReleaseAidl NO-SOURCE
> Task :unityLibrary:compileReleaseRenderscript NO-SOURCE
> Task :launcher:compileReleaseRenderscript NO-SOURCE
> Task :unityLibrary:generateReleaseResValues UP-TO-DATE
> Task :unityLibrary:generateReleaseResources UP-TO-DATE
> Task :launcher:javaPreCompileRelease UP-TO-DATE
> Task :launcher:generateReleaseResValues UP-TO-DATE
> Task :launcher:generateReleaseResources UP-TO-DATE
> Task :launcher:createReleaseCompatibleScreenManifests UP-TO-DATE
> Task :launcher:extractDeepLinksRelease UP-TO-DATE
> Task :unityLibrary:packageReleaseResources UP-TO-DATE
> Task :launcher:prepareLintJar UP-TO-DATE
> Task :unityLibrary:extractDeepLinksRelease UP-TO-DATE
> Task :launcher:mergeReleaseResources UP-TO-DATE
> Task :launcher:mergeReleaseShaders UP-TO-DATE
> Task :launcher:checkReleaseDuplicateClasses UP-TO-DATE
> Task :launcher:desugarReleaseFileDependencies UP-TO-DATE
> Task :launcher:compileReleaseShaders NO-SOURCE
> Task :launcher:generateReleaseAssets UP-TO-DATE
> Task :launcher:processReleaseJavaRes NO-SOURCE
> Task :launcher:collectReleaseDependencies UP-TO-DATE
> Task :launcher:sdkReleaseDependencyData UP-TO-DATE
> Task :launcher:mergeExtDexRelease UP-TO-DATE
> Task :launcher:mergeReleaseJniLibFolders UP-TO-DATE
> Task :launcher:validateSigningRelease UP-TO-DATE
> Task :unityLibrary:compileReleaseLibraryResources UP-TO-DATE
> Task :unityLibrary:parseReleaseLocalResources UP-TO-DATE
> Task :unityLibrary:generateReleaseBuildConfig UP-TO-DATE
> Task :unityLibrary:javaPreCompileRelease UP-TO-DATE
> Task :unityLibrary:prepareLintJarForPublish UP-TO-DATE
> Task :unityLibrary:mergeReleaseShaders UP-TO-DATE
> Task :unityLibrary:compileReleaseShaders NO-SOURCE
> Task :unityLibrary:generateReleaseAssets UP-TO-DATE
> Task :unityLibrary:packageReleaseAssets
> Task :unityLibrary:processReleaseJavaRes NO-SOURCE
> Task :unityLibrary:bundleLibResRelease NO-SOURCE
> Task :unityLibrary:mergeReleaseJniLibFolders UP-TO-DATE
> Task :unityLibrary:mergeReleaseNativeLibs UP-TO-DATE
> Task :launcher:mergeReleaseAssets
> Task :launcher:mergeReleaseJavaResource UP-TO-DATE
> Task :unityLibrary:stripReleaseDebugSymbols UP-TO-DATE
> Task :unityLibrary:copyReleaseJniLibsProjectOnly UP-TO-DATE
> Task :unityLibrary:processReleaseManifest
> Task :launcher:mergeReleaseNativeLibs UP-TO-DATE
> Task :unityLibrary:generateReleaseRFile UP-TO-DATE
> Task :unityLibrary:compileReleaseJavaWithJavac UP-TO-DATE
> Task :unityLibrary:bundleLibCompileToJarRelease UP-TO-DATE
> Task :unityLibrary:bundleLibRuntimeToJarRelease UP-TO-DATE
> Task :launcher:processReleaseManifest
> Task :launcher:processReleaseResources FAILED
39 actionable tasks: 5 executed, 34 up-to-date
]
exit code: 1
UnityEditor.Android.Command.WaitForProgramToRun (UnityEditor.Utils.Program p, UnityEditor.Android.Command+WaitingForProcessToExit waitingForProcessToExit, System.String errorMsg) (at <f5a27061d5634be188a0593af20cb363>:0)
UnityEditor.Android.Command.Run (System.Diagnostics.ProcessStartInfo psi, UnityEditor.Android.Command+WaitingForProcessToExit waitingForProcessToExit, System.String errorMsg) (at <f5a27061d5634be188a0593af20cb363>:0)
UnityEditor.Android.Command.Run (System.String command, System.String args, System.String workingdir, UnityEditor.Android.Command+WaitingForProcessToExit waitingForProcessToExit, System.String errorMsg) (at <f5a27061d5634be188a0593af20cb363>:0)
UnityEditor.Android.AndroidJavaTools.RunJava (System.String args, System.String workingdir, System.Action`1[T] progress, System.String error) (at <f5a27061d5634be188a0593af20cb363>:0)
UnityEditor.Android.GradleWrapper.Run (UnityEditor.Android.AndroidJavaTools javaTools, System.String workingdir, System.String task, System.Action`1[T] progress) (at <f5a27061d5634be188a0593af20cb363>:0)
Rethrow as GradleInvokationException: Gradle build failed
UnityEditor.Android.GradleWrapper.Run (UnityEditor.Android.AndroidJavaTools javaTools, System.String workingdir, System.String task, System.Action`1[T] progress) (at <f5a27061d5634be188a0593af20cb363>:0)
UnityEditor.Android.PostProcessor.Tasks.BuildGradleProject.Execute (UnityEditor.Android.PostProcessor.PostProcessorContext context) (at <f5a27061d5634be188a0593af20cb363>:0)
UnityEditor.Android.PostProcessor.PostProcessRunner.RunAllTasks (UnityEditor.Android.PostProcessor.PostProcessorContext context) (at <f5a27061d5634be188a0593af20cb363>:0)
Rethrow as BuildFailedException: Exception of type 'UnityEditor.Build.BuildFailedException' was thrown.
UnityEditor.Android.PostProcessor.CancelPostProcess.AbortBuild (System.String title, System.String message, System.Exception ex) (at <f5a27061d5634be188a0593af20cb363>:0)
UnityEditor.Android.PostProcessor.PostProcessRunner.RunAllTasks (UnityEditor.Android.PostProcessor.PostProcessorContext context) (at <f5a27061d5634be188a0593af20cb363>:0)
UnityEditor.Android.PostProcessAndroidPlayer.PostProcess (UnityEditor.BuildTarget target, System.String stagingAreaData, System.String stagingArea, System.String playerPackage, System.String installPath, System.String companyName, System.String productName, UnityEditor.BuildOptions options, UnityEditor.RuntimeClassRegistry usedClassRegistry, UnityEditor.Build.Reporting.BuildReport report) (at <f5a27061d5634be188a0593af20cb363>:0)
UnityEditor.Android.AndroidBuildPostprocessor.PostProcess (UnityEditor.Modules.BuildPostProcessArgs args, UnityEditor.BuildProperties& outProperties) (at <f5a27061d5634be188a0593af20cb363>:0)
UnityEditor.PostprocessBuildPlayer.Postprocess (UnityEditor.BuildTargetGroup targetGroup, UnityEditor.BuildTarget target, System.String installPath, System.String companyName, System.String productName, System.Int32 width, System.Int32 height, UnityEditor.BuildOptions options, UnityEditor.RuntimeClassRegistry usedClassRegistry, UnityEditor.Build.Reporting.BuildReport report) (at <44c3723143904fb88deebc993c7bb491>:0)
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr, Boolean&)
Build completed with a result of 'Failed' in 64 seconds (63936 ms)
UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)
UnityEditor.BuildPlayerWindow+BuildMethodException: 4 errors
  at UnityEditor.BuildPlayerWindow+DefaultBuildMethods.BuildPlayer (UnityEditor.BuildPlayerOptions options) [0x002ca] in <44c3723143904fb88deebc993c7bb491>:0 
  at UnityEditor.BuildPlayerWindow.CallBuildMethods (System.Boolean askForBuildLocation, UnityEditor.BuildOptions defaultBuildOptions) [0x00080] in <44c3723143904fb88deebc993c7bb491>:0 
UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)

I'm not sure how to fix these last build errors. I've tried messing with custom gradle build files, different project settings, adding a keystore, running the editor as admin, and trying an IL2CPP build, and I still can't get it to build.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.