UNET: правильная регистрация динамических объектов

Я работаю над своим личным проектом как любитель программирования. Моя цель с этим проектом состоит в том, чтобы позволить игрокам строить и настраивать свои собственные корабли, а затем присоединяться к общедоступному серверу и сражаться на нем.

Ошибка, которую я получаю, такова:

Не удалось создать объект сервера, assetsId=0000000000000000000000000000000e7 netId=3 UnityEngine.Networking.NetworkIdentity:UNetStaticUpdate()

И вот наиболее подходящий код для него:

    public void LoadShip(Vector2 pos, string path = "save.xml",Ship oldship = null){
    Debug.Log ("Loading Ship!");
    ShipObject shipObj;
    if (oldship != null) {
        shipObj = oldship.shipObjectClass;
    } else {
        GameObject newShip = new GameObject ();
        shipObj = newShip.AddComponent<ShipObject> ();
        Rigidbody2D rb = newShip.AddComponent<Rigidbody2D> ();
        rb.gravityScale = 0;
        rb.drag = 0.1f;
        rb.angularDrag = 0.1f;
    }
    shipObj.PrepareForLoad ();
    XmlSerializer serializer = new XmlSerializer (typeof(Ship));
    FileStream reader = new FileStream (Path.Combine(Application.dataPath, path), FileMode.Open);
    if (shipObj.LoadShip ((Ship)serializer.Deserialize (reader))) {
        shipObj.gameObject.transform.position = pos;
        reader.Close ();
        //Give all the children rigidbodies, as they are loaded without them
        //by default for when physics are not needed.
        for (int i = 0; i < shipObj.transform.childCount; i++) {
            GameObject child = shipObj.transform.GetChild (i).gameObject;
            Rigidbody2D rb = child.AddComponent<Rigidbody2D> ();
            rb.gravityScale = 0;
            rb.drag = 0;
            rb.angularDrag = 0;
            rb.mass = 0;
            rb.isKinematic = true;
        }
        shipObj.name = shipObj.ship.shipName;
        Debug.LogError ("Ship name = " + shipObj.name);
        ClientScene.RegisterPrefab (shipObj.gameObject, NetworkHash128.Parse (shipObj.name));
        GameObject prefab;
        ClientScene.prefabs.TryGetValue (NetworkHash128.Parse (shipObj.name), out prefab);
        if (!prefab) {
            Debug.LogError ("Prefab not registered!");
            return;
        }
        if (shipObj.GetComponent<NetworkIdentity> () != null) {
            Cmd_SpawnShip (prefab);
        } else {
            Debug.LogError ("No network identity here!");
        }
    }
}

[Command]
public void Cmd_SpawnShip(GameObject ship){
    NetworkServer.Spawn (ship);
}

Кратко о том, что вы видите: Игрок вызывает LoadShip() с желаемой позицией возрождения, путем загрузки корабля и, возможно, с уже существующим кораблем, который он хочет переопределить. Затем он загружает все необходимые данные с помощью XML, добавляет физику и регистрирует префаб на основе имени корабля, которое во всех случаях должно быть уникальным.

Как основной объект корабля, так и все его дочерние объекты (например, стены, пушки, консоли и т. д.) получают компоненты NetworkIdentity, а главному кораблю также предоставляется компонент NetworkTransform в LoadShip().

Корабль отлично появляется для любого клиента, который решил его загрузить, но ни сервер, ни другие клиенты не могут его увидеть и вместо этого получают эту ошибку.

Я пытался исправить это... Может быть, последние 3 часа. Это был долгий день, и я надеюсь, что вы поверите мне, когда я скажу, что я тщательно искал в Google и stackoverflow уже опубликованный ответ на мой вопрос. Наиболее распространенными проблемами среди прочих были: Просто не зарегистрировать префаб, зарегистрировать префаб на сервере, забыть дать ему assetsID, не вызвать его на клиенте/что-то с полномочиями. Я почти уверен, что избежал всего этого, и, пожалуйста, не ссылайтесь на руководства по Unity. Уверяю вас, я читал их несколько раз.

Кроме того, если я просто размещаю игру только с одним клиентом и появляюсь на корабле, префаб не отображается в списке «зарегистрированных префабов» Network Manager, даже если у меня есть сетевой менеджер на уровне журнала «Отладка», и он говорит мне, что он успешно зарегистрировал префаб.

Вот и вся актуальная информация. Я заранее благодарю вас за потраченное время, надеюсь, какая бы ошибка, которую я сделал, не была слишком явно очевидной.


person GrimdeReaper    schedule 25.10.2017    source источник


Ответы (1)


Появилась мотивация еще немного заняться этой проблемой. После еще нескольких часов старательного поиска ответов в Интернете; Эврика! Два неправильных представления, которые у меня были в моем коде, были;

  • RegisterClientPrefab() не автоматически создает префаб из GameObject для использования сервером. Я не уверен, почему я вообще подумал об этом, в ретроспективе это кажется довольно очевидным.
  • Я предположил, что когда вызывается RegisterClientPrefab(), он говорит серверу: «Эй, ты. Я кое-что сделал. Поделись со всеми!» Но на самом деле он просто сообщает этому отдельному клиенту, где искать конкретный идентификатор актива.

Способ, которым я исправлял эти заблуждения, заключался в том, что я просто предоставил серверу словарь, содержащий идентификатор актива каждого корабля и сериализованный массив byte[] XML-файла, из которого он был загружен, за которым следовал RegisterSpawnHandler, который привел к правильному созданию объектов. Я не уверен, что это лучший способ сделать это, и если есть какая-либо другая форма кодирования, которую проще/быстрее отправить по сети, чем массив byte[], но это работает для меня .

person GrimdeReaper    schedule 06.11.2017