Today I got a new issue and I am unsure what is causing it. I have gone over anything i can think I have done that may have caused it but still not fixed it. I am having trouble understanding what the crash report is saying. I crashed the server in debug mode and here is the log.

Code:
Server Crash Report
===================

JustUO Version 2.0, Build 5.0
Operating System: Microsoft Windows NT 6.2.9200.0
.NET Framework: 4.0.30319.34014
Time: 6/25/2015 12:49:58 AM
Mobiles: 2083
Items: 98992
Exception:
System.NullReferenceException: Object reference not set to an instance of an object.
   at Server.Announce.OnDeath(PlayerDeathEventArgs args) in c:\Users\Forest\Desktop\Ultima Online\Scripts\Custom\Items\Obituary Board.cs:line 46
   at Server.PlayerDeathEventHandler.Invoke(PlayerDeathEventArgs e)
   at Server.Mobile.OnDeath(Container c) in c:\Users\Forest\Desktop\trunk\Server\Mobile.cs:line 4270
   at Server.Mobiles.PlayerMobile.OnDeath(Container c) in c:\Users\Forest\Desktop\Ultima Online\Scripts\Mobiles\PlayerMobile.cs:line 2769
   at Server.Mobile.Kill() in c:\Users\Forest\Desktop\trunk\Server\Mobile.cs:line 4206
   at Server.Commands.Generic.KillCommand.Execute(CommandEventArgs e, Object obj) in c:\Users\Forest\Desktop\Ultima Online\Scripts\Commands\Generic\Commands\Commands.cs:line 879
   at Server.Commands.Generic.BaseCommandImplementor.RunCommand(Mobile from, Object obj, BaseCommand command, String[] args) in c:\Users\Forest\Desktop\Ultima Online\Scripts\Commands\Generic\Implementors\BaseCommandImplementor.cs:line 314
   at Server.Commands.Generic.SingleCommandImplementor.OnTarget(Mobile from, Object targeted, Object state) in c:\Users\Forest\Desktop\Ultima Online\Scripts\Commands\Generic\Implementors\SingleCommandImplementor.cs:line 91
   at Server.Targeting.Target.Invoke(Mobile from, Object targeted) in c:\Users\Forest\Desktop\trunk\Server\Targeting\Target.cs:line 277
   at Server.Network.PacketHandlers.TargetResponse(NetState state, PacketReader pvSrc) in c:\Users\Forest\Desktop\trunk\Server\Network\PacketHandlers.cs:line 1301
   at Server.Network.MessagePump.HandleReceive(NetState ns) in c:\Users\Forest\Desktop\trunk\Server\Network\MessagePump.cs:line 313
   at Server.Network.MessagePump.Slice() in c:\Users\Forest\Desktop\trunk\Server\Network\MessagePump.cs:line 131
   at Server.Core.Main(String[] args) in c:\Users\Forest\Desktop\trunk\Server\Main.cs:line 639

Clients:
- Count: 2
+ 127.0.0.1: (account = fc478987h) (mobile = 0x1 'Exale')
+ 127.0.0.1: (account = asdf) (mobile = 0x1C0 'asdf')

Any help better understanding what may be going on would be awesome.
 
So I notice it refrences the obituary script. This is a script I have had working fine for months so I am unsure as to the issue. The only thing I have done since that also announces on death is the xmlpoints system. I am unsure the conflict. Here is the obituary board if it helps.

EDIT: Maybe because they both use the
EventSink.PlayerDeath += new PlayerDeathEventHandler(OnDeath); ????
Is there a way to combne them? Though Like I said, these systems have worked together for a while and didnt seem to have any issues so I'm really confused.
 

Attachments

  • Obituary Board.cs
    5.3 KB · Views: 1
Code:
at Server.Announce.OnDeath(PlayerDeathEventArgs args)in c:\Users\Forest\Desktop\Ultima Online\Scripts\Custom\Items\Obituary Board.cs:line 46

This tells you what line, line 46

Line 46:
Code:
					deathToll = deathToll.ToString();

deathToll is null, so because of this it cannot call ToString. I'm guessing deaths.txt is empty. you don't need to "ToString()" this value, its already a string. ReadLine is assigning deathToll as a string if you look at ReadLine's return type. You would then need to do a null check before using it.
Something like
Code:
				if ( File.Exists( path ))
				{
					StreamReader r = new StreamReader( path, System.Text.Encoding.Default, false );
					deathToll = r.ReadLine();
					r.Close();

					int iDeath = 0;

					if(deathToll != null)
					{
						string[] result = deathToll.Split(new string[] { "<BR>------------------------------<BR>" }, StringSplitOptions.RemoveEmptyEntries);
						foreach (string str in result)
						{
							if ( iDeath < 99 ){deaths = deaths + "<BR>------------------------------<BR>" + str;}
							iDeath = iDeath + 1;
						}
					}
				}

