I'm working on trying to solve certain issues with OWLTR 3.1 & have succeeded with some of them, but this one is getting away from me. The old OWLTR had the Bard Stand that kept the Instrument Quality & Slayers intact when removed from it (large amount of coding), 3.1 does not. It reverts them to normal or low quality & removes the slayer. I'm including the scripts for both versions to see if anyone has any useful input. I'm working on releasing a new version of OWLTR with fixes in place & some possible new stuff & am running out of brain steam..... and I think my brain STEM is starting to melt.. If at all possible, I'd like to keep the amount of coding down to a minimum for the BardStorage.
 

Attachments

  • BardStorage.cs
    1.9 KB · Views: 6
  • Bards Stand.cs
    11.3 KB · Views: 7
@Hammerhand - correct me if I'm wrong: I think you want BardStorage to retain the instrument quality and slayers of the instruments added to it, similar to how BardsStand/BardsStandGump does it but coded more efficiently. If that's the case I have a question - does your BardStorage currently retain the uses left and crafter name? Or is it just quality and slayers info that are being left out when you get an instrument out of storage? I wasn't sure if you made changes to BaseStorage that does any of that.
 
Last edited by a moderator:
It retains the uses that you would normally get with a regular instrument. ex: 1 Exceptional Harp w/ Silver Slayer & 400 uses would come out as a Harp w/ no slayer & 200 uses. Not sure if it will retain crafters name because its removing the Exceptional quality. I've only got 1 other major issue (headache) to solve along with this one & a couple minor ones I may not even bother with.
 
Do you want BardStorage to save all that information? I'm not sure how fancy or short you want your code but you could create a local (private?) Dictionary<type or BaseInstrument, CustomClass> in BardStorage and define a local (private?) CustomClass to have all the attributes you want to save from your instrument. Then serialize/deserialize the Dictionary info in BardStorage. Adding an instrument on a BardStorage would add a <type or BaseInstrument, CustomClass> to the Dictionary and delete the instrument, removing an instrument from BardStorage would remove it from the Dictionary and create an instrument of the type saved as a key with attributes from the value CustomClass. You'd still need a way to choose which instrument you want to remove tho.
 
