• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Discusion about save load system

Status
Not open for further replies.
Level 17
Joined
Nov 13, 2006
Messages
1,814
i opened this for continue the discussion :p

Sadly, your save/load code appears to be longer than necessary.

It doesn't appear that you are converting everything into 1 massive number, so it grows larger there. Furthermore, you are always saving all of the information rather than saving partial sets.


You are using BigInt right?

Rather than using many integers, you can form them all up into 1 giant one.

http://www.hiveworkshop.com/forums/jass-resources-412/system-bigint-188973/

My save/load stuff in Spells section runs off of BigInt.


Furthermore, you are still saving the actual data incorrectly... not only the wrong format, but the wrong way... you don't know how to save a partial set do you?

I'm going to make this very simple for you to understand

2 and 1 are smaller than 2 and 1 as separate integers

2*2+1 = 5

2 and 1 make up 21

5 < 21


If you have more than one integer making up your save/load code, your code is longer than it needs to be. The more integers you have in your code, the longer it will be.

21 has 2x more digits than 5 does. This is the reason why most save/load systems, including AceHart's, have codes around 2x longer than the ones produced using BigInt. BigInt makes it possible to store all values into 1 integer. Without BigInt, you have to store them using multiple integers or you have to write your own BigInt library.


As for partial sets, we'll deal with that after you get your stuff saved correctly.

edit
If you want, you can convert my vjass BigInt 2 lib to JASS : ). It'll help decrease the size of your save/load code ;p. The alpha is in a thread in this forum =D.


The idea of saving partial sets is this.

If you have your standard wc3 inventory that can save items and the hero is only holding 4 items, don't save the extra 2 empty slots... that's just a waste of space... only save 5 slots, 4 for the items and 1 for holding 0 so that you know when to stop. An empty inventory should only save 1 slot.

After this, you also use advanced catalogs to lower the amount of space that each item takes up. If a hero can only equip warrior items, there is no need to use a catalog that includes wizard items... only use the warrior catalog. If a slot can only hold axes, there is no need to include armor when saving that slot.. just save axes. If you can only hold 1 sword and you just saved a sword, there is no need to include the sword catalog with future saves... remove it from your general catalog.

Someone was just asking me how he should do this and I gave him an algorithm that'll allow him to save partial inventories + remove catalogs as the necessary items are being saved.

If you are saving abilities and the hero is level 1, you shouldn't be saving level 40 abilities... that's just silly >.<. If you look at my SaveAbilities function, it saves abilities smartly... just like my SaveItemCharges function saves item charges smartly.. it doesn't save an item charge if the item can't have a charge >.<. It doesn't save a max item charge of 99 if the item can only hold 3 charges like other resources do... no, it saves the exact and precise item charge.

This is the exact thing I was talking about... most map makers are just sloppy about what they do. Later when you talk to them and say that there is a better way, most people will just say, "nah, you're wrong, what you say is just totally impossible." What's funny is that they will continue to say this even after you prove that you are right... they'll just go, that can't be working, even when it saves and loads properly.


For save/load, you always want to use BigInt and Catalog >.<. For saving values like gold, you want to use CompressInt.


There are many, many save/load resources out there (most of which that I have written) that help make good save/load easier, yet people will try to do it on their own and then wonder why their code is so much longer than it would have been if they had just taken the easy route and used the already made resources... yes, even map specific save/load systems lose to the general resources. Why? Because the general resources are used to create map specific save/load systems >: O. Notice that my resource isn't called The Ultimate Super Badass Save/Load System of the world >.<. It's called Save/Load With Snippets, meaning that it will teach you how to make your own save/load system using a collection of snippets >.<. Not using the snippets to make your own save/load system and instead writing your own snippets that don't even work as well is just silly. But then again, we have many GUI users who go, "I just want a save/load system." You can't have a general all purpose save/load system because not every map needs the same things or saves in the same way... they don't seem to understand that >.<.

You can still save partial custom inventories... it sounds like slots in your inventory equip specific items, so you can take advantage of that.

You don't understand what I am saying..

Can you wear a staff weapon in a slot that holds armor pieces?
Can you wear gloves in the helm slot?



shadow, I suggest running through the later parts of this tutorial (lesson 23+)

http://www.hiveworkshop.com/forums/...ading-interactive-saving-loading-tutorial.w3m

It'll teach you a lot. I am updating it right now to discuss more advanced topics like advanced catalogs, but it should get you started ; ).

You have the number 30. You want to save the number 60. The second number has a max of 99. This means that you use base 100 to store it as base 100 can store up to 99.

Hex: FF*10 = FF0 = 255*16 = 4080
Binary: 1*10 = 110 = 1*2 = 2
Decimal: 12*10 = 120

Notice how each number ends with a 0, a full digit to store a number. You can have a number with every digit in a different base.

So, 30*100 = 3000 + 99 = 3099


That is what I meant by storing gold in base 1,000,001.

