Example #1
0
    void onStream(AgentPrivate agent, string medialUrl)
    {
        bool throttled = false;

        try
        {
            ScenePrivate.OverrideAudioStream(medialUrl);
            agent.SendChat("Audio Stream URL successfully updated to " + medialUrl);
            if (DebugLogging)
            {
                Log.Write("New audio stream URL: " + medialUrl);
            }
        } catch
        {
            throttled = true;
            if (DebugLogging)
            {
                Log.Write("Throttled: Unable to update audio stream URL.");
            }
        }

        if (throttled)
        {
            try
            {
                agent.SendChat("Audio stream URL update was throttled.  Try again.");
            }
            catch
            {
                // Agent left
            }
        }
    }
Example #2
0
        public void RecordPickupTimed(AgentPrivate collectorAgent, Guid collectedItemId)
        {
            Guid     personaId = collectorAgent.AgentInfo.AvatarUuid;
            TimedRun timedRun;

            if (!TimedCollectorProgress.TryGetValue(personaId, out timedRun))
            {
                timedRun = new TimedRun(Collectibles);
            }
            bool isNew = timedRun.CollectItem(collectedItemId);

            TimedCollectorProgress[personaId] = timedRun;

            if (!isNew)
            {
                return;
            }
            if (timedRun.IsFinished())
            {
                collectorAgent.SendChat($"Congratulations, you collected all {Collectibles.Count} items, taking {timedRun.ElapsedTime().TotalSeconds}.{timedRun.ElapsedTime().Milliseconds} seconds!");
                PostResults(personaId, timedRun.ElapsedTime());
            }
            else
            {
                collectorAgent.SendChat($"You've collected {timedRun.Collected()} / {Collectibles.Count}, time: {timedRun.ElapsedTime().TotalSeconds}.{timedRun.ElapsedTime().Milliseconds} seconds");
            }
        }
Example #3
0
        public void RecordPickup(AgentPrivate collectorAgent, Guid collectedItemId)
        {
            Guid           personaId = collectorAgent.AgentInfo.AvatarUuid;
            HashSet <Guid> collectedItems;

            if (!CollectorProgress.TryGetValue(personaId, out collectedItems))
            {
                collectedItems = new HashSet <Guid>();
            }
            collectedItems.Add(collectedItemId);
            CollectorProgress[personaId] = collectedItems;

            Log.Write(LogLevel.Info, $"You've collected {collectedItems.Count} / {Collectibles.Count} items!");
            if (collectedItems.SetEquals(Collectibles))
            {
                Log.Write(LogLevel.Info, $"Congratulations, you collected all {Collectibles.Count} items!");
            }

            if (collectedItems.SetEquals(Collectibles))
            {
                collectorAgent.SendChat($"Congratulations, you collected all {Collectibles.Count} items!");
            }
            else
            {
                collectorAgent.SendChat($"You've collected {collectedItems.Count} / {Collectibles.Count} items!");
            }
        }
Example #4
0
        public List <string> GetAvailableQuests(AgentPrivate Quester)
        {
            List <string> QuestIds = new List <string>();

            HttpRequestOptions options = new HttpRequestOptions();

            options.Method = HttpRequestMethod.GET;

            Guid   PersonaId          = Quester.AgentInfo.AvatarUuid;
            string availableQuestsUrl = $"{BaseUrl}/players/{PersonaId}/characters/{CharacterId}/quest-definitions";

            Quester.SendChat($"{availableQuestsUrl}");
            var result = WaitFor(ScenePrivate.HttpClient.Request, availableQuestsUrl, options) as HttpClient.RequestData;

            if (!result.Success || result.Response.Status != 200)
            {
                return(QuestIds);
            }

            string jsonResponse = result.Response.Body;

            Quester.SendChat($"{jsonResponse}");
            StorylineResponse parsed = ((JsonSerializationData <StorylineResponse>)(WaitFor(JsonSerializer.Deserialize <StorylineResponse>, jsonResponse))).Object;

            Quester.SendChat(parsed.ToString());
            foreach (QuestData d in parsed.data)
            {
                QuestIds.Add(d.id);
            }
            return(QuestIds);
        }