Last edited:
Woops, I had assumed earlier that BardStorage was an Item. I think the actual saving of item information happens in MasterStorage.cs. It looks like BaseStorage and all inherited classes are used as definitions of the valid types for different types of storage containers. MasterStorage inherits from Backpack and is being used to store the item information(but maybe not the item itself? I'm still reviewing how it works) I believe a solution like the one I mentioned above can still work but needs to be applied to MasterStorage instead of BardStorage.
 
I do know the items are stored virtually, thereby cutting down on item count & weight. I've only got this and 1 other "major" issue to work out & these 2 seem to be the thickest wall to bull through so far. There are a couple minor ones as well that I know of, but those arent a big deal. I'm going to post that one in another thread if I cant make any headway on it.
 
Honestly, I've never looked that deeply into how OWLTR works before. I haven't used it on my own server so I'm unfamiliar about this MasterStorage concept in game. I'm trying to decipher the MasterStorage class because it is creating new instances of BaseStorage when it loads a save in Deserialize. What is MasterStorage used for by players? How would a new MasterStorage be created in game? Other than '[add MasterStorage' that is
 
MasterStorage is a combo Goldledger/TokenLedger/Looting system & Storage system in one backpack. Players can craft the storage deeds. The MasterStorage backpack itself can be added using [add or put in CharacterCreation to be auto added to the new players pack. Each one is "bound" to that player as soon as they use it. ie: Open it, add a storage deed by dbl clicking the deed & so on. Since everything is stored virtually, there is no extra weight & no extra item count. The player can purchase items from vendors & have the gold or tokens drawn directly from storage. They can change just what is looted & whether or not they want the body to be deleted (which gives a shard cleaning bonus) when looted, or just loot the body & leave it to decay. It can also be used without OWLTR if desired. There is also a MasterLooter stand alone system that daat99 made. Basically, its a hold a hell of a lot of stuff pack that doesnt add weight or item count that allows you to pull gold and/or token piles OR checks from it while also allowing you to craft without having to remove the resources from it. OWLTR itself is just custom Ores/Woods/Leathers & Token Resources. Once I get the 2 final "major" issues taken care & complete testing & tweaking on some new stuff for it, I'll be releasing a new version for RunUO 2.3, 2.5 & ServUO servers. The new stuff is almost entirely done, just needs a bit more tweaking & testing. I may also see about releasing the new parts for servers without OWLTR (obviously requiring a bit of reworking).
 
Thanks for the info. I'm guessing that the variable StoredItems is collection of items currently being stored in a MasterStorage. It's a Dictionary<Type, ulong> which appears to hold the type of item and the number of that item being stored. If that's right I think we can edit Serialize/Deserialize to check to see if the type is a BaseInstrument and if it is, add a bit more info. Here's the spots I'm looking at editing.
In Deserialize:
Code:
			if (version >= 6)
			{
				int count = reader.ReadInt();
				StoredItems = new Dictionary<Type, ulong>(count);
				for (int i = 0; i < count; ++i)
				{
					try
					{
						Type key = Type.GetType(reader.ReadString());
						ulong amount = reader.ReadULong();
						if (key != null)
						{
							StoredItems.Add(key, amount);

  							if (key == typeof(BaseInstrument) )
 				 			{
  								// add more info here to saves
 				 			}
						}
					}
					catch { }
				}

In Serialize:
Code:
			//version 6
			writer.Write(StoredItems.Count);
			foreach (Type key in StoredItems.Keys)
			{
				writer.Write(key.FullName);
				writer.Write(StoredItems[key]);
  				if (key == typeof(BaseInstrument) )
 				 {
  					// add more info here to saves
 				 }
			}

What do you think?
 
Right now it looks like gibberish to all 3 of my remaining sleep deprived brain cells.... (correction, 2 1/2.... one just 1/2 fizzled). Unfortunately, I'm not that confident in my coding skills for the most part & even told daat99 that last year when he made me lead dev. So a good portion of this has been an uphill battle on a slick slope for me. But I keep plugging away at it & have had some success (read LUCK). But for right now, I'm going to see about spending some quality time with my pillow before it forgets who I am. *looks for the sleepy icon, cant find it so just yawns instead*
 
I think I understand how we can get more item info to be saved and retrieved but it's going to take some rewriting of code in MasterStorage, MasterStorageStorageGump, MasterStorageUtils, and possibly in BaseStorage and all of it's child classes. It's a hellova lot a work but I do see a possible solution.

Right now it works like this: When you choose an item type to save in your MasterStorage, it calls the method TryStoreType in MasterStorage, checks to see if the type is an allowed item type, and if it is it will add one to the number of items for that type defined in the dictionary StoredItems and sends the player a MasterStorageStorageGump which gives all item information currently being stored in StoredItems. In that gump you can choose to withdraw an item type and an amount of that type, which calls the method TryExtractType in MasterStorage. In that method, it checks to see if you have stored that amount of that type and then creates instances of that item type in the static method MasterStorageUtils.

The number of items of each type is the value (as a ulong) from StoredItems and you can access it by using code like this:
Code:
StoredItems[typeof(BaseInstrument)]


What I propose is a rewriting of the dictionary StoredItems in MasterStorage and define it like this:

Code:
        private Dictionary<Type, Dictionary< string, ItemInformation>> storedItems;
        public Dictionary<Type, Dictionary< string, ItemInformation>> StoredItems { get { return storedItems; } private set { storedItems = value; } }

I'm suggesting that you make StoredItems a dictionary of of dictionaries. Whenever an item type is added to StoredItems, instead of merely adding 1 to the number of stored items of that type, you add a new Dictionary<string, ItemInformation> to StoredItems, where the string is a unique name of the item, and ItemInformation is a custom class that we define to hold extra item information for that item.

We could define a private class ItemInformation inside the class MasterStorage to be something like this:
Code:
        private class ItemInformation
        {
            private SlayerName m_Slayer, m_Slayer2;
            public SlayerName Slayer { get { return m_Slayer; } set { m_Slayer = value; } }
            public SlayerName Slayer2 { get { return m_Slayer2; } set { m_Slayer2 = value; } }

            private InstrumentQuality m_Quality;
            public InstrumentQuality Quality { get { return m_Quality; } set { m_Quality = value; } }

            private Mobile m_Crafter;
            public Mobile Crafter { get { return m_Crafter; } set { m_Crafter = value; } }

            private int m_UsesRemaining;
            public int UsesRemaining { get { return m_UsesRemaining; } set { m_UsesRemaining = value; } }

            public ItemInformation(SlayerName[] slayers, InstrumentQuality quality, Mobile crafter, int uses)
            {
                if (slayers != null)
                {
                    m_Slayer = slayers[0];
                    m_Slayer2 = slayers[1];
                }
                else
                {
                    m_Slayer = SlayerName.None;
                    m_Slayer2 = SlayerName.None;
                }
                m_Quality = quality;
                m_Crafter = crafter;
                m_UsesRemaining = uses;
            }

            public void Serialize(GenericWriter writer)
            {
                writer.Write(0); // version

                writer.Write((int)m_Slayer);
                writer.Write((int)m_Slayer2);
                writer.Write((int)m_Quality);
                writer.Write(m_Crafter);
                writer.Write((int)m_UsesRemaining);
            }

            public void Deserialize(GenericReader reader)
            {
                int version = reader.ReadInt();

                m_Slayer = (SlayerName)reader.ReadInt();
                m_Slayer2 = (SlayerName)reader.ReadInt();
                m_Quality = (InstrumentQuality)reader.ReadInt();
                m_Crafter = reader.ReadMobile();
                m_UsesRemaining = reader.ReadInt();
            }
        }

So, adding a new item to StoredItems could be done like this:

Code:
                if (StoredItems[typeof(BaseInstrument)] == null)
                    StoredItems[typeof(BaseInstrument)] = new Dictionary<string,ItemInformation>();  // we need to make sure value StoredItems[type] is not null

                // a BaseInstrument instrument = The item we want to add

                StoredItems[typeof(BaseInstrument)].Add( instrument.Name, new ItemInformation( new SlayerName[] {instrument.Slayer, instrument.Slayer2}, instrument.Quality, instrument.Crafter, instrument.UsesRemaining ) );

Also, we would have to change the code to serialize/deserialize to serialize the new information added and edit every line where StoredItems is accessed to get item information to display to the player. There might be an easier fix than this but I don't see an option yet.

*edit* Oh, and we may want to save the number of items of that item type in ItemInformation too. Also, if two unique items have the same name then we'll have to come up with another way to differentiate between unique items instead of only the name.
 
Last edited:
I'm willing to help more, I was just brainstorming a way to inject more item information into serialize/deserialize. That's the first step of many, though I'm unsure of what else it may take to get working completely right. If this solution works, it would allow the saving of extra information from any item type stored in MasterStorage, not just BaseInstrument.

@Hammerhand, your ability level will skyrocket if you understand the Dictionary class well. @Talow posted an awesome guide to using Lists and Dictionaries over at PlayUO: http://www.playuo.org/emu/index.php?threads/generic-collections-list-dictionary.946/ - I'm willing to help explain more too if it helps.

My free time for coding is limited for the next couple of weeks. I hope you don't mind waiting for me to tinker around with this stuff.
 
I know I can't offer much help but I am looking forward to seeing this work with ServIO. How's it coming?
 
Back