-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathWUBInventory.cs
273 lines (258 loc) · 11.3 KB
/
WUBInventory.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
using UnityEngine;
using System;
namespace MBS
{
public class WUBInventory : MBSSingleton<WUBInventory>
{
/// <summary>
/// Direct access to the data and all the search and filter functions available to you
/// The new methods provided in this class should be all you need but it is made public
/// so you have the option of doing advanced work if you so please
/// </summary>
static public CML Inventory { get; set; } = new CML();
/// <summary>
/// Default filename to store a player's inventory to and load it from.
/// This is guaranteed to be unique per player if loading and saving takes place
/// after login and before logout.
/// Change this before calling Load or Save functions if you want to use something else
/// </summary>
static public string SaveFileName => WULogin.Username + "Inventory";
/// <summary>
/// When subtracting inventory and meta values, should it be allowed to go below zero?
/// </summary>
const bool AllowNegativeValues = false;
const string OnlineSaveFieldName = "Inventory";
private void Awake()
{
WULogin.OnLoggedIn += OnLoggedIn;
}
void OnLoggedIn(CML _) => LoadInventory();
void LoadInventory() => Inventory.Load(SaveFileName);
void SaveInventory() => Inventory.Save(SaveFileName);
#if WUDATA
/// <summary>
/// If Bridge:Data extension is present in the project you can save
/// your entire inventory online rather than locally
/// </summary>
/// <param name="OnSuccess">(Optional) A function to trigger once upload has completed</param>
/// <param name="OnFailed">(Optional) A function to trigger if uploading the data failed for some reason</param>
void SaveInventoryOnline(Action<CML> OnSuccess = null, Action<CMLData> OnFailed = null)
{
var data = Encoder.Base64Encode(Inventory.ToString(false));
CMLData fields = new CMLData();
fields.Set(OnlineSaveFieldName, data);
WUData.UpdateCategory(SaveFileName, fields, response: OnSuccess, errorResponse: OnFailed);
}
/// <summary>
/// If Bridge:Data extension is present in the project you can load
/// your entire inventory back after saving it online.
/// Default behaviour on fail is to load the locally saved game
/// </summary>
/// <param name="OnFail">(Optional) A function to trigger if uploading the data failed for some reason</param>
void LoadInventoryFromOnline(Action<CMLData> OnFail = null) => WUData.FetchField(OnlineSaveFieldName, SaveFileName, ParseResponse, errorResponse: OnFail ?? HandleErrorWhileFetching);
/// <summary>
/// Upon successfully fetching the save game info from online it will be decoded
/// and restored back into Inventory
/// </summary>
/// <param name="response">The response received from the server</param>
void ParseResponse(CML response)
{
var results = string.Empty;
if (WUData.WUDataPro)
results = response.GetFirstNodeOfType(SaveFileName).String(OnlineSaveFieldName);
else
results = response[1].String(OnlineSaveFieldName);
results = Encoder.Base64Decode(results);
Inventory = new CML();
Inventory.Parse(results);
}
/// <summary>
/// Default behaviour when fetching data from online failed is to load the local game if present
/// </summary>
/// <param name="response"></param>
void HandleErrorWhileFetching(CMLData response)
{
Inventory = new CML();
LoadInventory();
}
#endif
#region Math on inventory items
/// <summary>
/// Add to the inventory item's value property. Create item if needed
/// </summary>
/// <param name="name">Item to add to inventory</param>
/// <param name="qty">Quantity to add</param>
/// <param name="meta">Optional additional info (Example: HP, Price, Rarity etc)</param>
static public void AddItems(string name, long qty, CMLData meta = null)
{
if (qty <= 0)
{
Debug.LogError("To deplete quantities, please use RemoveItems");
return;
}
var item = Inventory.GetFirstNodeOfType(name);
if (null == item)
{
Inventory.AddNode(name);
item = Inventory.Last;
}
item.Addl(qty, "value");
if (null != meta)
{
//remove any reference to "value" that might be set in the meta
meta.Remove();
//copy all the meta info over to the item
foreach (var kvp in meta.defined)
item.Set(kvp.Key, kvp.Value);
}
}
/// <summary>
/// Subtract items from the inventory
/// </summary>
/// <param name="name">Inventory item to subtract</param>
/// <param name="qty">How many to subtract</param>
/// <returns>NULL if <e>qty</e> <= 0, FALSE if negative and negative values are not allowed. TRUE upon successful subtraction </returns>
static public bool? RemoveItems(string name, long qty)
{
if (qty <= 0)
{
Debug.LogError("To add quantities, please use AddItems");
return null;
}
var item = Inventory.GetFirstNodeOfType(name);
if (null == item)
return null;
long newval = item.Long() - qty;
if (newval < 0 && !AllowNegativeValues)
return false;
if (!AllowNegativeValues && newval == 0)
Inventory.RemoveNode(item.ID);
else
item.Setl("value", newval);
return true;
}
#endregion
#region Math on meta values
/// <summary>
/// Add to the value of a meta field
/// </summary>
/// <param name="item_name">Item that has the meta to update (Ex: Longsword)</param>
/// <param name="meta_field">The meta field to update (Ex: ATT)</param>
/// <param name="qty">Amount to add to it's value</param>
/// <returns>NULL if the item doesn't exist or QTY <= 0.
/// Returns the new value on success</returns>
static public long? MetaMathAdd(string item_name, string meta_field, long qty)
{
if (qty <= 0)
{
Debug.LogError("To deplete quantities, please use MetaMathSubtract");
return null;
}
var item = Inventory.GetFirstNodeOfType(item_name);
if (null == item)
{
Debug.LogError("Item not found");
return null;
}
long result = item.Long(meta_field) + qty;
item.Setl(meta_field, result);
return result;
}
/// <summary>
/// Subtract from the value of a meta field
/// </summary>
/// <param name="item_name">Item that has the meta to update (Ex: Longsword)</param>
/// <param name="meta_field">The meta field to update (Ex: ATT)</param>
/// <param name="qty">Amount to subtract from it's value</param>
/// <param name="negative_to_zero">(Optional) If the result will be negative and invalid, force it to zero instead</param>
/// <returns>NULL if the item doesn't exist or QTY <= 0 or if negative values are not allowed
/// Returns the new value on success</returns>
static public long? MetaMathSubtract(string item_name, string meta_field, long qty, bool negative_to_zero = false)
{
if (qty <= 0)
{
Debug.LogError("To increase quantities, please use MetaMathAdd");
return null;
}
var item = Inventory.GetFirstNodeOfType(item_name);
if (null == item)
{
Debug.LogError("Item not found");
return null;
}
long result = item.Long(meta_field) - qty;
if (result < 0 && !AllowNegativeValues)
{
if (negative_to_zero)
{
result = 0;
}
else
{
Debug.LogError("Negative values are not allowed");
return null;
}
}
item.Setl(meta_field, result);
return result;
}
#endregion
#region Set meta values for an inventory item
/// <summary>
/// Set or create multiple meta fields and values for a specific inventory item
/// </summary>
/// <param name="item_name">The inventory item to update</param>
/// <param name="meta_fields">A list of fields and their values passed via a single CMLData object</param>
/// <returns>FALSE if item not found. True otherwise</returns>
static public bool SetMetaFields(string item_name, CMLData meta_fields)
{
var item = Inventory.GetFirstNodeOfType(item_name);
if (null == item)
{
Debug.LogError("Item not found");
return false;
}
foreach(var kvp in meta_fields.defined)
if (kvp.Key.ToLower() != "id")
item.Set(kvp.Key, kvp.Value);
return true;
}
/// <summary>
/// Set or create a single meta field and value for a specific inventory item
/// </summary>
/// <param name="item_name">The inventory item to update</param>
/// <param name="meta_field">The meta field to create or set</param>
/// <param name="meta_value">The meta field's raw value. Can be a string or number</param>
/// <returns>FALSE if item not found. True otherwise</returns>
static public bool SetMetaField(string item_name, string meta_field, string meta_value)
{
CMLData data = new CMLData();
data.Set(meta_field, meta_value);
return SetMetaFields(item_name, data);
}
#endregion
#region Test Inventory quantity
static public bool HasAtLeast(string name, int qty)
{
var indexer = Inventory.GetFirstNodeOfType(name);
if (null == indexer)
return qty == 0;
return indexer.Int() > qty;
}
static public bool DoesNotHave(string name, int qty)
{
var indexer = Inventory.GetFirstNodeOfType(name);
if (null == indexer)
return true;
return indexer.Int() < qty;
}
static public bool HasExactly(string name, int qty)
{
var indexer = Inventory.GetFirstNodeOfType(name);
if (null == indexer)
return qty == 0;
return indexer.Int() == qty;
}
#endregion
}
}