Afk Bot Plugin

This afk bot, maintains last seen and idle status of citizens. It persists these statuses using database persistance through the AwManaged SDK application storage db provider. Also it uses a simple Command Line interpreter from the console services offered by the SDK. Mainly it shows how compact code can be for a managed bot plugin.

/* **********************************************************************************
 *
 * Copyright (c) TCPX. All rights reserved.
 *
 * This source code is subject to terms and conditions of the Microsoft Public
 * License (Ms-PL). A copy of the license can be found in the license.txt file
 * included in this distribution.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * **********************************************************************************/
using System;
using System.Collections.Generic;
using AwManaged;
using AwManaged.ConsoleServices;
using AwManaged.Core.Reflection.Attributes;
using AwManaged.EventHandling.BotEngine;
using AwManaged.Scene;
using Db4objects.Db4o;
using Db4objects.Db4o.Linq;
using StandardBotPluginLibrary.GreeterBot;
using System.Linq;

namespace StandardBotPluginLibrary.AfkBot
{
    /// <summary>
    /// Simple greeter bot. To demonstrate The Local Plugin Provider
    /// Part of the Standard Bot Plugin Library.
    /// </summary>
    [PluginInfo("afkbot", "This is a simple afk bot.")] /* plugin information for the plugin provider */
    public class AfkBotPlugin : BotLocalPlugin
    {
        /// <summary>
        /// A dedicated isntance to the bot engine's application storage database.
        /// </summary>
        private readonly IObjectContainer _db;
        /// <summary>
        /// An in memory status list which keeps track of avatar idle status.
        /// </summary>
        private readonly List<AvatarStatus> _statusList;
        /// <summary>
        /// Ensures that the avatar status is available both on disk, and in memory.
        /// </summary>
        /// <param name="avatar">The avatar.</param>
        /// <returns></returns>
        private AvatarStatus EnsureStatus(Avatar avatar)
        {
            AvatarStatus status;
            var query = from AvatarStatus p in _db where p.Avatar.Citizen == avatar.Citizen select p;
            if (query.Count() == 0)
                status = new AvatarStatus(avatar);
            else
            {
                status = query.Single();
                status.Avatar = avatar;  // update old avatar status, citname might have been changed.
            }
            status.LastSeen = DateTime.Now;
            _db.Store(status);
            _db.Commit();
            _statusList.Add(status);
            return status;
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="GreeterBotPlugin"/> class.
        /// </summary>
        /// <param name="bot">The bot.</param>
        public AfkBotPlugin(BotEngine bot): base(bot)
        {
            _statusList = new List<AvatarStatus>();
            // Get a dedicated client/server connection to the storage server.
            _db = bot.Storage.Clone();
            // reset status for all avatars.
            foreach (var avatar in bot.SceneNodes.Avatars)
                EnsureStatus(avatar);
            // The bot needs to attach to three events for operation.
            bot.AvatarEventAdd += AvatarEventAdd;
            bot.AvatarEventRemove += AvatarEventRemove;
            bot.ChatEvent += ChatEvent;
        }

        public override void PluginInitialized()
        {
            Bot.Say("afkbot initialized.");
        }

        /// <summary>
        /// Handles a chat event.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The e.</param>
        void ChatEvent(BotEngine sender, EventChatArgs e)
        {
            var query = from AvatarStatus p in _statusList where p.Avatar.Citizen == e.Avatar.Citizen select p;
            var status = query.Single();
            status.LastSeen = DateTime.Now;
            var cmd = new CommandLine(e.Message); /* use a simple command line interpreter */
            switch (cmd.Command)
            {
                case "!seen":
                    if (cmd.Arguments.Count == 0)
                        sender.Whisper(e.Avatar,"Invalid, usage is in the form of !seen <citizen name>.");
                    else
                    {
                        var avatar = from AvatarStatus p in _statusList
                                    where p.Avatar.Name.ToLower() == cmd.Arguments[0].Value.Value.ToLower() select p;
                        if (avatar.Count() == 1)
                        {
                            sender.Whisper(e.Avatar, string.Format("Citizen {0} is here.", cmd.Arguments[0].Value.Value));
                            return;
                        }
                        var offline = from AvatarStatus p in _db where p.Avatar.Name.ToLower() == cmd.Arguments[0].Value.Value.ToLower() select p;
                        if (offline.Count() == 0)
                        {
                            sender.Whisper(e.Avatar, string.Format("Citizen {0} was never seen by me.", cmd.Arguments[0].Value.Value));
                            return;
                        }
                        var seen = offline.Single();
                        sender.Whisper(e.Avatar, string.Format("Citizen {0} was last seen on {1}", cmd.Arguments[0].Value.Value,seen.LastSeen.ToLongDateString()));
                        return;
                    }
                    break;
                case "!idle" :
                    var message = string.Empty;
                    foreach (var avatar in _statusList)
                        if (avatar.IsIdle)
                            message += " " + avatar.Avatar.Name;
                    if (message == string.Empty)
                        sender.Whisper(e.Avatar,"No one is idle.");
                    else
                        sender.Whisper(e.Avatar, "Idle citizens:" + message);
                    break;
            }
        }

        /// <summary>
        /// Fired when an avatar leaves the world
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The e.</param>
        void AvatarEventRemove(BotEngine sender, EventAvatarRemoveArgs e)
        {
            var query = from AvatarStatus p in _statusList where p.Avatar.Citizen == e.Avatar.Citizen select p;
            var status = query.Single();
            status.LastSeen = DateTime.Now;
            _db.Store(status);
            _db.Commit();
            _statusList.Remove(status);
        }

        /// <summary>
        /// Fired when an avatar enters the world.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The e.</param>
        void AvatarEventAdd(BotEngine sender, EventAvatarAddArgs e)
        {
            EnsureStatus(e.Avatar);
        }

        /// <summary>
        /// Called by the plugin services manager.
        /// Releases unmanaged and - optionally - managed resources.
        /// You should clean up your references to Bot here, such as events.
        /// And flush your game state data.
        /// </summary>
        public override void Dispose()
        {
            Bot.Say("afkbot terminating.");
            // store the last seen value before shutting down the bot completely.
            foreach (var status in _statusList)
            {
                status.LastSeen = DateTime.Now;
                _db.Store(status);
            }
            _db.Commit();
            _db.Dispose(); /* cleanup db resources and close connection */

            Bot.AvatarEventAdd -= AvatarEventAdd;
            Bot.AvatarEventRemove -= AvatarEventRemove;
            Bot.ChatEvent -= ChatEvent;
        }
    }
}
using System;
using AwManaged.Scene;

namespace StandardBotPluginLibrary.AfkBot
{
    public class AvatarStatus
    {
        private Avatar _avatar;
        private DateTime _lastSeen;

        public AvatarStatus(Avatar avatar)
        {
            _avatar = avatar;
            _lastSeen = DateTime.Now;
        }

        public bool IsIdle
        { 
            get
            {
                return DateTime.Now.Subtract(_lastSeen).TotalMinutes > 10;
            }
        }

        public Avatar Avatar
        {
            get { return _avatar; }
            set { _avatar = value;}
        }

        public DateTime LastSeen
        {
            get { return _lastSeen; }
            set { _lastSeen = value; }
        }
    }
}

Last edited Jan 13, 2010 at 7:57 AM by cube3, version 5

Comments

No comments yet.