//Merge the parameter into the current one
 public void Merge(VibratorControllerMessage otherMessage)
 {
     foreach (var message in otherMessage.messages)
     {
         this.messages[message.Key] = message.Value;
     }
 }
        public static void SendMessage(VibratorControllerMessage message)
        {
            if (client == null || message.Target == null)
            {
                return;
            }
            if (message.Command == Commands.SetSpeeds)
            {
                lock (messagesToSendPerTarget)
                {
                    if (messagesToSendPerTarget.ContainsKey(message.Target))
                    {
                        messagesToSendPerTarget[message.Target].Merge(message);
                    }
                    else
                    {
                        messagesToSendPerTarget[message.Target] = message;
                    }
                }
                return;
            }

            client.Send(new Message()
            {
                Method = "VibratorControllerMessage", Target = message.Target, Content = JsonConvert.SerializeObject(message)
            });
        }
        private static void handleSetSpeeds(VibratorControllerMessage msg)
        {
            foreach (var toymessage in msg.messages.Select(x => x.Value))
            {
                if (!Toy.myToys.ContainsKey(toymessage.ToyID))
                {
                    continue;
                }

                Toy toy = Toy.myToys[toymessage.ToyID];

                switch (toymessage.Command)
                {
                //Local toy commands
                case Commands.SetSpeed:
                    if (toy?.hand == Hand.shared)
                    {
                        toy?.setSpeed(toymessage.Strength);
                    }

                    break;

                case Commands.SetSpeedEdge:
                    if (toy?.hand == Hand.shared)
                    {
                        toy?.setEdgeSpeed(toymessage.Strength);
                    }

                    break;

                case Commands.SetAir:
                    if (toy?.hand == Hand.shared)
                    {
                        toy?.setContraction(toymessage.Strength);
                    }

                    break;

                case Commands.SetRotate:
                    if (toy?.hand == Hand.shared)
                    {
                        toy?.rotate();
                    }

                    break;
                }
            }
        }
        //message from server
        internal static async void message(VibratorControllerMessage msg, string userID)
        {
            await AsyncUtils.YieldToMainThread();

            switch (msg.Command)
            {
            case Commands.GetToys:
                handleGetToys(userID);
                break;

            case Commands.ToyUpdate:
                handleToyUpdate(msg, userID);
                break;

            case Commands.SetSpeeds:
                handleSetSpeeds(msg);
                break;
            }
        }
        private static void handleGetToys(string userID)
        {
            MelonLogger.Msg("Control Client requested toys");
            VibratorControllerMessage messageToSend = null;

            foreach (KeyValuePair <ulong, Toy> entry in Toy.myToys.Where(x => x.Value.hand == Hand.shared))
            {
                entry.Value.connectedTo = userID;
                if (messageToSend == null)
                {
                    messageToSend = new VibratorControllerMessage(userID, Commands.AddToy, entry.Value);
                }
                else
                {
                    messageToSend.Merge(new VibratorControllerMessage(userID, Commands.AddToy, entry.Value));
                }
            }

            if (messageToSend != null)
            {
                VRCWSIntegration.SendMessage(messageToSend);
            }
        }
        private static void handleToyUpdate(VibratorControllerMessage msg, string userID)
        {
            foreach (var toy in msg.messages.Select(x => x.Value))
            {
                switch (toy.Command)
                {
                //remote toy commands
                case Commands.AddToy:

                    MelonLogger.Msg($"Adding : {toy.ToyName} : {toy.ToyID}");
                    new Toy(toy.ToyName, toy.ToyID, userID, toy.ToyMaxSpeed, toy.ToyMaxSpeed2, toy.ToyMaxLinear, toy.ToySupportsRotate, TabButton.SubMenu);

                    break;

                case Commands.RemoveToy:

                    if (Toy.remoteToys.ContainsKey(toy.ToyID))
                    {
                        Toy.remoteToys[toy.ToyID].disable();
                    }
                    break;
                }
            }
        }