- Joined
- Nov 7, 2014
- Messages
- 571
gcio - Jass2 input/output with the gamecache natives
The gamecache natives allow for reading (ReloadGameCachesFromDisk) and writing (SaveGameCache) of data
from/to the disk (the Campaigns.w3v file), in single player only!
Input data can be passed to a running map by writing to the Campaigns.w3v file from an external program, then
from the jass' side, first the ReloadGameCachesFromDisk native must be called in order to reload the data from
the campaigns file and then the other gamecache natives (GetStoredInteger|Real|String) would be used to get
the data.
Output data can be written with jass using the StoreString and SaveGameCache natives. The SaveGameCache
native writes the data to the campaigns file, then an external program can extract the data and write it to another file.
Gamecaches were used by Blizzard to store progress of campaigns that spanned several maps.
Each single player profile has its own Campaigns.w3v file.
The location of the file is (at least on windows):
/path/to/game/save/ProfileX/Campaigns.w3v -- for game versions prior to 1.28 (I think)
/users/<user-name>/Saved Games/Warcraft III/ProfileX/Campaigns.w3v -- for later game versions
The 'X' in 'ProfileX' is an integer number that starts from 1, if you have 3 profiles then there would be 3 directories
called Profile1, Profile2 and Profile3.
WARNING:
It is possible that gcio could corrupt your profile's Campaigns.w3v file which would result in campaigns progress loss!
So before any attempts of using gcio you should either make a backup of your profile's Campaigns.w3v file
or create a new profile with an empty Campaigns.w3v file, which could be deleted if something goes wrong.
Feeding data to your map script using gcio:
gcio monitors a directory (given as a command line argument) that contains files with a .gc-txt extension.
Each .gc-txt file represents a single gamecache. The format of a .gc-txt file can hopefully be inferred from this example:
A change to a .gc-txt file is picked up by gcio and the target campaigns file (passed as a command line argument) is updated.
From jass' side the change to the campaigns file cannot be automatically detected (as far as I know), so the reload
of the campaigns file must be triggered manually.
Given the following gamecache stored in the my-tweak-files/gc1.gc-txt file:
We start gcio with the command:
gcio -in my-tweak-files path/to/my/profile/Campaigns.w3v
Then we trigger a change to the gc1.gc-txt file (add a newline or whitespace somewhere, or something...),
gcio picks up the change and updates the campaign file.
Then from jass we can use the values with:
Dumping data from jass to a file using gcio:
gcio monitors the campaigns file for changes, when these happen it goes over all the gamecaches stored in the
campaigns file and looks for gamecache names starting with '>', then it uses whatever is after the '>' as the
name of the output file. The content of that file comes from the values of the string-list of the key with
a name = 'lines'.
We start gcio with the command:
gcio -out out-files path/to/my/profile/Campaigns.w3v
Then from jass we write some data:
After calling the gc_out_example function the out-files/my-random-numbers.txt file should exist and contain some
random numbers, say:
The gamecache natives are a bit wordy so you might want to write some convinience wrappers, for example:
for getting input values and:
for writing out data to a file.
Credits:
PitzerMiker, whose CacheConv tool more or less documents the w3v file format, and everyone else that helped figuring it out.
The gamecache natives allow for reading (ReloadGameCachesFromDisk) and writing (SaveGameCache) of data
from/to the disk (the Campaigns.w3v file), in single player only!
Input data can be passed to a running map by writing to the Campaigns.w3v file from an external program, then
from the jass' side, first the ReloadGameCachesFromDisk native must be called in order to reload the data from
the campaigns file and then the other gamecache natives (GetStoredInteger|Real|String) would be used to get
the data.
Output data can be written with jass using the StoreString and SaveGameCache natives. The SaveGameCache
native writes the data to the campaigns file, then an external program can extract the data and write it to another file.
Gamecaches were used by Blizzard to store progress of campaigns that spanned several maps.
Each single player profile has its own Campaigns.w3v file.
The location of the file is (at least on windows):
/path/to/game/save/ProfileX/Campaigns.w3v -- for game versions prior to 1.28 (I think)
/users/<user-name>/Saved Games/Warcraft III/ProfileX/Campaigns.w3v -- for later game versions
The 'X' in 'ProfileX' is an integer number that starts from 1, if you have 3 profiles then there would be 3 directories
called Profile1, Profile2 and Profile3.
WARNING:
It is possible that gcio could corrupt your profile's Campaigns.w3v file which would result in campaigns progress loss!
So before any attempts of using gcio you should either make a backup of your profile's Campaigns.w3v file
or create a new profile with an empty Campaigns.w3v file, which could be deleted if something goes wrong.
Feeding data to your map script using gcio:
gcio monitors a directory (given as a command line argument) that contains files with a .gc-txt extension.
Each .gc-txt file represents a single gamecache. The format of a .gc-txt file can hopefully be inferred from this example:
Lua:
-- this is a comment
-- if your editor supports Lua highlighting, you might want to use it
'gamecache name':
-- what follows are the keys of the gamecache
'key-1':
-- each key has 3 lists, list of integers, list of reals and list of strings
integers
-- each list consists of a name-value pair
'a': 1 -- name is 'a', integer value is 1
'b': 2
reals
'tau': 6.28 -- name is 'tau', value is 6.28
strings
'foo': 'bar' -- name is 'foo', value is 'bar'
'baz': 'qux'
-- if we don't use an end token here, 'key-2' would be parsed as the name
-- of the next string after 'baz': 'qux'
end
'key-2':
-- the order is always integers, reals, strings
-- so seeing integers after reals is an error
reals
'tau': 6.28
-- integers
-- 'a': 1
-- 'b': 2
end
'key-3':
integers
'a': 1
-- it is allowed to skip any of the lists (integers, reals, strings)
-- here we are skipping the list of reals
strings
'foo': 'bar'
end
'key-4':
-- no integers, nor reals nor strings
end
'key-5':
integers -- empty integers list
reals
'tau': 6.28
strings -- empty strings list
end
'key-6':
-- newlines are required
-- integers reals 'tau': 6.28 strings -- error
-- ok
integers
reals
'tau': 6.28
strings
end
'key-7':
strings
-- a literal single quote can be used in a string
-- by escaping it with a backslash
'foo': 'foo\'s bar'
-- a backslash not followed by a single quote is a literal backslash
'path': 'to\file'
end
'key-8':
-- hexadecimal notation is supported for integers and reals
integers
'integer-255': 0xFF
reals
'real-1.0': 0x3F800000
end
'key-9':
strings
'multiline-string': '
Line A
Line B
'
end
A change to a .gc-txt file is picked up by gcio and the target campaigns file (passed as a command line argument) is updated.
From jass' side the change to the campaigns file cannot be automatically detected (as far as I know), so the reload
of the campaigns file must be triggered manually.
Given the following gamecache stored in the my-tweak-files/gc1.gc-txt file:
Lua:
'gc1':
'key-name':
integers
'integer-name': 1
reals
'real-name': 2.0
strings
'string-name': 'three'
end
We start gcio with the command:
gcio -in my-tweak-files path/to/my/profile/Campaigns.w3v
Then we trigger a change to the gc1.gc-txt file (add a newline or whitespace somewhere, or something...),
gcio picks up the change and updates the campaign file.
Then from jass we can use the values with:
JASS:
function gc1_example takes nothing returns nothing
local gamecache gc1 = InitGameCache("gc1")
if not ReloadGameCachesFromDisk() then
call BJDebugMsg("could not reload gamecaches from disk")
return
endif
call BJDebugMsg(I2S( GetStoredInteger(gc1, "key-name", "integer-name") )) // 1
call BJDebugMsg(R2S( GetStoredReal(gc1, "key-name", "real-name") )) // 2.0
call BJDebugMsg(( GetStoredString(gc1, "key-name", "string-name") )) // three
endfunction
Dumping data from jass to a file using gcio:
gcio monitors the campaigns file for changes, when these happen it goes over all the gamecaches stored in the
campaigns file and looks for gamecache names starting with '>', then it uses whatever is after the '>' as the
name of the output file. The content of that file comes from the values of the string-list of the key with
a name = 'lines'.
We start gcio with the command:
gcio -out out-files path/to/my/profile/Campaigns.w3v
Then from jass we write some data:
JASS:
function gc_out_example takes nothing returns nothing
local gamecache gc = InitGameCache(">my-random-numbers.txt")
local integer i = 1
loop
exitwhen i > 10
call StoreString(gc, "lines", I2S(i), R2S(GetRandomReal(0.0, 1.0)))
set i = i + 1
endloop
call SaveGameCache(gc) // flush the gamecache to disk
endfunction
After calling the gc_out_example function the out-files/my-random-numbers.txt file should exist and contain some
random numbers, say:
JASS:
0.057
0.248
0.263
0.306
0.959
0.861
0.676
0.327
0.501
0.224
The gamecache natives are a bit wordy so you might want to write some convinience wrappers, for example:
JASS:
struct Gc_Key
gamecache gc
string key_name
string val_name
static method create takes gamecache gc, string key_name returns Gc_Key
local Gc_Key gk = allocate()
set gk.gc = gc
set gk.key_name = key_name
return gk
endmethod
method operator [] takes string val_name returns Gc_Key
set this.val_name = val_name
return this
endmethod
method operator i takes nothing returns integer
return GetStoredInteger(this.gc, this.key_name, this.val_name)
endmethod
method operator i= takes integer x returns nothing
call StoreInteger(this.gc, this.key_name, this.val_name, x)
endmethod
method operator r takes nothing returns real
return GetStoredReal(this.gc, this.key_name, this.val_name)
endmethod
method operator r= takes real x returns nothing
call StoreReal(this.gc, this.key_name, this.val_name, x)
endmethod
method operator s takes nothing returns string
return GetStoredString(this.gc, this.key_name, this.val_name)
endmethod
method operator s= takes string x returns nothing
call StoreString(this.gc, this.key_name, this.val_name, x)
endmethod
endstruct
for getting input values and:
JASS:
struct Out_File
gamecache gc
integer line = 1
string cur_line = ""
static method open takes string name returns Out_File
local Out_File f = allocate()
set f.gc = InitGameCache(">" + name)
call FlushStoredMission(f.gc, "lines")
return f
endmethod
method write takes string s returns nothing
set this.cur_line = this.cur_line + s
endmethod
method writeln takes string s returns nothing
call StoreString(this.gc, "lines", I2S(this.line), this.cur_line + s)
set this.line = this.line + 1
set this.cur_line = ""
endmethod
method close takes nothing returns nothing
call SaveGameCache(this.gc)
call this.destroy()
endmethod
endstruct
for writing out data to a file.
Credits:
PitzerMiker, whose CacheConv tool more or less documents the w3v file format, and everyone else that helped figuring it out.