Example #5
0
        private void cast(AgentPrivate ap, ObjectPrivate op)
        {
            Vector start;
            Vector end;

            getSegment(ap, op, out start, out end);

            var hitData = ScenePrivate.CastRay(start, end);

            ap.SendChat("Intersected " + hitData.Length);
            foreach (var hit in hitData)
            {
                ap.SendChat("Location: " + hit.Location);
                ap.SendChat("Normal: " + hit.Normal);
            }
        }
    void OnTrigger(CollisionData data)
    {
        AgentPrivate agent = ScenePrivate.FindAgent(data.HitComponentId.ObjectId);

        if (agent != null)
        {
            if (data.Phase == CollisionEventPhase.TriggerEnter)
            {
                agent.SendChat("Agent entered trigger volume!");
            }
            else if (data.Phase == CollisionEventPhase.TriggerExit)
            {
                agent.SendChat("Agent exited trigger volume!");
            }
        }
    }
Example #7
0
        public override void Init()
        {
            if (Grid.Equals("production"))
            {
                Grid = "";
            }
            else
            {
                Grid = $".{Grid}";
            }
            BaseUrl = $"https://profiles-api{Grid}.sansar.com";
            GiveQuest.Subscribe((InteractionData idata) =>
            {
                GiveQuest.SetPrompt(GreetingText);
                AgentPrivate Quester = ScenePrivate.FindAgent(idata.AgentId);

                List <string> CompletedQuestIds = CompleteAnyQuests(Quester);
                if (CompletedQuestIds.Count > 0)
                {
                    return;
                }

                List <string> AvailableQuestIds = GetAvailableQuests(Quester);
                if (AvailableQuestIds.Count > 0)
                {
                    string firstQuestId = AvailableQuestIds[0];
                    OfferQuest(Quester, firstQuestId);

                    return;
                }

                Quester.SendChat(GreetingText);
            });
        }
Example #8
0
        void OnDrop(HeldObjectData data)
        {
            try
            {
                unsubscribe();
                unsubscribe = null;
                AgentPrivate user = ScenePrivate.FindAgent(holdingAgent.SessionId);

                // Do this after we get the user but before trying to use the user for chat in case they have left.
                holdingAgent         = null;
                simpleData.AgentInfo = null;
                simpleData.ObjectId  = ObjectId.Invalid;

                float accuracy = 0;
                if (shotsHit > 0)
                {
                    accuracy = 100.0f * (float)shotsHit / (float)shotsFired;
                }

                if (KeepScore)
                {
                    user.SendChat($"Final score: {score}. You hit {shotsHit} out of {shotsFired}, a hit accuracy of {accuracy.ToString("00.0")}%");
                }
            }
            catch (System.Exception) { }
        }
Example #9
0
        public ScenePrivate.CreateClusterData SpawnGlobalObjective(ObjectiveEntity entity)
        {
            Vector location      = new Vector(entity.definition.p.x, entity.definition.p.y, entity.definition.p.z);
            Vector eulerRotation = new Vector(entity.definition.r.x, entity.definition.r.y, entity.definition.r.z);

            Quaternion rotation = Quaternion.FromEulerAngles(eulerRotation);

            ScenePrivate.CreateClusterData createData = null;

            createData = (ScenePrivate.CreateClusterData)WaitFor(ScenePrivate.CreateCluster, objectiveCluster, location, rotation, Vector.Zero);
            ObjectPrivate.AddInteractionData addData = (ObjectPrivate.AddInteractionData)WaitFor(createData.ClusterReference.GetObjectPrivate(0).AddInteraction, entity.prompt, true);
            addData.Interaction.Subscribe((InteractionData data) =>
            {
                AgentPrivate Quester = ScenePrivate.FindAgent(data.AgentId);
                if (Quester == null || !Quester.IsValid)
                {
                    return;
                }
                HttpRequestOptions options = new HttpRequestOptions();
                options.Method             = HttpRequestMethod.PATCH;
                options.Headers            = new Dictionary <string, string>()
                {
                    { "content-type", "application/json" }
                };
                options.Body   = $"{{\"data\": {{\"state\":\"COMPLETED\"}} }}";
                Guid PersonaId = Quester.AgentInfo.AvatarUuid;
                string completeObjectiveUrl = $"{BaseUrl}/players/{PersonaId}/storylines/{entity.storylineId}/objectives/{entity.handle}";
                Quester.SendChat(completeObjectiveUrl);

                var result = WaitFor(ScenePrivate.HttpClient.Request, completeObjectiveUrl, options) as HttpClient.RequestData;
            });

            return(createData);
        }
