Since RoR, I've been having regular crashes when logging out of the game & when entering/exiting session play. I almost never get crashes at any other time (logging in, loading screens etc.). I'm fairly sure this plugin is the source of the problem, as I disabled it for a few days and I haven't crashed once. It doesn't do anything special, just writing character name & equipped gear to a file. Prior to RoR it worked perfectly.

I'm not particularly familiar with LUA, so I don't really have a clue what the issue is. Hopefully one of the LUA wizards around here will be able to spot it.

Code:
import "Turbine";
import "Turbine.Gameplay";
import "Turbine.UI";


-- AddCallback function (Lib)


function AddCallback(object, event, callback)
    if (object[event] == nil) then
        object[event] = callback;
    else
        if (type(object[event]) == "table") then
            table.insert(object[event], callback);
        else
            object[event] = {object[event], callback};
        end
    end
    return callback;
end


-- Timer function (Lib)


Timer = class( Turbine.UI.Control ); -- base the class on a generic control so that we can use an Update handler
function Timer:Constructor()
    Turbine.UI.Control.Constructor( self ); -- generic control constructor
    self.EndTime=Turbine.Engine.GetGameTime(); -- default the EndTime value
    self.Repeat=false; -- default the Repeat value
    -- this is the function which users will call on an instance of the class to set a timer
    self.SetTime=function(sender, numSeconds, setRepeat)
        numSeconds=tonumber(numSeconds); -- force the "type" of the numSeconds parameter
        if numSeconds==nil or numSeconds<=0 then
            numSeconds=0; -- force the numSeconds to a 0 or positive value (negative time is a baaadd thing, Marty...)
        end
        self.EndTime=Turbine.Engine.GetGameTime()+numSeconds; -- set the end time based on current time + the provided number of seconds
        -- note, numSeconds can contain a fractions of a second
        self.Repeat=false; -- default repeat
        self.NumSeconds=numSeconds; -- store the number of seconds internally for use with Repeat
        if setRepeat~=nil and setRepeat~=false then
            -- any non-false value will trigger a repeat
            self.Repeat=true;
        end
        self:SetWantsUpdates(true); -- we set updates to true AFTER we have established the end time and repeat settings (lua uses a single thread so this is kind of overkill, but again, a good practice)
    end
    -- this is the Update handler that will handle checking the time and firing the event(s) if needed
    self.Update=function()
        if self.EndTime~=nil and Turbine.Engine.GetGameTime()>=self.EndTime then
            -- we have a valid timer and it the end time has been reached
            self:SetWantsUpdates(false); -- turn off timer to avoid firing again while we are processing (not likely but it's a good practice)
            -- fire whatever event you are trying to trigger
            if self.TimeReached~=nil then
                -- we account for both a single "function" as well as a possible table of functions
                if type(self.TimeReached)=="function" then
                    self.TimeReached();
                elseif type(self.TimeReached)=="table"  then
                    for k,v in pairs(self.TimeReached) do
                        if type(v)=="function" then
                            v();
                        end
                    end
                end
            end
            -- last but not least, if we are set to repeat then we need to calculate the next time to fire and reenable the Update handler
            if self.Repeat then
                self.EndTime=Turbine.Engine.GetGameTime()+self.NumSeconds;
                self:SetWantsUpdates(true);
            end
        end
    end
end


-- Update Gear - Called at init & when a gear change is detected


updateGear = function()
    savedata["Shoulders"] = equip:GetItem(Turbine.Gameplay.Equipment.Shoulder):GetName();
    savedata["Helm"] = equip:GetItem(Turbine.Gameplay.Equipment.Head):GetName();
    savedata["Chest"] = equip:GetItem(Turbine.Gameplay.Equipment.Chest):GetName();
    savedata["Gloves"] = equip:GetItem(Turbine.Gameplay.Equipment.Gloves):GetName();
    savedata["Legs"] = equip:GetItem(Turbine.Gameplay.Equipment.Legs):GetName();
    savedata["Boots"] = equip:GetItem(Turbine.Gameplay.Equipment.Boots):GetName();
    savedata["MainWeapon"] = equip:GetItem(Turbine.Gameplay.Equipment.PrimaryWeapon):GetName();
    savedata["ClassItem"] = equip:GetItem(Turbine.Gameplay.Equipment.Class):GetName();


    Turbine.PluginData.Save(Turbine.DataScope.Account, "A", savedata, printUpdate);
end


-- Callback function for PluginData.Save - Prints a line to the shell


printUpdate = function()
    Turbine.Shell.WriteLine("Equipment Updated");
end


-- EqInit Class - Load-time check that the equipment object has been initialised


EqInit = class(Turbine.UI.Control);
function EqInit:Constructor()
    Turbine.UI.Control.Constructor(self);
    self:SetWantsUpdates(true);
    self.Update = function()
        player1 = Turbine.Gameplay.LocalPlayer:GetInstance();
        if player1:GetEquipment():GetItem(Turbine.Gameplay.Equipment.Shoulder)~=nil and player1:GetEquipment():GetItem(Turbine.Gameplay.Equipment.Head)~=nil and player1:GetEquipment():GetItem(Turbine.Gameplay.Equipment.Chest)~=nil and player1:GetEquipment():GetItem(Turbine.Gameplay.Equipment.Gloves)~=nil and player1:GetEquipment():GetItem(Turbine.Gameplay.Equipment.Legs)~=nil and player1:GetEquipment():GetItem(Turbine.Gameplay.Equipment.Boots)~=nil and player1:GetEquipment():GetItem(Turbine.Gameplay.Equipment.PrimaryWeapon)~=nil and player1:GetEquipment():GetItem(Turbine.Gameplay.Equipment.Class)~=nil then
            self:SetWantsUpdates(false);
            self.nonNil();
        end
    end
end


-- Instance of EqInit created


testNonNil = EqInit();


-- checkGearChange called every 30s


checkGearChange = function()
    if savedata["Shoulders"] ~= equip:GetItem(Turbine.Gameplay.Equipment.Shoulder):GetName() then
        updateGear();
    elseif savedata["Helm"] ~= equip:GetItem(Turbine.Gameplay.Equipment.Head):GetName() then
        updateGear();
    elseif savedata["Chest"] ~= equip:GetItem(Turbine.Gameplay.Equipment.Chest):GetName() then
        updateGear();
    elseif savedata["Gloves"] ~= equip:GetItem(Turbine.Gameplay.Equipment.Gloves):GetName() then
        updateGear();
    elseif savedata["Legs"] ~= equip:GetItem(Turbine.Gameplay.Equipment.Legs):GetName() then
        updateGear();
    elseif savedata["Boots"] ~= equip:GetItem(Turbine.Gameplay.Equipment.Boots):GetName() then
        updateGear();
    elseif savedata["MainWeapon"] ~= equip:GetItem(Turbine.Gameplay.Equipment.PrimaryWeapon):GetName() then
        updateGear();
    elseif savedata["ClassItem"] ~= equip:GetItem(Turbine.Gameplay.Equipment.Class):GetName() then
        updateGear();
    end
end


-- Create timer to check periodically for gear changes


gearChecker = Timer();


-- "Main" function - When the Equipment object is initialised (non-nil), we save initial data then start the change-checking cycle


myInit = function()
    player = Turbine.Gameplay.LocalPlayer:GetInstance();


    name = player:GetName();
    equip = player:GetEquipment();
    savedata = {};    
    savedata["Name"] = name;
    updateGear();
    Turbine.Shell.WriteLine("CurrentChar Initialised");


    AddCallback(gearChecker, "TimeReached", checkGearChange);


    gearChecker:SetTime(30, true);    
end


-- Callback created, so when the equipment object is created the plugin is initiated


AddCallback(testNonNil, "nonNil", myInit);