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

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

Я получаю такую ​​ошибку:

Не удалось создать объект сервера, assetId=000000000000000000000000000000e7 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 и stackru уже опубликованный ответ на мой вопрос. Наиболее распространенными проблемами среди других были: просто не регистрировать префаб, зарегистрировать префаб на сервере, забыть дать ему идентификатор ресурса, не вызывать его на клиенте / чем-то с полномочиями. Я уверен, что избежал всех этих вещей, и, пожалуйста, не связывайте меня с учебниками по Unity. Я обещаю вам, я прочитал их несколько раз.

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

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

1 ответ

Решение

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

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

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

Другие вопросы по тегам