Example #10
0
    private void msgId(SessionId sourceId, string Text)
    {
        AgentPrivate agent = ScenePrivate.FindAgent(sourceId);

        agent.SendChat($"{Text}");
        //agent.SendChat($"{ScenePrivate.SceneInfo.ExperienceName} scene!");
    }
Example #11
0
    public void OnClick(InteractionData data)
    {
        // Find the agent that clicked.
        AgentPrivate agent = ScenePrivate.FindAgent(data.AgentId);

        // Send them a message.
        agent.SendChat("Hello! Thanks for clicking me.");
    }
        public void GetQuest(AgentPrivate Quester, string QuestId)
        {
            HttpRequestOptions options = new HttpRequestOptions();

            options.Method = HttpRequestMethod.GET;
            Guid PersonaId = Quester.AgentInfo.AvatarUuid;
            var  result    = WaitFor(ScenePrivate.HttpClient.Request, $"{BaseUrl}/players/{PersonaId}/quests/{QuestId}", options) as HttpClient.RequestData;

            if (!result.Success || result.Response.Status != 200)
            {
                return;
            }

            string jsonResponse = result.Response.Body;

            Quester.SendChat($"Quest response: {jsonResponse}");
            QuestResponse         parsed        = ((JsonSerializationData <QuestResponse>)(WaitFor(JsonSerializer.Deserialize <QuestResponse>, jsonResponse))).Object;
            ObjectiveResponseData objectiveData = null;

            if (State == "ACTIVE")
            {
                for (int i = parsed.data.objectives.Count - 1; i >= 0; i--)
                {
                    ObjectiveResponseData d = parsed.data.objectives[i];
                    if (d.state == "COMPLETED")
                    {
                        objectiveData = d;
                        break;
                    }
                }
            }
            else if (State == "COMPLETED")
            {
                foreach (ObjectiveResponseData d in parsed.data.objectives)
                {
                    if (d.state == "ACTIVE")
                    {
                        objectiveData = d;
                        break;
                    }
                }
            }
            Quester.SendChat($"objectiveData: {objectiveData}");
            UpdateObjectiveStatus(Quester, QuestId, objectiveData);
        }
Example #13
0
    void AddUser(UserData data)
    {
        // Lookup the name of the agent.
        string name = ScenePrivate.FindAgent(data.User).AgentInfo.Name;

        ScenePrivate.Chat.MessageAllUsers(string.Format("{0} Has Entered", name));
        AgentPrivate agent = ScenePrivate.FindAgent(data.User);

        agent.SendChat($"type !commands for a list");
        CharSound(data, join_sound);
    }
Example #14
0
    // send the log messages
    private void Show(AgentPrivate agent)
    {
        StringBuilder list = new StringBuilder();

        foreach (var message in Log.Messages)
        {
            list.AppendLine(message.Text);
        }
        list.AppendLine("End of messages");
        agent.SendChat(list.ToString());
    }
Example #15
0
        // Simple collision handler just records the collision with the Tracker and reports the total number of collisions.
        void OnHit(CollisionData data)
        {
            AgentPrivate agent = ScenePrivate.FindAgent(data.HitComponentId.ObjectId);

            if (agent != null)
            {
                // This will record a new collision in the Tracker script and return the new total.
                int hits = Tracker.RecordCollision(agent.AgentInfo.AvatarUuid);
                agent.SendChat($"You have hit {hits} targets.");
            }
        }