edit
Ok, this appears to be the catalog you want minus the levels

http://www.hiveworkshop.com/forums/...talog-level-slot-group-version-filter-212758/

If a warrior can equip something like a wand (no groups), then you can get away with this minus the level
http://www.hiveworkshop.com/forums/submissions-414/item-catalog-level-group-version-filter-212750/

^)^

not even close

Also, your ranges are bad... I assume that this -> 1000000 is for gold... first, compress the ranges necessary... furthermore, for items, the ranges are variable if you do it right, so you can't really get a precise number. Furthermore, with items, you save partial sets. I can give you a worst case scenario, but again, you would have to list out all of your items with restrictions and what slots they can go into and what heroes can use them.
And btw, with partial inventories, I have turned a 6 character save/load code into a 1 character save/load code np. With full inventories and good catalogs, I have turned a 6 char save/load code into a 2 char save/load code. The full demonstrations of this are in the latest unreleased interactive save/load tutorial.


i use 1 array for all equiable item, this why my ranges maybe weird, becauese item_type[50-1200] the equipable item list :p

i understanded that u save items to 1 table (in ur example 1st key=itemtypeid, key2=item array index), but example when inside the table have more item than what u can code to 1 character, if i understand well then if u got less item u can make catalog easier because combination is smaller, so with few char u can make set, but what about when have alot item so array index is higher than 100?

i dont made restrictions because u set mannually the attributes (str/agi/int) and dont need class restriction if have stat restriction, so example lv100 staff need 4*int, 1*str, lv100 axe need 4*str and 1*agi and lv100 one handed sword need 3*str and 2*agi so dont have class restriction because u can stat warrior with mage stat/attributes (even he will be useless but have option for that, also i made restat thing so u can redistribute ur attributes) so this is why dont have class restriction in few word
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Then make catalogs based off of stat restrictions. It'd be a bit more complicated than level restrictions as it'd be a 3D tree, meaning you'd need a Kd-Tree or an Octal Tree, but you can do it ; ). Actually, you could just do 3 layers of range filters and that'd work perfectly. Take my LevelFilter and then make 2 more, link them up, and pass stats into them rather than levels and boom, you got your catalog ^_^.

Now, after you build the catalog, there is still more... the next step is saving the data the correct way >: ), which is almost as complicated as building the catalog ;D, fuahaha.

Now, are you going to make this catalog working off of the Level + Version Filter Catalog I got sitting in JASS submissions, or shall I? This may sound challenging, but it's actually very simple ;o. Rather than loading up catalogs in the Level Filter, you load up additional trees... so .get some more ;o. I already did all the hard stuff ^)^.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Here is how easy it is to use this stuff when you are using vjass.. This is Catalog Lesson 1 from my unreleased Interactive Save/Load Tutorial update.

JASS:
/*****************************************************************************************
*   
*                   -       Requires vJASS Knowledge        -
*
*   An advanced catalog is like a catalog that is made up of many, many smaller catalogs.
*   These catalogs are put together and outputted to the savers/loaders for use.
*
*   Before being able to create these advanced catalogs, learning how to create simple catalogs
*   is necessary.
*
*   A simple catalog is a struct that implements the Catalog module. These structs must extend
*   an array.
*   
*****************************************************************************************/

    struct MyCatalog extends array
        implement Catalog
    endstruct
    
/*****************************************************************************************
*   
*   These catalogs are quite easy to populate.
*
*   The add method is used to add new things to the catalog.
*
*****************************************************************************************/

    static method add takes integer value returns nothing
    
/*****************************************************************************************
*   
*   Population is normally done within an onInit method in the struct.
*   
*****************************************************************************************/

    struct MyCatalog extends array
        implement Catalog
        
        private static method onInit takes nothing returns nothing
            //populate the catalog
            call add('Hpal')                //paladin
            call add('Hmkg')                //mountain king
        endmethod
    endstruct
    
/*****************************************************************************************
*   
*   Recall that save/load requires the maximum a value can be in order to store that value.
*   This maximum can be retrieved with count.
*   
*****************************************************************************************/

    readonly static integer count

/*****************************************************************************************
*   
*   Count returns how many values are in the catalog.
*   
*****************************************************************************************/

    struct MyCatalog extends array
        implement Catalog
        
        private static method onInit takes nothing returns nothing
            //populate the catalog
            call add('Hpal')                //paladin
            call add('Hmkg')                //mountain king
            
            call ClearTextMessages()
            call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"Count: "+I2S(count))
        endmethod
    endstruct

/*****************************************************************************************
*   
*   Recall that catalogs are used to substitute small values like 1 and 2 for larger values
*   like 'hpea'.
*
*   The id propery is used to retrieve the catalog id of a value within the catalog.
*   
*****************************************************************************************/

    readonly integer id

