I’m working on features for my sciencesim/opensim-based population genetics simulation project that require a web interface so I have been developing a website on Utah State University’s domain using Drupal. The basic information describing my opensim region modules, cellular automata, population genetics/fern lifecycle, and data visualization projects has been transferred and reorganized.  I have started a new blog on that site as well, so I will no longer be posting information here. I’ll leave this site available for the history it contains. Please check out the new website at:

http://fernseed.usu.edu

 

This is my first foray into web development, so comments and criticism are welcome. Thanks for reading and I hope to see you over there!

Picture 1

Many people are finding this blog by searching for information on opensim region modules, and the posts about my Twitter Visit Logger and Cellular Automata modules seem to get a lot of views. So I have decided to make the code for those available (in a format a little easier to implement than just posting it here). I have started public repositories for both modules on GitHub. That means anyone can download the source, compile it, load it on their own opensim installations and experiment with it. My hope is that if others improve on it they will push those improvements back to the repository.  If nothing else, this puts a couple more region module examples out there for people trying to learn to customize their opensim regions.
Anyway, the code is available at the links below. The instructions are a bit sparse for now – mainly in the form of comments within the code – but as I find time I’ll try to improve the documentation. Enjoy!

GitHub repo for twitter-based Visit-Logger

GitHub repo for Conway’s Game of Life on the surface of a toroid

GitHub mainpage for links to information on using git and GitHub

Here is a quick and dirty opensim region module that uses the Twitterizer library to access the Twitter API.
For each visitor that enters a region, the module posts a Twitter update with the visitor’s name.  Each visitor is only recorded once in a one hour period to avoid the spam that could result from avatars logging in repeatedly or flying back and forth across borders.
Visitors can also post comments or suggestions to the Twitter page by chatting on channel 15.

Here is a quick opensim region module that lets you do a couple basic tasks using the Twitterizer library to access the Twitter API.

For each visitor that enters a region, the module posts a Twitter update with the visitor’s name.  Each visitor is only recorded once in a one hour period to avoid the spam that could result from avatars logging in repeatedly or flying back and forth across borders.

Visitors can also post comments or suggestions to the Twitter page by chatting on channel 15.  This could be misused for griefing so there is a limit on the number of comments that can be posted in a 24 hour period.

I could see this module being useful in an orientation or help-desk type region where the owners would like to be able to personally greet as many visitors as possible without having to keep a viewer logged in all the time.  A dedicated twitter account would be set up for the region, and by following that twitter account a region owner (or a team) could keep tabs on what is happening in the region and log in when visitors arrive.  It could also be useful for a special-interest region like mine.  I have a very small target audience, so  the visitors are few and far between but most are likely people I want to meet.

I could have done this with emails instead of a twitter feed (I wrote that module too) but I like the openness of this system.  Visitors are free to view the comments left by others – perhaps even stimulating an ongoing dialogue.  And it seems a little less “big brother” to make visitor tracking public.  Though if you prefer, you can change the settings of the twitter feed to only allow specific people to view. (Added 9/19/09) It probably isn’t something you’d want to follow, but you can see the twitter page for my region here.

Anyway, here is the code if anyone wants to use/modify it.  You’ll need to download the Twitterizer.framework.dll and place it in your opensim/bin folder.  Comments and suggestions are appreciated (here on the blog or on channel 15 of Fern Seed Info in ScienceSim!).

//An opensim region module to send a twitter "tweet" update announcing each visitor.
//Visitors can also record comments on channel 15.
//Aaron M. Duffy
//aduffy70@gmail.com
//September 2009

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Timers;

using log4net;
using Nini.Config;
using OpenMetaverse;

using OpenSim.Framework;
using OpenSim.Region.Framework;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using Twitterizer.Framework;

namespace VisitLoggerModule {
    public class VisitLoggerModule : IRegionModule {
		Twitter twit = new Twitter("YourTwitterID", "yourpassword");
        string twitteraddress = "twitter.com/YourTwitterFeedURL";
        Dictionary<string, DateTime> recentvisits = new Dictionary<string, DateTime>();
        int blocktime = 3600; //If an avatar re-visits within this many seconds, do not tweet
        int maxcomments = 20; //If we get more comments than this in 24 hours it is probably griefing
        int commentstoday = 0;
        Timer mytimer = new Timer();
        private Scene m_scene;

        #region IRegionModule interface

        public void Initialise(Scene scene, IConfigSource config) {
            m_scene = scene;
        }

        public void PostInitialise() {
            m_scene.EventManager.OnMakeRootAgent += new EventManager.OnMakeRootAgentDelegate(OnVisit);
            m_scene.EventManager.OnChatFromClient += new EventManager.ChatFromClientEvent(OnChat);
            mytimer.Elapsed += new ElapsedEventHandler(TimerEvent);
            mytimer.Interval = 86400000;
            mytimer.Start();
        }

        public void Close(){
        }

        public string Name{
            get { return "VisitLoggerModule"; }
        }

        public bool IsSharedModule {
            get { return false; }
        }

        #endregion

        void OnVisit(ScenePresence presence) {
            string visitorname = presence.Firstname + "_" + presence.Lastname;
            if (recentvisits.ContainsKey(visitorname)) {
                if (DateTime.Now.Subtract(recentvisits[visitorname]).TotalSeconds > blocktime) {
                    twit.Status.Update("Welcome " + presence.Firstname + " " + presence.Lastname + "!");
                    recentvisits[visitorname] = DateTime.Now;
                }
                else {
                    recentvisits[visitorname] = DateTime.Now;
                }
            }
            else {
                twit.Status.Update("Welcome " + presence.Firstname + " " + presence.Lastname + "!");
                recentvisits.Add(visitorname, DateTime.Now);
            }
        }

        void OnChat(Object sender, OSChatMessage chat) {
            if (chat.Channel != 15)
                return;
            else if (commentstoday <= maxcomments) {
                string sendername = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(chat.SenderUUID).UserProfile.Name;
                //There must be a better way to get the avatar's name, but chat.Name returns null...
                string firstinitial = sendername.Substring(0,1);
                string lastinitial = sendername.Split(' ')[1].Substring(0,1);
                twit.Status.Update(firstinitial + lastinitial + ":" + chat.Message);
                IDialogModule dialogmod = m_scene.RequestModuleInterface<IDialogModule>();
                if (dialogmod != null) {
                    dialogmod.SendGeneralAlert("Thanks for the feedback!  View comments at " + twitteraddress);
                    commentstoday++;
                }
            }
            else  {
                IDialogModule dialogmod = m_scene.RequestModuleInterface<IDialogModule>();
                if (dialogmod != null)
                    dialogmod.SendGeneralAlert("Too many comments today.  Message not sent.");
            }
        }

        void TimerEvent(object source, ElapsedEventArgs e) {
            commentstoday = 0;
        }
    }
}