• 🏆 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!

Automated Chat-based save/load (for RPs)

Status
Not open for further replies.
Level 12
Joined
Jun 12, 2010
Messages
413
This is a JASS/GUI Save/Load System. The plan is to have as much GUI as possible and include a guide to editing the JASS for GUI users.

This is a system I was trying to come up with to allow saving and loading of bases in RP games such as Titan Land and RoTRP (basically, any sandbox in which resources don't matter)

Unfortunately, no physics professor is going to teach you about packets and netcoding, and studying already takes up a decent chunk of my time. So instead of trying to learn the existing save/load systems, I decided to take a day off and make my own, simpler version and finally learn at least some JASS.

Warcraft 3 doesn't allow you to force messages from player, so a fairly simple python script is required.

What it does:
  1. Saves the UnitTypeId,X,Y,current life and facing angle of a unit in a file for every unit in a unit group (default is all units owned by triggering player, configurable to structures only in-game, but you can change it to whatever you want in the editor)
  2. Using an external program (written in Python), loads the units into the game by writing chat messages. Command to request the Python program to load is issued by the player in-game

YouTube Demonstration: *trigger warning: No editing, recommend watching at least at 1.5x**No annotations yet, so you probably won't be able to read anything, just see things happen*

Google Drive link for Python script source code (if you want to run the script, but don't think executables and strangers go well together or if you want to check out some lazy coding)

The current version of the system has been tested in a LAN environment and worked without causing any kind of desync. I also discovered that simulating keystrokes is not possible on wc3 windows opened by UnrealLoader (nor was it possible to create macros with my G510 keyboard, so it's likely an issue with the UnrealLoader)

TODO:
-Allow a larger number of save-names and maybe save player name along with save-name
-Stop being lazy and clear leaks <- Should be done, please tell me if you find any
-General optimization
-Make a better guide and reduce the number of required steps

DLs: Demo map and zipfile containing executable SaveNLoad.exe, required files and the python script (source code)

TL;DR: Has been tested on multiple LAN games with 2-4 players (same PC). Not the best system out there, but I decided to post it anyway since it may give someone a new idea on mixing external languages and wc3, and it's JASS/GUI

Guide:
  1. Create a folder named DataManager in the wc3 directory
  2. Extract zipfile to DataManager folder
  3. Open the folder SaveNLoad
  4. Open the folder Settings
  5. Edit Warcraft-Path.txt to match your wc3 installation path (change any \ to / and don't forget / at the end)
  6. Go back to folder SaveNLoad and run SaveNLoad.exe
  7. Open the map as normal
  8. Commands: -save xxxx to save|-request xxxx to load (please don't do anything until you see -load end)
Update: Added a few text files, will delete them on next update
 

Attachments

  • save stuff.w3x
    30.2 KB · Views: 129
  • SaveNLoad.zip
    6.7 MB · Views: 165
  • [Change-log].txt
    225 bytes · Views: 119
  • [Read-me].txt
    371 bytes · Views: 126
  • SaveNLoad.txt
    6.3 KB · Views: 145
Last edited:
Level 12
Joined
Jun 12, 2010
Messages
413
JASS:
function SaveToFile takes string password, integer numbr, unit target returns nothing   
    local real cur_life = 0
    local real posx
    local real posy
    set posx = GetUnitX(target)
    set posy = GetUnitY(target)
    call PreloadGenStart()
    call PreloadGenClear()
    call Preload( I2S(GetUnitTypeId(target)) + "," + R2S(posx)+","+ R2S(posy) + "," + R2S(cur_life) + "," + R2S(GetUnitFacing(target)) + "," )
    call PreloadGenEnd("DataManager\\" + password + "\\" + I2S(numbr) + ".txt")
    set target = null
endfunction
function CutToComma takes string str returns integer
    local string comma = "lol"
    local integer looping = 0
    loop
        exitwhen comma == ","
        set comma = SubString(str,looping,looping+1)
        set looping = looping + 1
    endloop
    return looping-1
endfunction
function LoadUnit takes string chat_str, player un_owner returns nothing
    local integer str_index
    local integer un_type
    local real un_posx
    local real un_posy
    local real un_life
    local real un_fangle
    local integer len_str = StringLength(chat_str)
    //call DisplayTextToForce( GetPlayersAll(), chat_str )
   
    set str_index = CutToComma(chat_str)
    set un_type = S2I(SubString(chat_str,0,str_index))
    set chat_str = SubString(chat_str,str_index+1,len_str+1)
    set len_str = StringLength(chat_str)
    //call DisplayTextToForce( GetPlayersAll(), I2S(un_type) )
    set str_index = CutToComma(chat_str)
    set un_posx = S2R(SubString(chat_str,0,str_index)) + udg_load_center[GetPlayerId(un_owner)+1]
    set chat_str = SubString(chat_str,str_index+1,len_str+1)
    set len_str = StringLength(chat_str)
    //call DisplayTextToForce( GetPlayersAll(), R2S(un_posx) )
    set str_index = CutToComma(chat_str)
    set un_posy = S2R(SubString(chat_str,0,str_index)) + udg_load_center[GetPlayerId(un_owner)+1+12]
    set chat_str = SubString(chat_str,str_index+1,len_str+1)
    set len_str = StringLength(chat_str)
    //call DisplayTextToForce( GetPlayersAll(), R2S(un_posy) )
    set str_index = CutToComma(chat_str)
    set un_life = S2R(SubString(chat_str,0,str_index))
    set chat_str = SubString(chat_str,str_index+1,len_str+1)
    set len_str = StringLength(chat_str)
    //call DisplayTextToForce( GetPlayersAll(), R2S(un_life) )
    set str_index = CutToComma(chat_str)
    set un_fangle = S2R(SubString(chat_str,0,str_index))
    set chat_str = SubString(chat_str,str_index+1,len_str+1)
    set len_str = StringLength(chat_str)
    //call DisplayTextToForce( GetPlayersAll(), R2S(un_fangle) )

//If the desired position is outside of the playable map area, abort the opertaion
    if  un_posx > GetRectMaxX(GetPlayableMapRect()) then
        return
    endif
    if un_posx < GetRectMinX(GetPlayableMapRect()) then
        return
    endif
    if un_posy > GetRectMaxY(GetPlayableMapRect()) then
        return
    endif
    if un_posy < GetRectMinY(GetPlayableMapRect()) then
        return
    endif
//If the desired position is within playable bounds, continue
  
    call CreateUnit (un_owner, un_type, un_posx, un_posy, un_fangle )

endfunction
function SaveSize takes string password,integer size returns nothing
    call PreloadGenStart()
    call PreloadGenClear()
    call Preload(I2S(size))
    call PreloadGenEnd("DataManager\\" + password + "\\" + "size.txt")
endfunction
function LoadRequest takes string password returns nothing
    call PreloadGenStart()
    call PreloadGenClear()
    call Preload(password)
    call PreloadGenEnd("DataManager\\load.txt")
endfunction

  • SnL Setup
    • Events
      • Time - Elapsed game time is 0.00 seconds
    • Conditions
    • Actions
      • Set save_load_strings[0] = Finished Saving
      • Game - Display to Player Group - Neutral Passive the text: save_load_strings[0]
      • Trigger - Add to LoadSetLimit <gen> the event (Player - GAME_MASTER types a chat message containing -load limit as A substring)
      • Set SAVE_FORBIDDEN_TYPES[0] = Gryphon Rider
  • SaveCall
    • Events
      • Player - Player 1 (Red) types a chat message containing -save as A substring
      • Player - Player 2 (Blue) types a chat message containing -save as A substring
      • Player - Player 3 (Teal) types a chat message containing -save as A substring
      • Player - Player 4 (Purple) types a chat message containing -save as A substring
      • Player - Player 5 (Yellow) types a chat message containing -save as A substring
      • Player - Player 6 (Orange) types a chat message containing -save as A substring
      • Player - Player 7 (Green) types a chat message containing -save as A substring
      • Player - Player 8 (Pink) types a chat message containing -save as A substring
      • Player - Player 9 (Gray) types a chat message containing -save as A substring
      • Player - Player 10 (Light Blue) types a chat message containing -save as A substring
      • Player - Player 11 (Dark Green) types a chat message containing -save as A substring
      • Player - Player 12 (Brown) types a chat message containing -save as A substring
    • Conditions
    • Actions
      • Custom script: local integer udg_temp_integer
      • Set temp_integer = (Player number of (Triggering player))
      • Set save_password[(Player number of (Triggering player))] = (Substring((Entered chat string), 7, 11))
      • Set save_grp[temp_integer] = (Units owned by (Triggering player))
      • Set save_unit_nmbr[temp_integer] = 0
      • Set save_load_boolean[temp_integer] = True
      • Unit Group - Pick every unit in save_grp[temp_integer] and do (Actions)
        • Loop - Actions
          • Custom script: local integer udg_temp_integer
          • For each (Integer temp_integer) from 0 to 1, do (Actions)
            • Loop - Actions
              • Custom script: if GetUnitTypeId(GetEnumUnit()) == udg_SAVE_FORBIDDEN_TYPES[udg_temp_integer] then
              • Unit Group - Remove (Picked unit) from save_grp[(Player number of (Triggering player))]
              • Set temp_integer = 2
              • Custom script: endif
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • save_load_boolean[((Player number of (Triggering player)) + 24)] Equal to True
                • Then - Actions
                  • If (((Picked unit) is A structure) Equal to False) then do (Unit Group - Remove (Picked unit) from save_grp[(Player number of (Triggering player))]) else do (Do nothing)
                • Else - Actions
      • Game - Display to (All players) the text: (String(temp_integer))
  • SaveLoop
    • Events
      • Time - Every 0.50 seconds of game time
    • Conditions
    • Actions
      • Custom script: local integer udg_temp_integer
      • Custom script: local unit udg_temp_unit
      • For each (Integer temp_integer) from 1 to 12, do (Actions)
        • Loop - Actions
          • Custom script: if udg_save_load_boolean[udg_temp_integer] == true then
          • Set temp_unit = (Random unit from save_grp[temp_integer])
          • Set save_unit_nmbr[temp_integer] = (save_unit_nmbr[temp_integer] + 1)
          • Unit Group - Remove temp_unit from save_grp[temp_integer]
          • Custom script: if CountUnitsInGroup(udg_save_grp[udg_temp_integer]) == 0 then
          • Set save_load_boolean[temp_integer] = False
          • Game - Display to (Player group((Player(temp_integer)))) the text: save_load_strings[0]
          • Custom script: endif
          • Custom script: if ( GetLocalPlayer() == Player(udg_temp_integer - 1) ) then
          • Custom script: call SaveToFile(udg_save_password[udg_temp_integer], udg_save_unit_nmbr[udg_temp_integer], udg_temp_unit)
          • Custom script: if udg_save_load_boolean[udg_temp_integer] == false then
          • Custom script: call SaveSize(udg_save_password[udg_temp_integer], udg_save_unit_nmbr[udg_temp_integer])
          • Custom script: endif
          • Custom script: endif
          • Custom script: endif
      • Custom script: set udg_temp_unit = null
      • Skip remaining actions

  • LoadRequest
    • Events
      • Player - Player 1 (Red) types a chat message containing -request as A substring
      • Player - Player 2 (Blue) types a chat message containing -request as A substring
      • Player - Player 3 (Teal) types a chat message containing -request as A substring
      • Player - Player 4 (Purple) types a chat message containing -request as A substring
      • Player - Player 5 (Yellow) types a chat message containing -request as A substring
      • Player - Player 6 (Orange) types a chat message containing -request as A substring
      • Player - Player 7 (Green) types a chat message containing -request as A substring
      • Player - Player 8 (Pink) types a chat message containing -request as A substring
      • Player - Player 9 (Gray) types a chat message containing -request as A substring
      • Player - Player 10 (Light Blue) types a chat message containing -request as A substring
      • Player - Player 11 (Dark Green) types a chat message containing -request as A substring
      • Player - Player 12 (Brown) types a chat message containing -request as A substring
    • Conditions
    • Actions
      • Custom script: if GetLocalPlayer() == GetTriggerPlayer() then
      • Custom script: call LoadRequest(SubString(GetEventPlayerChatString(),9,15))
      • Custom script: endif
  • LoadCall
    • Events
      • Player - Player 1 (Red) types a chat message containing -load ini as An exact match
      • Player - Player 2 (Blue) types a chat message containing -load ini as An exact match
      • Player - Player 3 (Teal) types a chat message containing -load ini as An exact match
      • Player - Player 4 (Purple) types a chat message containing -load ini as An exact match
      • Player - Player 5 (Yellow) types a chat message containing -load ini as An exact match
      • Player - Player 6 (Orange) types a chat message containing -load ini as An exact match
      • Player - Player 7 (Green) types a chat message containing -load ini as An exact match
      • Player - Player 8 (Pink) types a chat message containing -load ini as An exact match
      • Player - Player 9 (Gray) types a chat message containing -load ini as An exact match
      • Player - Player 10 (Light Blue) types a chat message containing -load ini as An exact match
      • Player - Player 11 (Dark Green) types a chat message containing -load ini as An exact match
      • Player - Player 12 (Brown) types a chat message containing -load ini as An exact match
    • Conditions
    • Actions
      • Set save_load_boolean[((Player number of (Triggering player)) + 12)] = True
      • Set load_number[(Player number of (Triggering player))] = 0
      • Trigger - Turn on LoadUnit <gen>
  • LoadUnit
    • Events
      • Player - Player 1 (Red) types a chat message containing , as A substring
      • Player - Player 2 (Blue) types a chat message containing , as A substring
      • Player - Player 3 (Teal) types a chat message containing , as A substring
      • Player - Player 4 (Purple) types a chat message containing , as A substring
      • Player - Player 5 (Yellow) types a chat message containing , as A substring
      • Player - Player 6 (Orange) types a chat message containing , as A substring
      • Player - Player 7 (Green) types a chat message containing , as A substring
      • Player - Player 8 (Pink) types a chat message containing , as A substring
      • Player - Player 9 (Gray) types a chat message containing , as A substring
      • Player - Player 10 (Light Blue) types a chat message containing , as A substring
      • Player - Player 11 (Dark Green) types a chat message containing , as A substring
      • Player - Player 12 (Brown) types a chat message containing , as A substring
    • Conditions
    • Actions
      • Custom script: local integer udg_temp_integer
      • Set temp_integer = (Player number of (Triggering player))
      • Custom script: if udg_load_number[udg_temp_integer] < udg_load_limit then
      • Set load_number[temp_integer] = (load_number[temp_integer] + 1)
      • Custom script: call LoadUnit(GetEventPlayerChatString(),GetTriggerPlayer())
      • Custom script: endif
  • LoadFinish
    • Events
      • Player - Player 1 (Red) types a chat message containing -load end as An exact match
      • Player - Player 2 (Blue) types a chat message containing -load end as An exact match
      • Player - Player 3 (Teal) types a chat message containing -load end as An exact match
      • Player - Player 4 (Purple) types a chat message containing -load end as An exact match
      • Player - Player 5 (Yellow) types a chat message containing -load end as An exact match
      • Player - Player 6 (Orange) types a chat message containing -load end as An exact match
      • Player - Player 7 (Green) types a chat message containing -load end as An exact match
      • Player - Player 8 (Pink) types a chat message containing -load end as An exact match
      • Player - Player 9 (Gray) types a chat message containing -load end as An exact match
      • Player - Player 10 (Light Blue) types a chat message containing -load end as An exact match
      • Player - Player 11 (Dark Green) types a chat message containing -load end as An exact match
      • Player - Player 12 (Brown) types a chat message containing -load end as An exact match
    • Conditions
    • Actions
      • Custom script: local integer udg_temp_integer
      • Set save_load_boolean[((Player number of (Triggering player)) + 12)] = False
      • For each (Integer temp_integer) from 13 to 24, do (Actions)
        • Loop - Actions
          • Custom script: if udg_save_load_boolean[udg_temp_integer] == true then
          • Set temp_integer = 30
          • Custom script: endif
      • Custom script: if udg_temp_integer != 31 then
      • Trigger - Turn off LoadUnit <gen>
      • Custom script: endif

  • LoadSetCenter
    • Events
      • Player - Player 1 (Red) types a chat message containing -load center as An exact match
      • Player - Player 2 (Blue) types a chat message containing -load center as An exact match
      • Player - Player 3 (Teal) types a chat message containing -load center as An exact match
      • Player - Player 4 (Purple) types a chat message containing -load center as An exact match
      • Player - Player 5 (Yellow) types a chat message containing -load center as An exact match
      • Player - Player 6 (Orange) types a chat message containing -load center as An exact match
      • Player - Player 7 (Green) types a chat message containing -load center as An exact match
      • Player - Player 8 (Pink) types a chat message containing -load center as An exact match
      • Player - Player 9 (Gray) types a chat message containing -load center as An exact match
      • Player - Player 10 (Light Blue) types a chat message containing -load center as An exact match
      • Player - Player 11 (Dark Green) types a chat message containing -load center as An exact match
      • Player - Player 12 (Brown) types a chat message containing -load center as An exact match
    • Conditions
    • Actions
      • Custom script: local group udg_temp_group = CreateGroup()
      • Custom script: local unit udg_temp_unit
      • Custom script: local location udg_temp_point
      • Custom script: local integer udg_temp_integer
      • Set temp_integer = (Player number of (Triggering player))
      • Set temp_group = (Units currently selected by (Triggering player))
      • Set temp_unit = (Random unit from temp_group)
      • Set temp_point = (Rally-Point of temp_unit as a point)
      • Set load_center[temp_integer] = (X of temp_point)
      • Set load_center[(temp_integer + 12)] = (Y of temp_point)
      • Game - Display to (Player group((Triggering player))) the text: (Successfully set the center of future unit loads to + (( + (((String(load_center[temp_integer])) + |) + ((String(load_center[(temp_integer + 12)])) + )))))
      • Custom script: call RemoveLocation (udg_temp_point)
      • Custom script: call DestroyGroup (udg_temp_group)
      • Custom script: set udg_temp_group = null
      • Custom script: set udg_temp_unit = null
      • Custom script: set udg_temp_point = null
  • LoadSetLimit
    • Events
    • Conditions
    • Actions
      • Set load_limit = (Integer((Substring((Entered chat string), 13, 16))))
      • Game - Display to (All players) the text: (Unit Load Limit has been set to + (String(load_limit)))
      • -------- Double conversion ensures that, if for some reason the first conversion did not work out, the players won't receive the correct message --------
  • SaveSetParameters
    • Events
      • Player - Player 1 (Red) types a chat message containing -nosave units as A substring
      • Player - Player 2 (Blue) types a chat message containing -nosave units as A substring
      • Player - Player 3 (Teal) types a chat message containing -nosave units as A substring
      • Player - Player 4 (Purple) types a chat message containing -nosave units as A substring
      • Player - Player 5 (Yellow) types a chat message containing -nosave units as A substring
      • Player - Player 6 (Orange) types a chat message containing -nosave units as A substring
      • Player - Player 7 (Green) types a chat message containing -nosave units as A substring
      • Player - Player 8 (Pink) types a chat message containing -nosave units as A substring
      • Player - Player 9 (Gray) types a chat message containing -nosave units as A substring
      • Player - Player 10 (Light Blue) types a chat message containing -nosave units as A substring
      • Player - Player 11 (Dark Green) types a chat message containing -nosave units as A substring
      • Player - Player 12 (Brown) types a chat message containing -nosave units as A substring
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • save_load_boolean[((Player number of (Triggering player)) + 24)] Equal to False
        • Then - Actions
          • Set save_load_boolean[((Player number of (Triggering player)) + 24)] = True
          • Game - Display to (Player group((Triggering player))) the text: Units are now NOT b...
        • Else - Actions
          • Set save_load_boolean[((Player number of (Triggering player)) + 24)] = False
          • Game - Display to (Player group((Triggering player))) the text: Units are now being...
 
Last edited:
Level 24
Joined
Aug 1, 2013
Messages
4,657
hides dont really work, they are called [hidden=name]hidden text[/hidden]

Saving and reading files to and from the WC3 directory inst a problem, but the files that are stored are most probably going to be different, so this would never work in multiplayer.

You have to load in the data, synchronize the data, then create the units and whatever else you wanted to have stored.

Also... I can see that you might be a bit lazy to clear leaks and do things better, but this for example:
call CreateNUnitsAtLoc( 1, un_type, un_owner, un_loc, un_fangle ) is not lazyness.
You spend more time doing this than you would have if you just used the native.
 
Last edited:
Level 12
Joined
Jun 12, 2010
Messages
413
You spend more time doing this than you would have if you just used the native.
Yeah, I wanted to change that, but I just wanted to test it out quickly and converted the function from the GUI. Should've probably googled the native, yeah (just changed it)

Why would the data be different? The person who is storing the data is the one who knows how his base looks like, so what matters is how his client views the unit's position.

The data is being synchronized because all the clients detect the chat messages being sent, so all clients run the trigger(that's what I hope, anyway, is there something about chat messages that would stop that from happening?).


Remember, wc3 is not reading the files, it's reading the chat messages that the python script automatically types in after reading each file.


EDIT: Yep, the smell of GUI conversion is strong. Can't believe there were GetUnitX/Y natives
 
Last edited:
Level 12
Joined
Jun 12, 2010
Messages
413
But if you save, then quit, then make a game with me, then load, I dont have your data.

Yeah, you don't have my data, but you don't need to. I will run the Python script, it will iterate over each file and type enter + file content + enter. So I just run the python file (it starts typing after 5 seconds), go to Warcraft 3, and let the python file type all the data.

Then, my chat messages are broadcast to all clients. All clients receive the data from each entered chat message, and they run the trigger to interpret the chat message as a unit type, unit location, unit life(not implemented) and unit facing angle. (A GUI trigger has the chat event and calls a jass function. Both are called LoadUnit)

So your client would receive my data from the chat messages that my client sent (thus the uncreative name "chat based save/load")

Of course, this may fail horribly for some reason, but the overall logic behind it seems reasonable.

What do you mean that wc3 doesnt read the files?

Warcraft 3 isn't opening the files themselves, the Python script is. I.e: You don't need local files enabled
 
Last edited:
Level 12
Joined
Jun 12, 2010
Messages
413
Update 1:

Wc3 system:
-Typing [-request (str)] command in Wc3 will interact with the python program (by creating a file named "load.txt" (no longer requires typing outside wc3)
-Added command [-load limit (9999 max)], allowing GAME_MASTER player to limit the amount of units that can be loaded into the map
-QoL changes:
  1. Organized categories
  2. Added test commands

Python script:
-Made changes to adjust to new system

Original Post:
-Added guide
-Changed a lot of stuff
 

Attachments

  • save stuff.w3x
    30.2 KB · Views: 91
Last edited:
Level 12
Joined
Jun 12, 2010
Messages
413
This is by far the worst save system code-wise that I have ever seen.

Thanks. I'd figured it would be no top 20, but that is worse than what I had thought. Sure there are a lot of unnecessary function calls, but that's an optimization problem that can be fixed and not a code/logic problem.

Seriously, there are lots of other options on Hive with far better configurability, code structure and overall execution.

I know it's not at effective compared to Triggerhappy's system (for example), but that and all other codeless systems are written in vJASS and configured to RPGs (saving heroes and not multiple unit positions/facing), so I just gave up on trying to edit or configure those systems to the purpose I need them for. Can you point me to a system that could be easily changed to have this same functionality (saving entire bases and armies, with hundreds of units)? Even if it's vJASS I'm willing to learn the language if the configuring is easy enough.

Just a point though, there's basically no configuration because I made the code in 1/2 days just to get the functionality in my map specifically, and posted it here to link it to my map here on the hive (which was not currently uploaded in the beta map section). Most maps that would want this kind of save/load wouldn't really need to configure much (except forbidden load unit-types and saving unit flying height), but of course I would add more configurability if I were posting it in a resource section.

My other original intent of giving ideas to link wc3 and external apps is basically moot now because I learnt that SharpCraft can basically do anything related to this =/


Anyway, I would appreciate any indications to good systems that I may have missed, preferably GUI/JASS but vJASS works too, as I said. Thanks for your time (even if it may have been wasted reading subpar code =/ )
 
Last edited:
Level 31
Joined
Jul 10, 2007
Messages
6,306
To do codeless save/load, you need 3 things.


1. File IO
2. Data Synchronizer (broadcast, receive)
3. Encoder/Decoder


These three can be three separate systems. The actual save/load bit would be the thing that glues them together.

If you look at what TriggerHappy did, he has a data synchronizer lib (since I have yet to update mine, lol) and a File IO lib (the one I wrote). He uses these two libs in his encoder/decoder. The encoder/decoder kind of glues everything plus does its own encoding/decoding. I don't really agree with this, but w/e.


There are several encoder/decoder libs out there, a mostly ok data synchronization lib, and a semi-ok File IO lib. Pick and choose and glue them together and you've got your codeless save/load. There are even examples of optimized StringPackets in my codeless save/load lib (my glue example).


There are plenty of libs for encoding by bit or encoding by a specific base too.



There is also a fourth piece of the puzzle. This is security. There are MD5 libs, AES libs, checksum libs, scrambling libs... you name it, we probably have it : p.


There are also a bunch of algorithms published around and about for saving things like a unit's inventory, level, and abilities. I don't think there are any algorithms for saving a group that are published, but that is simple enough : ).



We even have lossy compression algorithms : O.
 
Level 12
Joined
Jun 12, 2010
Messages
413
To do codeless save/load, you need 3 things.


1. File IO
2. Data Synchronizer (broadcast, receive)
3. Encoder/Decoder


These three can be three separate systems. The actual save/load bit would be the thing that glues them together.

If you look at what TriggerHappy did, he has a data synchronizer lib (since I have yet to update mine, lol) and a File IO lib (the one I wrote). He uses these two libs in his encoder/decoder. The encoder/decoder kind of glues everything plus does its own encoding/decoding. I don't really agree with this, but w/e.


There are several encoder/decoder libs out there, a mostly ok data synchronization lib, and a semi-ok File IO lib. Pick and choose and glue them together and you've got your codeless save/load. There are even examples of optimized StringPackets in my codeless save/load lib (my glue example).


There are plenty of libs for encoding by bit or encoding by a specific base too.



There is also a fourth piece of the puzzle. This is security. There are MD5 libs, AES libs, checksum libs, scrambling libs... you name it, we probably have it : p.


There are also a bunch of algorithms published around and about for saving things like a unit's inventory, level, and abilities. I don't think there are any algorithms for saving a group that are published, but that is simple enough : ).



We even have lossy compression algorithms : O.


Thanks for the reply and the help!

Security is not really an issue, since it's a sandbox map, and I undesired unit-types can be filtered in-game.

Data sync seems to work really well through the chat messages, but I have only tried with 4 player local games :S And it requires an external program to actually type the messages =/ So the vJASS libs are definitely better (except for the fact that I don't really understand how they work yet) and faster (though I haven't tested how fast this system can be at its limit)
Encoding/Decoding is really nice because of the reduction of the final string that you're saving to the file, I didn't do it originally because I wanted to see if my concept worked first, but I'll look into that xD

I just don't get the File I/O part. Isn't that what the Preload API is used for?

Anyway, it seems like my system has got File I/O (at least, the preload API :S) down, and can synchronize data through chat messages and the python program, from the things you listed. (so 2/3, with a third-party program required...yay...)

I still don't understand the Sync lib that TriggerHappy made (because I have almost no knowledge of network code), but I guess I'll just have to live with the fact that I need to add vJASS to my map and learn it :S
 
Level 6
Joined
Jul 30, 2013
Messages
282
yes, FileIO is accessible thru the Preload* natives. there are some libs out there that provide better abstractions( eg Nestharus' FileIO lib is quite nice) but you can do it manually if you like.

File IO is not the difficult part tho, just annoying. the real issue is the fact that file io is local to 1 player, if you load stuff naively then you can have a situation where the player that just loaded his code will be in a different gamestate than everybody else and he will be kicked from the game by the war3 coherence enforcement systems (desync).

to solve this you need to explicity coordinate the loading procedure so that everybody agrees on the game state. this is what the Sync libraries are for (Nestharus and TriggerHappy have one i think..) this is also what your python script solves by entering chat messages on the users behalf.

The python program is simpler perhaps(to implement) because you dont have to deal with syncing state in game but rely on built in war3 mechanisms however that requires an external program. other solutions work in pure JASS2 and are adevantageous in that no players need to install 3rd party programs. Since you don't have to code the sync yourself but can rely on excellent community resources there is really no reason to make something less usable.
 
Level 12
Joined
Jun 12, 2010
Messages
413
yes, FileIO is accessible thru the Preload* natives. there are some libs out there that provide better abstractions( eg Nestharus' FileIO lib is quite nice) but you can do it manually if you like.

So there are other ways of doing IO, or are those libs using the Preload API to make an effective system and then abstracting that to a better API?

My own way of doing it in this is currently very, very bad (saving 1 unit per file is such a waste), it's embarrassing even though it was more of a proof of concept :S


The python program is simpler perhaps(to implement) because you dont have to deal with syncing state in game but rely on built in war3 mechanisms however that requires an external program. other solutions work in pure JASS2 and are adevantageous in that no players need to install 3rd party programs. Since you don't have to code the sync yourself but can rely on excellent community resources there is really no reason to make something less usable.



Well, it COULD be said that you need a .bat file/JGNP/Registry editor for those libs, since the client needs local files enabled :p

But yeah, this is a lot less convenient for the user, and I definetly didn't mean to make it out to be a better alternative than the sync libs. It just seemed easier to me (because I'd never coded in JASS when I set out to make this) to learn JASS and make my own thing than learn JASS -> vJASS and then understand the codeless save/load libs to make them do what I wanted.

Basically I made this because of my own incompetence/inexperience (and it was fun), and posted it because someone, somewhere may need a JASS/GUI codeless save/load for RPs (if you're going to change it, might as well learn and use the better libs )

This could always be deleted, but might as well just leave it here for reference and possible use (as if :rolleyes:). Also got some fairly insightful responses, so that's a plus

I'm probably going to use an improved version of this anyway, because I intend to make the first version of my Titan Land map saveable in default World Editor (for accessibility to other mappers). Then I can switch to vJASS.
 
Level 6
Joined
Jul 30, 2013
Messages
282
So there are other ways of doing IO, or are those libs using the Preload API to make an effective system and then abstracting that to a better API?

My own way of doing it in this is currently very, very bad (saving 1 unit per file is such a waste), it's embarrassing even though it was more of a proof of concept :S






Well, it COULD be said that you need a .bat file/JGNP/Registry editor for those libs, since the client needs local files enabled :p

But yeah, this is a lot less convenient for the user, and I definetly didn't mean to make it out to be a better alternative than the sync libs. It just seemed easier to me (because I'd never coded in JASS when I set out to make this) to learn JASS and make my own thing than learn JASS -> vJASS and then understand the codeless save/load libs to make them do what I wanted.

Basically I made this because of my own incompetence/inexperience (and it was fun), and posted it because someone, somewhere may need a JASS/GUI codeless save/load for RPs (if you're going to change it, might as well learn and use the better libs )

This could always be deleted, but might as well just leave it here for reference and possible use (as if :rolleyes:). Also got some fairly insightful responses, so that's a plus

I'm probably going to use an improved version of this anyway, because I intend to make the first version of my Titan Land map saveable in default World Editor (for accessibility to other mappers). Then I can switch to vJASS.

underneath all current fileIO libs use preload(honestly i dont think there are any other ways, at least not practical ones tho if you use gamecache then that might count for singleplayer use), they are just much nicer to use. (also you pretty much need vjass to get the nice interface, Vexorians JassHelper is pretty much the "industry standard" on Hive and the JNGP makes it nice for new users.)

the current file io libs create the bat file for you once, the user just needs to run it once, as opposed to a python script that you need to run every single time. the user can also enable local files via the map editor rly but then they can forget about that. better usability in short.

if you want to tinker then maybe you could do something to trick preload natives to access some web resources in stead... (windows network file paths.. should be doable..) ;)
 
Level 6
Joined
Jul 30, 2013
Messages
282
you might find this useful(Nestharus' series of tutorials about vjass and newgen pack):
Nes' even has an example of how to make a codeless save/load system using some of his resources. quite informative.
 
Status
Not open for further replies.
Top