I do question a lot of this code, there are a lot of weird things in this script, but im hoping thats for debugging purposes. Writing out all this txt, reading it to get a number is very very inefficient and going to kill your server eventually.

We are here to help, so maybe you can explain what you are trying to accomplish by with writing it out, and maybe we can give you a better idea on how to accomplish that ;)
 
Interesting enough, that is one thing I did recently. We are preparing to launch the server soon so I went ahead and cleared the file so it didn't show all the beta testing deaths. That did however give me an idea. I went ahead and deleted the entire file instead of just emptying it. That way it didn't exist at all until the script went to create it. That seemed to of fixed the issue completely. So then I placed the empty file back in the directory and made the change you suggested and that also worked perfectly. I can't thank you enough. I keep pretty detailed revisions of every change I do to the server and had been racking my brain against all the changes I made to see what caused it. This didn't even occur to me.

The script itself is an old script I found on RunUO from years ago. I updated it and got it to work, and even added some extra features like the commands (also posted it here in the forums as a release) but the script itself I didn't write. Basically all it does is keep track of who died in a txt file so players could either type [obituaries or check a board to see the last 100 people who died.

I love this community. It never ceases to amaze me the little bugs that can makes hours and hours just fly by when your learning this stuff. lol
 
The script itself is an old script I found on RunUO from years ago. I updated it and got it to work, and even added some extra features like the commands (also posted it here in the forums as a release) but the script itself I didn't write. Basically all it does is keep track of who died in a txt file so players could either type [obituaries or check a board to see the last 100 people who died.

I love this community. It never ceases to amaze me the little bugs that can makes hours and hours just fly by when your learning this stuff. lol
You should just serialize the data, rather than write a text file that you read and parse all the time. Instead you should save and load with the server, and keep the last 100 in memory. File access is a taxing process, and since RunUO is single threaded, this can cause things to slow down when you have multiple players. Opening on closing that file each time a player clicks the stone, or someone dies is really bad :(
 
Oh damn. Good points. I'm not very well acquainted with serializing and stuff yet. Something I will have to look into this weekend and try figuring out. I'm still in the "i look at 30 scripts for refrence and take way longer than i need to to finally get proper code to work together" phase. lol
 
Here's something to get you started. I added a Persistence item that stores the deaths. Its a single instance item, it will add itself if it doesnt exist, and wont add itself again unless its deleted. It shouldn't be easy to deleted since its not an actual item that exists in the world in a visible state (it works the same way faction persistence works). This allows you to not have to create your own persistence model for things like a global list of kills :)

Here's the unchecked, uncompiled, probably buggy code, but it should get you started (I just modified the script you attached above in VS Code)
Code:
using System;
using System.Collections;
using Server.Items;
using Server.ContextMenus;
using Server.Misc;
using Server.Network;
using System.Text;
using Server;
using Server.Commands;
using Server.Commands.Generic;
using System.IO;
using Server.Mobiles;
using System.Threading;
using Server.Gumps;
using Server.Accounting;

namespace Server
{
    public class ObituaryPersistance : Item
    {		
        private static ObituaryPersistance m_Instance;
					
        public static ObituaryPersistance Instance
        {
            get
            {
                return m_Instance;
            }
        }
		
        public static void Initialize()
		{
			    EventSink.WorldLoad += OnLoad
        }
		
		public static void OnLoad(WorldLoadEventArgs args)
		{
			if(ObituaryPersistance.Instance == null)
			{
				new ObituaryPersistance();
			}
		}
		
		private List<string> m_Deaths = new List<string>();
		
		public ObituaryPersistance()
            : base(1)
        {
            this.Movable = false;

            if (m_Instance == null || m_Instance.Deleted)
                m_Instance = this;
            else
                base.Delete();
        }

        public ObituaryPersistance(Serial serial)
            : base(serial)
        {
            m_Instance = this;
        }
		
		public string[] GetOrderedDeaths()
		{
			string[] deaths = new string[m_Deaths.Count];
			
			for(int i = 0; i < m_Deaths.Count; i++)
			{
				deaths[i] = m_Deaths[i];	
			}
			
			// Ordered in reverse so the most recent deaths are first
			Array.Reverse(deaths);
			
			return deaths;
		}
		
		public void AddDeath(string death)
		{
			m_Deaths.Add(death);
			
			if(m_Deaths.Count > 100)
			{
				//Removes the oldest.
				m_Deaths.RemoveAt(0);
			}
		}

        public override void Serialize(GenericWriter writer)
        {
            base.Serialize(writer);

            writer.Write((int)0); // version
			
			writer.Write((int)m_Deaths.Count);
			
			for(int i = 0; i < m_Deaths.Count; i++)
			{
				writer.WriteString(m_Deaths[i]);
			}
		}
		