Example #16
0
    // send the help text
    private void Help(AgentPrivate agent)
    {
        StringBuilder commands = new StringBuilder();

        commands.Append("Recognized commands are ");

        foreach (string command in chatHandlers.Keys)
        {
            commands.AppendFormat("{0} ", command);
        }
        agent.SendChat(commands.ToString());
    }
        public void GetAvailableQuests(AgentPrivate Quester)
        {
            HttpRequestOptions options = new HttpRequestOptions();

            options.Method = HttpRequestMethod.GET;

            Guid   PersonaId          = Quester.AgentInfo.AvatarUuid;
            string availableQuestsUrl = $"{BaseUrl}/players/{PersonaId}/storylines/{StorylineId}/quests";

            Quester.SendChat($"{availableQuestsUrl}");
            var result = WaitFor(ScenePrivate.HttpClient.Request, availableQuestsUrl, options) as HttpClient.RequestData;

            if (!result.Success || result.Response.Status != 200)
            {
                return;
            }

            string jsonResponse = result.Response.Body;

            Quester.SendChat($"{jsonResponse}");
            JsonSerializerOptions jsonOptions = new JsonSerializerOptions
            {
                SerializeReferences = false
            };
            StorylineResponse parsed = ((JsonSerializationData <StorylineResponse>)(WaitFor(JsonSerializer.Deserialize <StorylineResponse>, jsonResponse, jsonOptions))).Object;

            if (parsed.data.Count == 0)
            {
                return;
            }
            Quester.SendChat(parsed.ToString());
            Quester.SendChat(parsed.data.ToString());
            Quester.SendChat(parsed.data[0].ToString());
            Quester.SendChat(parsed.data[0].id.ToString());

            string QuestId    = parsed.data[0].id;
            string QuestTitle = parsed.data[0].title;

            Quester.SendChat($"questID: {QuestId}");
            Quester.SendChat($"questTitle: {QuestTitle}");
            Quester.SendChat($"questObjectives: {parsed.data[0].objectiveDefinitions.ToString()}");

            GetQuest(Quester, QuestId);
        }
Example #18
0
    void NewUser(UserData userData, HttpRequestOptions options)
    {
        AgentPrivate agent = ScenePrivate.FindAgent(userData.User);

        if (agent != null)
        {
            var result = WaitFor(ScenePrivate.HttpClient.Request, "https://www.random.org/integers/", options) as HttpClient.RequestData;
            if (result.Success)
            {
                agent.SendChat("Your lucky number is " + result.Response.Body);
            }
        }
    }
Example #19
0
        public List <string> CompleteAnyQuests(AgentPrivate Quester)
        {
            List <string> QuestIds = new List <string>();

            HttpRequestOptions options = new HttpRequestOptions();

            options.Method  = HttpRequestMethod.PATCH;
            options.Headers = new Dictionary <string, string>()
            {
                { "content-type", "application/json" }
            };
            options.Body = $"{{\"data\": {{\"state\":\"COMPLETED\"}} }}";

            Guid   PersonaId         = Quester.AgentInfo.AvatarUuid;
            string completeQuestsUrl = $"{BaseUrl}/players/{PersonaId}/characters/{CharacterId}/objectives/{CompleteObjectiveHandle}";

            Quester.SendChat(completeQuestsUrl);

            var result = WaitFor(ScenePrivate.HttpClient.Request, completeQuestsUrl, options) as HttpClient.RequestData;

            if (!result.Success || result.Response.Status != 200)
            {
                return(QuestIds);
            }

            string jsonResponse = result.Response.Body;

            Quester.SendChat($"{jsonResponse}");
            StorylineResponse parsed = ((JsonSerializationData <StorylineResponse>)(WaitFor(JsonSerializer.Deserialize <StorylineResponse>, jsonResponse))).Object;

            Quester.SendChat(parsed.ToString());

            foreach (QuestData d in parsed.data)
            {
                QuestIds.Add(d.id);
            }
            return(QuestIds);
        }
    public override void Init()
    {
        ObjectPrivate.AddInteractionData addData = (ObjectPrivate.AddInteractionData)WaitFor(ObjectPrivate.AddInteraction, Title, true);

        addData.Interaction.Subscribe((InteractionData data) =>
        {
            AgentPrivate agent = ScenePrivate.FindAgent(data.AgentId);

            if (agent != null)
            {
                agent.SendChat($"Hello from {Title}!");
            }
        });
    }
