Unity3D. Попытка отправить команду для объекта без полномочий

У меня есть многопользовательская пошаговая стратегическая игра, в которой нужен игровой менеджер, который контролирует текущее состояние игры (чья очередь и т.д.) Этот менеджер должен быть общим для каждого клиента, его состояние должно быть синхронизировано на сервере.

Вот как я это делаю: Объект диспетчера игры - NetworkBehaviour, и он имеет NetworkIdentity, который не является полномочиями локального игрока или сервера. Я сделал собственный NetworkManager, и он запускает Game Manager при подключении к клиенту, а также проверяет, является ли он сервером. Вот код:

public override void OnClientConnect(NetworkConnection conn)
    {
        ClientScene.Ready(conn);
        if (NetworkServer.active)
        {
            var manager = Instantiate(MultiplayerManagerPrefab, Vector3.zero, Quaternion.identity) as GameObject;
            var tacticsManager = manager.GetComponent<MultiplayerManagerModel>();
            NetworkServer.RegisterHandler(MsgType.AddPlayer, tacticsManager.CreatePlayerOnServer);
            NetworkServer.Spawn(manager);
        }
        ClientScene.AddPlayer(0);
    }

Когда я запускаю его на сервере, он работает нормально, он создает экземпляр на клиенте и синхронизирует переменные от сервера к клиенту. Но когда я пытаюсь запустить команды из клиента, он игнорирует их и выдает следующее предупреждение:

Попытка отправить команду для объекта без полномочий. UnityEngine.Networking.NetworkBehaviour:SendCommandInternal(NetworkWriter, Int32, String)

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

3 ответа

Рядом с вашим фрагментом кода, предупреждение

Попытка отправить команду для объекта без полномочий.

Означает, что: вы посылаете команду от объекта, полномочия которого у вашего (игрока) отсутствуют.

Что говорится в документации Unity: Команды от объектов игрока на клиенте отправляются объектам игрока на сервере. В целях безопасности Команды могут отправляться только с объекта ВАШЕГО игрока, поэтому вы не можете управлять объектами других игроков.

НО

Начиная с выпуска Unity 5.2 можно отправлять команды от неигровых объектов, которые имеют полномочия клиента. Эти объекты должны быть созданы с помощью NetworkServer.SpawnWithClientAuthority или иметь полномочия, установленные с помощью NetworkIdentity.AssignClientAuthority. Команды, отправленные из этих объектов, выполняются на экземпляре объекта сервера, а не на связанном объекте проигрывателя для клиента ( подробнее).

Итак, каково решение: Перед отправкой команды (или выполнением функции команды) назначьте полномочия этого объекта вашему проигрывателю. Что-то вроде этого

assignAuthorityObj.GetComponent<NetworkIdentity>().AssignClientAuthority(this.GetComponent<NetworkIdentity>().connectionToClient);

" this " будет представлять ваш объект Player. После выполнения командного вызова вы можете удалить полномочия, используя этот фрагмент кода.

 assignAuthorityObj.GetComponent<NetworkIdentity>().RemoveClientAuthority(this.GetComponent<NetworkIdentity>().connectionToClient);

Опять же, " это " будет представлять для вашего объекта Player.

Важное примечание: я обычно назначаю полномочия объекта (если я хочу это использовать), используя OnTriggerEnter, и удаляю полномочия для OnTriggerExit. Это зависит от конкретного сценария, при котором вы хотите получить или удалить объектные права доступа.

Вы не можете отправить команду без местных полномочий.

if (!isLocalPlayer) return;

Но какие данные вы отправляете с помощью этой команды? В общем и как ты сказал

"это состояние должно быть синхронизировано на сервере"

Так что, ИМХО, у вас нет причин отправлять Command от вашего игрока. Команды должны быть для ввода игрока. Эти входы будут запускать действия в вашей игре. Ваш менеджер будет получать информацию об этих действиях (обновление счета, конец игры...) и отправлять данные и / или инициировать действия на клиентах, используя ClientRpc

Это модель авторитета сервера. Если вы позволите локальному объекту отправлять команды, хакер может легко войти и сказать вашему менеджеру

"Эй, это моя очередь. Эй, это моя очередь снова. Эй, мой счет 9999999, и я выиграл игру за 1 секунду".

Если вы используете зеркало, используйте Bypass Authority, потребовался целый день, чтобы попытаться реализовать вышеуказанные решения, которые не сработали. Вот как это нужно сделать: https://mirror-networking.gitbook.io/docs/guides/communication/remote-actions

      [Command(requiresAuthority = false)]
public void Something (){
   
}
Другие вопросы по тегам