        public override void Deserialize(GenericReader reader)
        {
            base.Deserialize(reader);

            int version = reader.ReadInt();

            switch ( version )
            {
                case 0:
                    {
						int count = reader.ReadInt32();
						
						for(int i = 0; i < count; i++)
						{
							m_Deaths.Add(reader.ReadString());	
						}
						
						break;
					}
			}
		}
		
        public override void Delete()
        {
        }
	}
	
    public class Announce
    {
        public static void Initialize()
        {
            EventSink.PlayerDeath += OnDeath;
		}
		
        public static void OnDeath(PlayerDeathEventArgs args)
        {
            Mobile m = args.Mobile;

            if (args.Mobile.AccessLevel < AccessLevel.GameMaster)
            {
				Mobile killer = m.LastKiller;

				if ( killer == null )
				{
					ObituaryPersistance.AddDeath("{0} was killed!", m.Name);
				}
				else if (killer is PlayerMobile)
				{
					ObituaryPersistance.AddDeath("{0} was slain by {1}!", m.Name, killer.Name);
				}
				else if (killer == m)
				{
					
					ObituaryPersistance.AddDeath("{0} killed themself!", m.Name);
				}
				else 
				{
					ObituaryPersistance.AddDeath("{0} was killed by {1}!", m.Name, killer.Name);
				}
            }
        }
    }
}

namespace Server.Items
{
	[Flipable(0x1E5E, 0x1E5F)]
	public class DeathBoard : Item
	{
		[Constructable]
		public DeathBoard( ) : base( 0x1E5E )
		{
			Weight = 1.0;
			Name = "Obituaries";
			//Hue = 0xB85;
			Hue = 0;
			Movable = false;
		}

		public override void GetProperties( ObjectPropertyList list )
		{
			base.GetProperties( list );
			list.Add( "A Listing Of Recent Deaths" );
		}

		public class KillsGump : Gump
		{
			
			public static void Initialize()
			{
				CommandSystem.Register( "Obituaries", AccessLevel.Player, new CommandEventHandler( DeathBoard_OnCommand ) );
			}

			private static void DeathBoard_OnCommand( CommandEventArgs e ) 
			{ 
				e.Mobile.SendGump( new KillsGump( e.Mobile ) ); 
			}
			
			public KillsGump( Mobile from ): base( 100, 100 )
			{
				this.Closable=true;
				this.Disposable=true;
				this.Dragable=true;
				this.Resizable=false;
				this.AddPage(0);
				this.AddImage(0, 0, 9380);
				this.AddImage(114, 0, 9381);
				this.AddImage(372, 0, 9382);
				this.AddImage(171, 0, 9381);
				this.AddImage(0, 140, 9386);
				this.AddImage(114, 140, 9387);
				this.AddImage(171, 140, 9387);
				this.AddImage(372, 140, 9388);
				this.AddImage(34, 36, 30501);
				this.AddImage(228, 0, 9381);
				this.AddImage(284, 0, 9381);
				this.AddImage(319, 0, 9381);
				this.AddImage(227, 140, 9387);
				this.AddImage(278, 140, 9387);
				this.AddImage(322, 140, 9387);
				//this.AddButton(35, 221, 2151, 2152, 1, GumpButtonType.Reply, 0);
				//this.AddLabel(72, 225, 0, @"REFRESH");

				string[] deaths = ObituaryPersistence.GetOrderedDeaths();
								
				if ( deaths.Length > 0 )
				{
					StringBuilder builder = new StringBuilder();
					
					foreach(string death in ObituaryPersistence.GetDeaths())
					{
						builder.Append(death);
						builder.Append("<BR>------------------------------<BR>");
					}
					
					this.AddHtml( 162, 40, 294, 201, string.Concat(@"<basefont color=black>", builder.ToString(), "</basefont>"), (bool)false, (bool)true);
				}
				else
				{
					this.AddHtml( 162, 40, 294, 201, @"<basefont color=black>There are no recent deaths.</basefont>", (bool)false, (bool)true);
				}
			}

			/*public override void OnResponse(Server.Network.NetState sender, RelayInfo info)
			{
				Mobile from = sender.Mobile;

				switch ( info.ButtonID )
				{
					case 0: { break; }
					case 1:
					{
						from.CloseGump( typeof( KillsGump ) );
						from.SendGump( new KillsGump( from ) );
						break;
					} 
				}
			}*/
		}

		public override void OnDoubleClick( Mobile e )
		{
			e.SendGump( new KillsGump( e ) );
		}

		public DeathBoard(Serial serial) : base(serial)
		{
		}

		public override void Serialize(GenericWriter writer)
		{
			base.Serialize(writer);
			writer.Write((int) 0);
		}

		public override void Deserialize(GenericReader reader)
		{
			base.Deserialize(reader);
			int version = reader.ReadInt();
		}
	}
}
 
Back