Example #21
0
    void OnChat(ChatData data)
    {
        // Find the agent who wrote this chat message
        AgentPrivate owner = ScenePrivate.FindAgent(data.SourceId);

        // If the agent is the scene owner
        if ((owner != null) && (owner.AgentInfo.AvatarUuid == ScenePrivate.SceneInfo.AvatarUuid))
        {
            if (data.Message.StartsWith("/notify "))
            {
                // The message is everything after the "/notify " prefix
                var message = data.Message.Substring(8);
                if (string.IsNullOrWhiteSpace(message))
                {
                    return;
                }

                if (ModalNotifications)
                {
                    // Go through each agent in the scene
                    foreach (var agent in ScenePrivate.GetAgents())
                    {
                        // try/catch is usually a good idea when dealing with agents
                        try
                        {
                            // Display the message in a modal dialog
                            agent.Client.UI.ModalDialog.Show(message, "Ok", "");
                        }
                        catch {}
                    }
                }
                else
                {
                    // Just send a system message to chat instead
                    ScenePrivate.Chat.MessageAllUsers(message);
                }
            }
            else if (data.Message == "/help")
            {
                try
                {
                    // Let the owner know the notify chat command is available to them in the scene
                    owner.SendChat("/notify [message]");
                }
                catch {}
            }
        }
    }
Example #22
0
 void OnDrop(HeldObjectData data)
 {
     try
     {
         unsubscribe();
         unsubscribe = null;
         AgentPrivate user     = ScenePrivate.FindAgent(holdingAgent.SessionId);
         float        accuracy = 0;
         if (shotsHit > 0)
         {
             accuracy = 100.0f * (float)shotsHit / (float)shotsFired;
         }
         user.SendChat($"Final score: {score}. You hit {shotsHit} out of {shotsFired}, a hit accuracy of {accuracy.ToString("00.0")}%");
         Log.Write(GetType().Name, "Gun dropped");
     }
     catch (System.Exception) { }
 }
Example #23
0
        public void UpdateQuestStatus(AgentPrivate Quester, string QuestId)
        {
            HttpRequestOptions options = new HttpRequestOptions();

            options.Method  = HttpRequestMethod.PATCH;
            options.Headers = new Dictionary <string, string>()
            {
                { "content-type", "application/json" }
            };
            Guid PersonaId = Quester.AgentInfo.AvatarUuid;

            options.Body = $"{{\"data\": {{\"state\":\"{State}\"}} }}";
            var result = WaitFor(ScenePrivate.HttpClient.Request, $"{BaseUrl}/players/{PersonaId}/quests/{QuestId}", options) as HttpClient.RequestData;

            if (result.Success)
            {
                Quester.SendChat($"{result.Response.Body}");
            }
        }
Example #24
0
    public override void Init()
    {
        ScenePrivate.Chat.Subscribe(Chat.DefaultChannel, (ChatData data) =>
        {
            if (data.Message == "/setlowgrav")
            {
                AgentPrivate agent = ScenePrivate.FindAgent(data.SourceId);

                // If the agent is the scene owner
                if ((agent != null) && (agent.AgentInfo.AvatarUuid == ScenePrivate.SceneInfo.AvatarUuid))
                {
                    // Set the gravity to 15% of earth gravity
                    ScenePrivate.SetGravity(0.15f * 9.81f);

                    // Send a private acknowledgement message back to the user
                    agent.SendChat("You set low gravity!");
                }
            }
        });
    }
