Skip to content

Commit 940f488

Browse files
committed
new save load tutorial
1 parent 4d37df7 commit 940f488

File tree

4 files changed

+113
-51
lines changed

4 files changed

+113
-51
lines changed

_doc/tutorials/saveload.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
---
22
title: Save and Load
33
excerpt: Learn how to use Wurst's codeless save and load API
4-
date: 2021-10-06
4+
date: 2021-12-04
55
icon:
66
type: fa
77
name: fa-save
88
color: blue
99
layout: tutorialdoc
1010
sections:
11-
- /tutorials/saveload/highlevel
12-
- /tutorials/saveload/lowlevel
11+
- /tutorials/saveload/saveload
12+
- /tutorials/saveload/serializable
1313
---

_doc/tutorials/saveload/lowlevel.md

Lines changed: 0 additions & 42 deletions
This file was deleted.

_doc/tutorials/saveload/highlevel.md renamed to _doc/tutorials/saveload/saveload.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
title: High level API
2+
title: Save Load API
33
sections:
44
- Welcome
55
- Behind the scenes
@@ -15,7 +15,7 @@ Import the `SaveLoadData` package to use the following code examples.
1515

1616
## Behind the scenes
1717

18-
Internally the save load packages make use of the preload exploit, which is now officially endorsed by blizzard to save and load files from the CustomMapData folder in your Warcraft III Document root.
18+
Internally the save load packages make use of the preload exploit, which is now officially endorsed by blizzard to save and load files from the `CustomMapData` folder in your Warcraft III Document root.
1919
Data loaded from a specific player is therefore only loaded on that player's machine and needs to be synchronized with all other players before it can be used in a synchronous environment.
2020
Wurst wraps all this behind a simple API, so you don't need to worry about the details.
2121

@@ -26,7 +26,7 @@ Existing file contents will be overriden.
2626
Since saving does not require synchronizing, it is a simple, blocking operation.
2727

2828
```wurst
29-
init
29+
function savePlayerData()
3030
players[0].saveData("MyFileName", "someDataString")
3131
```
3232

@@ -40,17 +40,17 @@ Loading may also fail if the file is empty, corrupted, or the player disconnects
4040
If the status is `SUCCESS`, the `data` parameter will contain the synchronized version of the file's contents, which you can immediately use in a synchronous context.
4141

4242
```wurst
43-
init
43+
function loadPlayerData()
4444
players[0].loadData("MyFileName") (status, data) ->
4545
if status == LoadStatus.SUCCESS
46-
Log.info("Loaded: " + data.readStringUnsafe())
46+
Log.info("Loaded: " + data.getUnsafeString())
4747
else
4848
// some error handling
4949
```
5050

5151
## Limitations and Chunking
5252

53-
As you can see we used `.readStringUnsafe()` in the example above. It is unsafe because the maximum length of a `string` in Jass is capped at 1024 bytes without and 4099 characters with concatenation. This would not only limit how much data we can load/save, but also complicate the usage in general.
53+
As you can see we used `.getUnsafeString()` in the example above. It is unsafe because the maximum length of a `string` in Jass is capped at 1024 bytes without and 4099 characters with concatenation. This would not only limit how much data we can load/save, but also complicate the usage in general.
5454
1024 bytes also doesn't equal to 1024 characters, because certain characters (unicode) take up more than 1 byte.
5555

5656
Thus it is generally recommended to use a `ChunkedString` for any data above around 500 characters. The `ChunkedString` splits big strings into smaller chunks, which can then be acceessed seperately. The save functions are overloaded to allow string or ChunkedString input.
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
---
2+
title: Serializable
3+
sections:
4+
- Motivation
5+
- Usage
6+
- Complete Example
7+
---
8+
9+
## Motivation
10+
11+
Of course usually we don't want to save just strings, but data that is stored in some object.
12+
For this purpose there is the `abstract class Serializable` for simple saving and loading of primitive attribute values.
13+
The `serialize()` function returns a `ChunkedString`, which then can be passed to the data save function from above.
14+
15+
16+
## Usage
17+
18+
Import `Serializable` Make your data class extend `Serializable` and implement the required functions.
19+
20+
```wurst
21+
import Serializable
22+
23+
class MyClass extends Serializable
24+
var amount = 0
25+
26+
override function serializeProperties()
27+
28+
override function deserializeProperties()
29+
```
30+
31+
### Saving Attributes
32+
33+
Inside the `serializeProperties` register all attributes that should be serialized using `addProperty`.
34+
35+
```wurst
36+
override function serializeProperties()
37+
addProperty("amount", amount)
38+
```
39+
40+
### Loading attributes
41+
42+
Every serialized attribute should also be deserialized again in the `deserializeProperties` function using the appropriate `getXXProperty` function and assigned to the attribute.
43+
Make sure to use the same name used for saving.
44+
45+
```wurst
46+
override function deserializeProperties()
47+
amount = getIntProperty("amount")
48+
```
49+
50+
### Serializing
51+
52+
Serialize the data class object to a `ChunkedString` using `serialize`. You can pass this chunked string directly to the save functions from above.
53+
54+
```wurst
55+
let saveData = new MyClass()
56+
saveData.amount = 1337
57+
let result = saveData.serialize()
58+
```
59+
60+
### Deserializing
61+
62+
To load from a `ChunkedString`, which could be obtained by loading using the function above, use `deserialize`.
63+
64+
```wurst
65+
let loadedData = new MyClass()
66+
loadedData.deserialize(inputChunkedString)
67+
```
68+
69+
## Complete Example
70+
71+
Find a full working example below. The first time you run the map a new save file will be created saving the value `1337` in the `amount` attribute.
72+
The second time you run the map it will load the existing save file and assign `1337` to the loaded object's `amount` variable, which is printed on the screen.
73+
74+
```wurst
75+
package SerTest
76+
import Serializable
77+
import SaveLoadData
78+
import ClosureTimers
79+
80+
constant FILE_NAME = "MyFileName"
81+
82+
class MyClass extends Serializable
83+
var amount = 0
84+
85+
override function serializeProperties()
86+
addProperty("amount", amount)
87+
88+
override function deserializeProperties()
89+
amount = getIntProperty("amount")
90+
91+
init
92+
doAfter(1.) ->
93+
players[0].loadData(FILE_NAME) (status, data) ->
94+
if status == LoadStatus.SUCCESS
95+
let loadedData = new MyClass()..deserialize(data)
96+
print("loaded: " + loadedData.amount.toString())
97+
else
98+
let saveData = new MyClass()
99+
saveData.amount = 1337
100+
let saveString = saveData.serialize()
101+
players[0].saveData(FILE_NAME, saveString)
102+
print("created new save file")
103+
104+
```

0 commit comments

Comments
 (0)