/*****************************************************************************************
*   
*   With this property, values within the catalog can be saved.
*   
*****************************************************************************************/

    struct MyCatalog extends array
        implement Catalog
        
        private static method onInit takes nothing returns nothing
            //populate the catalog
            call add('Hpal')                //paladin
            call add('Hmkg')                //mountain king
        endmethod
    endstruct
    
    struct SaveLoad extends array
        private static constant string BASE = "0123456789" //base used for save/load
        private static Base baset
    
        private static method save takes nothing returns boolean
            local BigInt saveCode
            
            local integer catalogValue
            local integer catalogId
            
            local string ascii
            
            call ClearTextMessages()
            
            set catalogValue = 'Hpal'
            set catalogId = MyCatalog['Hpal'].id            //convert 'Hpal' to catalog id -> 1
            
            set saveCode = BigInt.create()                  //create the integer
            call saveCode.add(catalogId)                    //add catalog id to integer
            
            set ascii = A2S(catalogValue)                   //convert 'Hpal' to ascii string -> "Hpal"
            call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"Saved: '"+ascii+"'")
            
            //display integer -> 1
            set saveCode.base = baset
            call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"Code: "+saveCode.toString())
            
            call saveCode.destroy()                         //destroy integer
            
            return false
        endmethod
        
        private static method onInit takes nothing returns nothing
            local trigger t = CreateTrigger()
            
            call TriggerAddCondition(t, Condition(function thistype.save))
            call TriggerRegisterPlayerChatEvent(t, Player(0), "-save", true)
            
            set t = null
            
            set baset = Base["0123456789"]
        endmethod
    endstruct

/*****************************************************************************************
*   
*   Catalog ids are converted back into values with the raw property.
*   
*****************************************************************************************/

    readonly integer raw

/*****************************************************************************************
*   
*   The raw property allows the loader to get the original values back.
*   
*****************************************************************************************/

    struct MyCatalog extends array
        implement Catalog
        
        private static method onInit takes nothing returns nothing
            //populate the catalog
            call add('Hpal')                //paladin
            call add('Hmkg')                //mountain king
        endmethod
    endstruct
    
    struct SaveLoad extends array
        private static constant string BASE = "0123456789" //base used for save/load
        private static Base baset
    
        private static method save takes nothing returns boolean
            local BigInt saveCode
            
            local integer catalogValue
            local integer catalogId
            
            local string ascii
            
            call ClearTextMessages()
            
            set catalogValue = 'Hpal'
            set catalogId = MyCatalog['Hpal'].id            //convert 'Hpal' to catalog id -> 1
            
            set saveCode = BigInt.create()                  //create the integer
            call saveCode.add(catalogId)                    //add catalog id to integer
            
            set ascii = A2S(catalogValue)                   //convert 'Hpal' to ascii string -> "Hpal"
            call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"Saved: '"+ascii+"'")
            
            //display integer -> 1
            set saveCode.base = baset
            call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"Code: "+saveCode.toString())
            
            call saveCode.destroy()                         //destroy integer
            
            return false
        endmethod
        
        private static method load takes nothing returns boolean
            local string saveStr
            local BigInt saveCode
            
            local integer catalogId
            local integer catalogValue
            
            local string ascii
            
            call ClearTextMessages()
            
            set saveStr = GetEventPlayerChatString()                //retrieve player input
            set saveStr = RemoveString(saveStr, "-load ", 1, 0)     //remove "-load " from string
            
            set saveCode = BigInt.convertString(saveStr, base)      //convert string to integer
            
            set catalogId = saveCode.toInt()                        //convert integer to JASS integer
            set catalogValue = MyCatalog[catalogId].raw             //catalog id -> 'Hpal'
            
            set ascii = A2S(catalogValue)                           //convert base 10 number to ascii string -> "Hpal"
            
            //outputs "Hpal"
            call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"Loaded: '"+ascii+"'")
            
            call saveCode.destroy()                                 //destroy integer
            
            return false
        endmethod
        
        private static method onInit takes nothing returns nothing
            local trigger t = CreateTrigger()
            
            call TriggerAddCondition(t, Condition(function thistype.save))
            call TriggerRegisterPlayerChatEvent(t, Player(0), "-save", true)
            
            set t = CreateTrigger()
            call TriggerAddCondition(t, Condition(function thistype.load))
            call TriggerRegisterPlayerChatEvent(t, Player(0), "-load ", false)
            
            set t = null
            
            set baset = Base["0123456789"]
        endmethod
    endstruct
    
/****************************************************************************************/
 
Level 17
Joined
Nov 13, 2006
Messages
1,814
i belive easy to use but i got enough bad experience when i tryed use vjass (enough often happened when map dont was saved well and map was corrupted even i reinstalled few times) so until i dont make terrains i try avoid the vjass

about ur jass string what contain only number (0-9), the reason was for make useable for bigint function?


Code:
          local BigInt saveCode

here u use bigint function like variable type?

A2S just make from number a string or its make a character from ascii code?

sorry for lame questions :D
 
Status
Not open for further replies.
Top