Example #25
0
    private void onShowLog(AgentPrivate agent)
    {
        string message = "There have been " + Visitors.Count + " visitors";

        message += "\nThe doors are open: " + DoorsOpen;

        message += "\nVisitor list: ";

        foreach (var visitor in Visitors)
        {
            bool isAdmin  = IsAdmin(visitor.Value.Agent);
            bool isBanned = IsBanned(visitor.Value.Agent);

            message += "\nName: " + visitor.Value.Name;

            if (isAdmin)
            {
                message += "\n - isAdmin: " + isAdmin;
            }
            else
            {
                message += "\n - isBanned " + isBanned;
            }
        }

        message += "\nAdmin list: ";
        foreach (var a in Admins)
        {
            message += "\n - " + a;
        }


        message += "\nBanned list: ";
        foreach (var b in Banned)
        {
            message += "\n - " + b;
        }

        agent.SendChat(message);
    }
Example #26
0
    //Chat Commands

    private void onShowHelp(AgentPrivate agent)
    {
        string helpMessage = "Access Control Command usage:";

        foreach (var kvp in _commandsUsage)
        {
            helpMessage += "\n" + kvp.Key + " " + kvp.Value;
        }

        try
        {
            agent.SendChat(helpMessage);
        }
        catch
        {
            // Agent left
            if (DebugLogging)
            {
                Log.Write("Possible race condition and they already logged off.");
            }
        }
    }
Example #27
0
        void OnSelect(CommandData command)
        {
            try
            {
                if (!FreeCamEnabled && command.CameraControlMode == CameraControlMode.FlyCam)
                {
                    AgentPrivate user = ScenePrivate.FindAgent(holdingAgent.SessionId);
                    user.SendChat("This device does not work in Free Cam mode, return to 1st or 3rd person views to use this device.");
                    return;
                }

                switch (command.ControlPoint)
                {
                case ControlPointType.DesktopGrab:
                    if (!MouseLookEnabled && command.MouseLookMode)
                    {
                        AgentPrivate user = ScenePrivate.FindAgent(holdingAgent.SessionId);
                        user.SendChat("This device does not work in desktop Mouse Look Mode: press Escape to enter or exit Mouse Look.");
                        return;
                    }
                    if (!FreeClickEnabled && !command.MouseLookMode)
                    {
                        AgentPrivate user = ScenePrivate.FindAgent(holdingAgent.SessionId);
                        user.SendChat("This device does not work in desktop Free Click Mode: press Escape to enter or exit Mouse Look.");
                        return;
                    }
                    break;

                case ControlPointType.LeftTool:
                case ControlPointType.RightTool:
                    if (!VREnabled)
                    {
                        AgentPrivate user = ScenePrivate.FindAgent(holdingAgent.SessionId);
                        user.SendChat("This device does not work in VR.");
                        return;
                    }

                    // Check hand after CheckReload which handles "shooting yourself to reload"
                    // If they grabbed it in desktop let them use it from whichever hand now? I guess?
                    if (heldHand != ControlPointType.DesktopGrab && command.ControlPoint != heldHand)
                    {
                        return;
                    }
                    break;

                default:
                    break;
                }

                SendToAll(EveryCommandEvent, simpleData);

                var targetAgent = ScenePrivate.FindAgent(command.TargetingComponent.ObjectId);
                if (targetAgent != null)
                {
                    SimpleData targetSimpleData = new SimpleData(this);
                    targetSimpleData.AgentInfo      = targetAgent.AgentInfo;
                    targetSimpleData.ObjectId       = targetSimpleData.AgentInfo.ObjectId;
                    targetSimpleData.SourceObjectId = simpleData.SourceObjectId;

                    SendToAll(PlayerSelectedEvent, targetSimpleData);
                }
                else
                {
                    ObjectPrivate targetObject = ScenePrivate.FindObject(command.TargetingComponent.ObjectId);
                    if (targetObject != null)
                    {
                        SimpleData targetSimpleData = new SimpleData(this);
                        targetSimpleData.AgentInfo      = null;
                        targetSimpleData.ObjectId       = targetObject.ObjectId;
                        targetSimpleData.SourceObjectId = simpleData.SourceObjectId;

                        ITarget target = targetObject.FindScripts <ITarget>("Simple.Target").FirstOrDefault();
                        if (target == null ||
                            (SameGroupRequired && target.GetGroupTag() != base.Group))
                        {
                            SendToAll(ObjectSelectedEvent, targetSimpleData);
                            return;
                        }
                        else
                        {
                            target.Hit(holdingAgent, command);
                            SendToAll(TargetSelectedEvent, targetSimpleData);
                            return;
                        }
                    }

                    SendToAll(NothingSelectedEvent, simpleData);
                }
            }
            catch (System.Exception) { } // ignore exceptions for not found agents.
        }
