Full Version : Using XmlAttachment in a command
xmlspawner >>Scripting Support >>Using XmlAttachment in a command


<< Prev | Next >>

oak- 07-04-2006
I am rewriting some 1.0 code of mine and decided to use an XmlAttachment instead of modifying playermobile.cs. This is a "Grab" command that players use to "grab" loot from creatures they kill without opening the corpse. It will also dispose of the corpse to keep the littering down. Typeing "grab options" will give them a gump that allows them to set the types of loot they want to "grab" when they use the command.
My 1.0 version had bool properties in playermobile.cs but it makes sense to keep it clean and use an XmlAttachment.

1) I get this error when I try to run the server:

RunUO - [www.runuo.com] Version 2.0, Build 2373.10833
Core: Running on .NET Framework Version 2.0.50727
Core: Optimizing for 2 processors
Scripts: Compiling C# scripts...failed (1 errors, 0 warnings)
Errors:
+ custom/loottest.cs:
CS0103: Line 34: The name 'lootoptions' does not exist in the current contex
t
Scripts: One or more scripts failed to compile or no script files were found.
- Press return to exit, or R to try again.


2) The test script (loottest.cs):

CODE
using System;
using System.Collections;
using Server.Items;
using Server.Mobiles;
using Server.Misc;
using Server.Engines.XmlSpawner2;

namespace Server.Commands
{
public class testloot
{
 public static void Initialize()
 {
  CommandSystem.Register( "testloot", AccessLevel.Player, new CommandEventHandler( testloot_OnCommand ) );
 }

 [Usage( "testloot" )]
 [Description( "test the loot options xmlattachment" )]
 public static void testloot_OnCommand( CommandEventArgs e )
 {
  // does player already have a lootdata attachment?
  if (XmlAttach.FindAttachment(e.Mobile, typeof(LootData))==null)
  {
   // create lootdata attachment and add it to the player
   LootData lootoptions = new LootData();
   XmlAttach.AttachTo(e.Mobile, lootoptions);
  }
  else
  {
   // player has the attachment so set the variable
   LootData lootoptions = (LootData)XmlAttach.FindAttachment(e.Mobile, typeof(LootData));
  }

  Console.WriteLine("bool getall is:" + lootoptions.GetAll);
 }
}
}


3) The attachment script (lootdata.cs):

CODE
// LootData.cs
// Author: ssalter
// Version: .01
// Server Tested with: 2.0 build 64
// Revision Date: 7/1/2006

using System;
using Server;
using Server.Items;
using Server.Network;
using Server.Mobiles;

namespace Server.Engines.XmlSpawner2
{
   public class LootData : XmlAttachment
   {
 private bool m_getall;
 private bool m_getgold;
 private bool m_getweapons;
 private bool m_getarmor;
 private bool m_getjewelry;
 private bool m_getpotions;
 private bool m_getregs;
 private bool m_getclothes;
 private bool m_getgems;
 private bool m_getartifact;
 private bool m_gethides;
 private bool m_getfood;

       [CommandProperty( AccessLevel.GameMaster )]
       public bool GetAll { get { return m_getall; } set { m_getall  = value; } }

 [CommandProperty( AccessLevel.GameMaster )]
       public bool GetGold { get { return m_getgold; } set { m_getgold  = value; } }

 [CommandProperty( AccessLevel.GameMaster )]
       public bool GetWeapons { get { return m_getweapons; } set { m_getweapons  = value; } }
       
 [CommandProperty( AccessLevel.GameMaster )]
       public bool GetArmor { get { return m_getarmor; } set { m_getarmor  = value; } }
       
 [CommandProperty( AccessLevel.GameMaster )]
       public bool GetJewelry { get { return m_getjewelry; } set { m_getjewelry  = value; } }
       
 [CommandProperty( AccessLevel.GameMaster )]
       public bool GetPotions { get { return m_getpotions; } set { m_getpotions  = value; } }
       
 [CommandProperty( AccessLevel.GameMaster )]
       public bool GetRegs { get { return m_getregs; } set { m_getregs  = value; } }
       
 [CommandProperty( AccessLevel.GameMaster )]
       public bool GetClothes { get { return m_getclothes; } set { m_getclothes  = value; } }
       
 [CommandProperty( AccessLevel.GameMaster )]
       public bool GetGems { get { return m_getgems; } set { m_getgems  = value; } }
       
 [CommandProperty( AccessLevel.GameMaster )]
       public bool GetArtifact { get { return m_getartifact; } set { m_getartifact  = value; } }

 [CommandProperty( AccessLevel.GameMaster )]
       public bool GetHides { get { return m_gethides; } set { m_gethides  = value; } }

 [CommandProperty( AccessLevel.GameMaster )]
       public bool GetFood { get { return m_getfood; } set { m_getfood  = value; } }


       public LootData(ASerial serial) : base(serial)
       {
       }

       [Attachable]
       public LootData()
       {
       }

