Hi,
I'm running RunUO 2.4 with mods.

I've added emailing players if one of their houses becomes greatly worn to remind them to refresh.

That works OK, but if a house gets to that decay level and the email is sent, then the next time I restart the server it throws a null exception on world load and asks to delete the house. The only way to recover is to turn decay off, restart the server, save, then turn decay back on and restart again. If I take out the line that checks for old decay state != new decay state then everything is fine but obviously nobody gets an email.

So to clarify: if I restart the server before the email is triggered, all is well if I restart the server.

To test this I have my local test server set with 3 day house decay and I email on Slightly worn so that I get the email in about 35 minutes from refreshing.

I am probably being incredibly stupid as usual, but I can't see what the problem is. As the result is calculated, nothing new should need to be serialized/deserialized so what is it complaining about as being null, especially when I think I am testing everything for null?

Here is the server load error:

Code:
World: Loading...An error was encountered while loading a saved object
 - Type: Server.Multis.TwoStoryVilla
 - Serial: 0x40000534
Delete the object? (y/n)
After pressing return an exception will be thrown and the server will terminate.

Error:
System.Exception: Load failed (items=True, mobiles=False, guilds=False, type=Server.Multis.TwoStoryVilla, serial=0x40000534) ---> System.NullReferenceException: Object reference not set to an instance of an object.
  at Server.Multis.BaseHouse.WarnOwner(BaseHouse house, DecayLevel level)
  at Server.Multis.BaseHouse.get_DecayLevel()
  at Server.Multis.BaseHouse.CheckDecay()
  at Server.Multis.BaseHouse.Deserialize(GenericReader reader)
  at Server.Multis.TwoStoryVilla.Deserialize(GenericReader reader)
  at Server.World.Load()
  --- End of inner exception stack trace ---
  at Server.World.Load()
  at Server.Core.Main(String[] args)
This exception is fatal, press return to exit

And here is the test, at the end of this code segment:
Code:
 [CommandProperty( AccessLevel.GameMaster )]
 public virtual DecayLevel DecayLevel
 {
 get
 {
 DecayLevel result;

 if ( !CanDecay )
 {
 if ( DynamicDecay.Enabled )
 ResetDynamicDecay();

 m_LastRefreshed = DateTime.UtcNow;
 result = DecayLevel.Ageless;
 }
 else if ( DynamicDecay.Enabled )
 {
 DecayLevel stage = m_CurrentStage;

 if ( stage == DecayLevel.Ageless || ( DynamicDecay.Decays( stage ) && m_NextDecayStage <= DateTime.UtcNow ) )
 SetDynamicDecay( ++stage );

 if ( stage == DecayLevel.Collapsed && ( HasRentedVendors || VendorInventories.Count > 0 ) )
 result = DecayLevel.DemolitionPending;
 else
 result = stage;
 }
 else
 {
 result = GetOldDecayLevel();
 }

 if ( result != m_LastDecayLevel )
 {
 m_LastDecayLevel = result;

 if ( m_Sign != null && !m_Sign.GettingProperties )
 {
 m_Sign.InvalidateProperties();
 
 }

 if ( result != null && this != null && result == DecayLevel.Slightly )
 WarnOwner ( this, result );
 }

 return result;
 }
 }

And the WarnOwner method:

Code:
 public virtual void WarnOwner( BaseHouse house, DecayLevel level )
 {
 if ( level != null && level == DecayLevel.Slightly )
 {
 // if email exists send email
 string emailhouseName, emailhouseOwner, emailhouseLocation, emailhouseMap, emailSubject, recipients, emailFrom, emailMessage;

 emailhouseName = ( house.Sign.GetName() );

 Mobile emailowner = house.Owner ;
 Account acct = emailowner.Account as Account;
 
 if ( emailowner == null )
 emailhouseOwner = "nobody";
 else
 emailhouseOwner = emailowner.Name;

 if (house.Map == Map.Felucca )
 emailhouseMap = "Felucca";
 else if (house.Map == Map.Trammel )
 emailhouseMap = "Trammel";
 else if (house.Map == Map.Ilshenar )
 emailhouseMap = "Ilshanar";
 else if (house.Map == Map.Malas )
 emailhouseMap = "Malas";
 else if (house.Map == Map.Tokuno )
 emailhouseMap = "Tokuno";
 else if (house.Map == Map.TerMur )
 emailhouseMap = "Ter Mur";
 else
 emailhouseMap = "Internal";

 emailhouseLocation = house.X.ToString() + "," + house.Y.ToString() + " in " + emailhouseMap; ;
 emailSubject = "UO Utopia house decay warning";
 emailMessage = "This is a note to alert you to the fact that your house ";
 emailMessage = emailMessage + emailhouseName + " owned by " + emailhouseOwner + " at location: " + emailhouseLocation;
 emailMessage = emailMessage + " is now marked as Greatly Worn.";
 recipients = Email.CrashAddresses;

 if ( acct.Email != null )
 recipients = acct.Email + "," + recipients;

 SendEmail( emailSubject, emailMessage, recipients ); 
 return;
 }
 }

Thank you

David
 
Back