Example #28
0
 // Reports the last recorded memory level from an event along with current Memory data.
 private void ReportMemory(AgentPrivate agent)
 {
     agent.SendChat(String.Format("Memory info: [{0}] {1}", memoryLevel.ToString(), Memory.ToString()));
 }
Example #29
0
 // clear the log
 private void Clear(AgentPrivate agent)
 {
     Log.Clear();
     agent.SendChat("Console log cleared");
 }
Example #30
0
    void OnChat(ChatData data)
    {
        AgentPrivate agent = ScenePrivate.FindAgent(data.SourceId);

        if (!IsAccessAllowed(agent))
        {
            return;
        }

        string[] chatWords = data.Message.Split(' ');

        if (chatWords.Length < 1)
        {
            return;
        }

        string command = chatWords[0];

        if (!_commandsUsage.ContainsKey(command))
        {
            return;
        }

        if (command == "/help" || chatWords.Length < 2)
        {
            string helpMessage = "MediaChatCommand usage:";
            foreach (var kvp in _commandsUsage)
            {
                helpMessage += "\n" + kvp.Key + " " + kvp.Value;
            }

            try
            {
                agent.SendChat(helpMessage);
            }
            catch
            {
                // Agent left
            }

            return;
        }

        string medialUrl = "";

        if (command == "/media" || chatWords[1].StartsWith("http"))
        {
            medialUrl = chatWords[1];
        }
        else if (command == "/yt" || command == "/youtube")
        {
            string videoId = chatWords[1];
            medialUrl = string.Format("https://www.youtube.com/embed/{0}?autoplay=1&loop=1&playlist={0}&controls=0", videoId);

            if (chatWords.Length > 2)
            {
                int startTime = 0;
                if (int.TryParse(chatWords[2], out startTime))
                {
                    medialUrl += "&start=" + startTime;
                }
            }
        }
        else if (command == "/ytlive")
        {
            string livestreamId = chatWords[1];
            medialUrl = string.Format("https://www.youtube.com/embed/live_stream?channel={0}&autoplay=1", livestreamId);
        }
        else if (command == "/ytpl")
        {
            string playlistId = chatWords[1];
            medialUrl = string.Format("https://www.youtube.com/embed?%20listType=playlist%20&list={0}&loop=1&autoplay=1&controls=0", playlistId);
        }
        else if (command == "/twitch")
        {
            string channelName = chatWords[1];
            medialUrl = string.Format("http://player.twitch.tv/?channel={0}&quality=source&volume=1", channelName);
        }
        else if (command == "/twitchv")
        {
            string videoId = chatWords[1];
            medialUrl = string.Format("http://player.twitch.tv/?video={0}&quality=source&volume=1", videoId);
        }
        else if (command == "/vimeo")
        {
            string videoId = chatWords[1];
            medialUrl = string.Format("https://player.vimeo.com/video/{0}?autoplay=1&loop=1&autopause=0", videoId);
        }

        bool throttled = false;

        try
        {
            ScenePrivate.OverrideMediaSource(medialUrl);

            agent.SendChat("Media URL successfully updated to " + medialUrl);
            Log.Write("New media URL: " + medialUrl);
        }
        catch (ThrottleException)
        {
            throttled = true;
            Log.Write("Throttled: Unable to update media URL.");
        }
        catch
        {
            // Agent left
        }

        if (throttled)
        {
            try
            {
                agent.SendChat("Media URL update was throttled.  Try again.");
            }
            catch
            {
                // Agent left
            }
        }
    }