       [Attachable]
       public LootData(bool allflag, bool goldflag, bool weaponsflag, bool armorflag, bool jewelryflag, bool potionsflag, bool regsflag, bool clothesflag, bool gemsflag, bool artifactflag, bool hidesflag, bool foodflag)
       {
  m_getall=allflag;
  m_getgold=goldflag;
  m_getweapons=weaponsflag;
  m_getarmor=armorflag;
  m_getjewelry=jewelryflag;
  m_getpotions=potionsflag;
  m_getregs=regsflag;
  m_getclothes=clothesflag;
  m_getgems=gemsflag;
  m_getartifact=artifactflag;
  m_gethides=hidesflag;
  m_getfood=foodflag;
       }
       
 public override void Serialize( GenericWriter writer )
 {
  base.Serialize(writer);

  writer.Write( (int) 0 );
  // version 0
  writer.Write(m_getall);
  writer.Write(m_getgold);
  writer.Write(m_getweapons);
  writer.Write(m_getarmor);
  writer.Write(m_getjewelry);
  writer.Write(m_getpotions);
  writer.Write(m_getregs);
  writer.Write(m_getclothes);
  writer.Write(m_getgems);
  writer.Write(m_getartifact);
  writer.Write(m_gethides);
  writer.Write(m_getfood);
 }

 public override void Deserialize(GenericReader reader)
 {
  base.Deserialize(reader);
  // version 0
  int version = reader.ReadInt();
  m_getall = reader.ReadBool();
  m_getgold = reader.ReadBool();
  m_getweapons = reader.ReadBool();
  m_getarmor = reader.ReadBool();
  m_getjewelry = reader.ReadBool();
  m_getpotions = reader.ReadBool();
  m_getregs = reader.ReadBool();
  m_getclothes = reader.ReadBool();
  m_getgems = reader.ReadBool();
  m_getartifact = reader.ReadBool();
  m_gethides = reader.ReadBool();
  m_getfood = reader.ReadBool();
 }
   }
}


4) This probably is also a *really* inefficient way to set up the loot options. Can you suggest a more elegant method, maybe with enums or something?
But, I just need to figure out my context problem to start with.

thanks for any help,
Steve



godfood- 07-04-2006
Moved to the appropriate location smile.gif

ArteGordon- 07-05-2006
the problem with the first error is just a matter of scope.

CODE

// does player already have a lootdata attachment?
 if (XmlAttach.FindAttachment(e.Mobile, typeof(LootData))==null)
 {
  // create lootdata attachment and add it to the player
  LootData lootoptions = new LootData();
  XmlAttach.AttachTo(e.Mobile, lootoptions);
 }
 else
 {
  // player has the attachment so set the variable
  LootData lootoptions = (LootData)XmlAttach.FindAttachment(e.Mobile, typeof(LootData));
 }

 Console.WriteLine("bool getall is:" + lootoptions.GetAll);


lootoptions in only defined within the scope of the bracketed code blocks in which it is declared, and the Console.WriteLine is outside of those code blocks.

CODE
else
 {
  // player has the attachment so set the variable
  LootData lootoptions = (LootData)XmlAttach.FindAttachment(e.Mobile, typeof(LootData));
// lootoptions exists in here
 }

// but it doesnt exist out here

 Console.WriteLine("bool getall is:" + lootoptions.GetAll);



You could change it to something like

CODE

 [Usage("testloot")]
 [Description("test the loot options xmlattachment")]
 public static void testloot_OnCommand(CommandEventArgs e)
 {
  // does player already have a lootdata attachment?
  LootData lootoptions = (LootData)XmlAttach.FindAttachment(e.Mobile, typeof(LootData));

  if (lootoptions == null)
  {
   // create lootdata attachment and add it to the player
   lootoptions = new LootData();
   XmlAttach.AttachTo(e.Mobile, lootoptions);
  }

  if (lootoptions != null)
  {
   Console.WriteLine("bool getall is:" + lootoptions.GetAll);
  }
 }


notice how lootoptions is now declared outside of those code blocks and so is accessible anywhere within the method.

as for the second question, you could certainly use an enum for that if you only wanted to enabled one type of loot at a time. Your current method allows any combination which it seems is what you need, so I wouldnt change it.
You could do it with flags to be a bit more efficient with memory but the overall code would look quite similar and the savings minimal, but it would technically be more elegant.

oak- 07-06-2006
Thanks Arte. I always have problems with scope. That cleared up my problem and I was able to almost finish off the script. Using an xmlattachment instead of modifying base scripts is SO nice.

ArteGordon- 07-07-2006
yeah, the attachments are great for adding features that involve saving information that would otherwise require serialization changes to the target (which can get ugly fast).
Because the attachments handle their own serialization that all becomes transparent.

Some of the mods in the 'Members Tips' section, like custom corpse names, are good examples of those kinds of little changes that are easy to implement because you dont have to worry about serialization of the data.