Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

return values from Commands #647

Closed
paulpach opened this issue Mar 24, 2019 · 7 comments
Closed

return values from Commands #647

paulpach opened this issue Mar 24, 2019 · 7 comments
Labels
enhancement New feature or request

Comments

@paulpach
Copy link
Contributor

paulpach commented Mar 24, 2019

I would like to be able to return values from [Command].

One way to do it would be to use async/await, this is how a developer would use it:

class Player : NetworkBehaviour 
{
    [Command]
    public async Task<bool> CmdPurchase(string item) 
    {
        ...
        return success;
    }

    [Client]
    public async void ClickPurchase()
    {
        if (await CmdPurchase("sword")) 
        {
            Debug.Log("Sword purchased");
        }
        else
        {
            Debug.Log("Not enough money");
        }
    }
}
@paulpach paulpach added the enhancement New feature or request label Mar 24, 2019
@paulpach paulpach changed the title return values form Commands return values from Commands Mar 24, 2019
@uweeby
Copy link
Contributor

uweeby commented Mar 24, 2019

Would really love to see this in Mirror.

@miwarnec
Copy link
Collaborator

Task/async/await is going to take a huge performance hit. That'll probably not scale beyond 100+ ccu again

@miwarnec
Copy link
Collaborator

also, if someone awaits a unreliable command then there is a chance that they'll wait forever

@uweeby
Copy link
Contributor

uweeby commented Mar 25, 2019

The callbacks in Insight have a time out and possible error return.

@paulpach
Copy link
Contributor Author

@vis2k this would be used for purchasing or low volume calls. It should not affect CCU unless someone bases his whole game on it. If commands are void, we would keep using whatever we are using now.

Yes, it is possible to wait forever, you can easily do a timeout with await, so that should not be an issue

@MaZyGer
Copy link
Contributor

MaZyGer commented Feb 7, 2020

@paulpach
I just made this few days ago for a custom client (for a masterserver / matchmakign which uses websockettransport). Its not best way and also not optimitzed. I use actions for that and also it not a command. I use messagebase for it.

Example why I needed it. A client requests a serverlist from matchmakingserver / masterserver, (lets call it mserver) and mserver requests from gameserver the information, if mserver receive an answer he will send route the information back to the client / requester.
RequestServerUpdateMessage = MServer request update from gameserver.
ServerUpdateMessage this is the event / message we wait for.

I called it SendAsync but it isn't actually async xD

        private void OnRequestServerlistMessage(int conn, RequestServerlistMessage arg2)
        {
            foreach(var keyPair in serverlist)
            {
                SendAsync<RequestServerUpdateMessage, ServerUpdateMessage>(keyPair.Key, new RequestServerUpdateMessage(), () =>
                {
                    Send(conn, new ServerlistMessage()
                    {
                        serverInformation = serverlist[keyPair.Key]
                    });
                });
            }
        }
        public static Dictionary<int, System.Action<int, NetworkReader>> messageHandlers = new Dictionary<int, System.Action<int, NetworkReader>>();
        private void OnServerDataReceived(int conn, ArraySegment<byte> buffer, int channelId)
        {
            NetworkReader reader = new NetworkReader(buffer);
            if (MessagePacker.UnpackMessage(reader, out int msgType))
            {
                if (messageHandlers.TryGetValue(msgType, out System.Action<int, NetworkReader> action))
                {
                    action.Invoke(conn, reader);

                    if (listAsyncs.ContainsKey(msgType))
                    {
                        var funcList = listAsyncs[msgType];
                        MessageAsync messageAsync = null;
                        foreach(var a in funcList)
                        {
                            if(a.UniqueId == conn)
                            {
                                a.Action.Invoke();
                                messageAsync = a;
                                break;
                            }

                        }

                        if (messageAsync != null)
                            funcList.Remove(messageAsync);
                    }

                }
            }
        }
        public bool SendAsync<T, M>(int conn, T msg, System.Action action, int channelId = Channels.DefaultReliable) where T : IMessageBase where M : IMessageBase
        {
            NetworkWriter writer = NetworkWriterPool.GetWriter();

            MessagePacker.Pack(msg, writer);
            var msgId = MessagePacker.GetId<M>();

            MessageAsync msgAsync = new MessageAsync(action, conn);

            if (listAsyncs.ContainsKey(msgId))
            {
                var list = listAsyncs[msgId];
                list.Add(msgAsync);
            } else {
                listAsyncs.Add(msgId, new List<MessageAsync>() { msgAsync });
            }

            bool result = transport.ServerSend(new List<int>() { conn }, channelId, writer.ToArraySegment());

            NetworkWriterPool.Recycle(writer);
            return result;
        }

Its not perfect, because I have still problem to identifier who called when what ^^. I just used connection id for now.
You do not have custom client I think so you could make custom messagebase which contains the actual message

@miwarnec
Copy link
Collaborator

miwarnec commented Jun 2, 2020

closing because we can't do async for networking. it's not gonna scale, and it's not obvious that it doesn't when using it.

@miwarnec miwarnec closed this as completed Jun 2, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants