|
| 1 | +# DataStorage |
| 2 | + |
| 3 | +DataStorage support is included in the library. You may save values on the archipelago server in order to share them |
| 4 | +across other player's sessions or to simply keep track of values outside your game's state. |
| 5 | + |
| 6 | +The DataStorage provides an interface based on keys and their scope. By assigning a value to a key, that value is stored |
| 7 | +on the server and by reading from a key a value is retrieved from the server. |
| 8 | +Assigning and reading values from the store can be done using simple assignments `=`: |
| 9 | + |
| 10 | +* `= session.DataStorage["Key"]`, read value from the data storage synchronously |
| 11 | +* `session.DataStorage["Key"] =`, write value to the data storage asynchronously |
| 12 | +* Complex objects need to be stored and retrieved in the form of a `JObject`, therefore you must wrap them into a |
| 13 | + `JObject.FromObject()` |
| 14 | + |
| 15 | +The DataStorage also provides methods to retrieve the value of a key asynchronously using `[key].GetAsync`. |
| 16 | +To set the initial value of a key without overriding any existing value, the `[key].Initialize` method can be used. |
| 17 | +If you're interested in keeping track of when a value of a certain key is changed by any client you can use the |
| 18 | +`[key].OnValueChanged` handler to register a callback for when the value gets updated. |
| 19 | + |
| 20 | +Mathematical operations on values stored on the server are supported using the following operators: |
| 21 | + |
| 22 | +* `+`, Add right value to left value |
| 23 | +* `-`, Subtract right value from left value |
| 24 | +* `*`, Multiply left value by right value |
| 25 | +* `/`, Divide left value by right value |
| 26 | +* `%`, Gets remainder after dividing left value by right value |
| 27 | +* `^`, Multiply left value by the power of the right value |
| 28 | + |
| 29 | +Bitwise operations on values stored on the server are supported using the following operations: |
| 30 | + |
| 31 | +* `+ Bitwise.Xor(x)`, apply logical exclusive OR to the left value using value x |
| 32 | +* `+ Bitwise.Or(x)`, apply logical OR to the left value using value x |
| 33 | +* `+ Bitwise.And(x)`, apply logical AND to the left value using value x |
| 34 | +* `+ Bitwise.LeftShift(x)`, binary shift the left value to the left by x |
| 35 | +* `+ Bitwise.RightShift(x)`, binary shift the left value to the right by x |
| 36 | + |
| 37 | +Other operations on values stored on the server are supported using the following operations: |
| 38 | + |
| 39 | +* `+ Operation.Min(x)`, get the lowest value of the left value and x |
| 40 | +* `+ Operation.Max(x)`, get the highest value of the left value and x |
| 41 | +* `+ Operation.Remove(x)`, when the left value is a list, removes the first element with value x |
| 42 | +* `+ Operation.Pop(x)`, when the left value is a list or dictionary, removes the element at index x or key x |
| 43 | +* `+ Operation.Update(x)`, when the left value is a list or dictionary, updates the dictionary with the keys/values in x |
| 44 | + |
| 45 | +Operation specific callbacks are supported, these get called only once with the results of the current operation: |
| 46 | + |
| 47 | +* `+ Callback.Add((oldValue, newValue) => {});`, calls this method after your operation or chain of operations are |
| 48 | + processed by the server |
| 49 | + |
| 50 | +Mathematical operations, bitwise operations and callbacks can be chained, given the extended syntax with `()` around |
| 51 | +each operation. |
| 52 | + |
| 53 | +Examples: |
| 54 | + |
| 55 | +```csharp |
| 56 | +var session = ArchipelagoSessionFactory.CreateSession("localhost", 38281); |
| 57 | +session.TryConnectAndLogin("Timespinner", "Jarno", ItemsHandlingFlags.AllItems); |
| 58 | + |
| 59 | +//Initializing |
| 60 | +session.DataStorage["B"].Initialize(20); //Set initial value for B in global scope if it has no value assigned yet |
| 61 | +
|
| 62 | +//Storing/Updating |
| 63 | +session.DataStorage[Scope.Slot, "SetPersonal"] = 20; //Set `SetPersonal` to 20, in scope of the current connected user\slot |
| 64 | +session.DataStorage[Scope.Global, "SetGlobal"] = 30; //Set `SetGlobal` to 30, in global scope shared among all players (the default scope is global) |
| 65 | +session.DataStorage["Add"] += 50; //Add 50 to the current value of `Add` |
| 66 | +session.DataStorage["Divide"] /= 2; //Divide current value of `Divide` in half |
| 67 | +session.DataStorage["Max"] += + Operation.Max(80); //Set `Max` to 80 if the stored value is lower than 80 |
| 68 | +session.DataStorage["Dictionary"] = JObject.FromObject(new Dictionary<string, int>()); //Set `Dictionary` to a Dictionary |
| 69 | +session.DataStorage["SetObject"] = JObject.FromObject(new SomeClassOrStruct()); //Set `SetObject` to a custom object |
| 70 | +session.DataStorage["BitShiftLeft"] += Bitwise.LeftShift(1); //Bitshift current value of `BitShiftLeft` to left by 1 |
| 71 | +session.DataStorage["Xor"] += Bitwise.Xor(0xFF); //Modify `Xor` using the Bitwise exclusive or operation |
| 72 | +session.DataStorage["DifferentKey"] = session.DataStorage["A"] - 30; //Get value of `A`, Assign it to `DifferentKey` and then subtract 30 |
| 73 | +session.DataStorage["Array"] = new []{ "One", "Two" }; //Arrays can be stored directly, List's needs to be converted ToArray() first |
| 74 | +session.DataStorage["Array"] += new []{ "Three" }; //Append array values to existing array on the server |
| 75 | +
|
| 76 | +//Chaining operations |
| 77 | +session.DataStorage["Min"] = (session.DataStorage["Min"] + 40) + Operation.Min(100); //Add 40 to `Min`, then Set `Min` to 100 if `Min` is bigger than 100 |
| 78 | +session.DataStorage["C"] = ((session.DataStorage["C"] - 6) + Bitwise.RightShift(1)) ^ 3; //Subtract 6 from `C`, then multiply `C` by 2 using bitshifting, then take `C` to the power of 3 |
| 79 | +
|
| 80 | +//Update callbacks |
| 81 | +//EnergyLink deplete pattern, subtract 50, then set value to 0 if its lower than 0 |
| 82 | +session.DataStorage["EnergyLink"] = ((session.DataStorage["EnergyLink"] - 50) + Operation.Min(0)) + Callback.Add((oldData, newData) => { |
| 83 | + var actualDepleted = (float)newData - (float)oldData; //calculate the actual change, might differ if there was less than 50 left on the server |
| 84 | +}); |
| 85 | + |
| 86 | +//Keeping track of changes |
| 87 | +session.DataStorage["OnChangeHandler"].OnValueChanged += (oldData, newData) => { |
| 88 | + var changed = (int)newData - (int)oldData; //Keep track of changes made to `OnChangeHandler` by any client, and calculate the difference |
| 89 | +}; |
| 90 | + |
| 91 | +//Keeping track of change (but for more complex data structures) |
| 92 | +session.DataStorage["OnChangeHandler"].OnValueChanged += (oldData, newData) => { |
| 93 | + var old_dict = oldData.ToObject<Dictionary<int, int>>(); |
| 94 | + var new_dict = newData.ToObject<Dictionary<int, int>>(); |
| 95 | +}; |
| 96 | + |
| 97 | +//Retrieving |
| 98 | +session.DataStorage["Async"].GetAsync<string>(s => { string r = s }); //Retrieve value of `Async` asynchronously |
| 99 | +float f = session.DataStorage["Float"]; //Retrieve value for `Float` synchronously and store it as a float |
| 100 | +var d = session.DataStorage["DateTime"].To<DateTime>() //Retrieve value for `DateTime` as a DateTime struct |
| 101 | +var array = session.DataStorage["Strings"].To<string[]>() //Retrieve value for `Strings` as string Array |
| 102 | +
|
| 103 | +//Handling anonymous object, if the target type is not known you can use `To<JObject>()` and use its interface to access the members |
| 104 | +session.DataStorage["Anonymous"] = JObject.FromObject(new { Number = 10, Text = "Hello" }); //Set `Anonymous` to an anonymous object |
| 105 | +var obj = session.DataStorage["Anonymous"].To<JObject>(); //Retrieve value for `Anonymous` where an anonymous object was stored |
| 106 | +var number = (int)obj["Number"]; //Get value for anonymous object key `Number` |
| 107 | +var text = (string)obj["Text"]; //Get value for anonymous object key `Text` |
| 108 | +
|
| 109 | +``` |
0 commit comments