Skip to content

Commit 832f013

Browse files
TechnikTilAbnormalPoof
authored andcommitted
Add Save Data Options, also allow user to load and save with Newgrounds Save Slots.
1 parent e8d41c9 commit 832f013

5 files changed

Lines changed: 255 additions & 28 deletions

File tree

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package funkin.api.newgrounds;
2+
3+
import io.newgrounds.utils.SaveSlotList;
4+
import io.newgrounds.objects.SaveSlot;
5+
import io.newgrounds.Call.CallError;
6+
import io.newgrounds.objects.events.Outcome;
7+
import funkin.save.Save;
8+
9+
@:nullSafety
10+
@:access(funkin.save.Save)
11+
class NGSaveSlot
12+
{
13+
public static var instance(get, never):NGSaveSlot;
14+
static var _instance:Null<NGSaveSlot> = null;
15+
16+
static function get_instance():NGSaveSlot
17+
{
18+
if (_instance == null)
19+
{
20+
return loadInstance();
21+
}
22+
return _instance;
23+
}
24+
25+
public static function loadInstance():NGSaveSlot
26+
{
27+
trace("[NEWGROUNDS] Loading save slot...");
28+
29+
var loadedSave:NGSaveSlot = loadSlot(Save.BASE_SAVE_SLOT);
30+
if (_instance == null) _instance = loadedSave;
31+
32+
return loadedSave;
33+
}
34+
35+
static function loadSlot(slot:Int):NGSaveSlot
36+
{
37+
trace('[NEWGROUNDS] Loading save slot from ID $slot');
38+
39+
var saveSlot:Null<SaveSlot> = NewgroundsClient.instance.saveSlots?.getById(slot);
40+
41+
if (saveSlot != null && !saveSlot.isEmpty())
42+
{
43+
// Precache Slots
44+
saveSlot.load(function(outcome:SaveSlotOutcome):Void {
45+
switch (outcome)
46+
{
47+
case SUCCESS(value):
48+
trace('[NEWGROUNDS] Loaded save slot with the ID of ${saveSlot.id}!');
49+
#if FEATURE_DEBUG_FUNCTIONS
50+
trace('Save Slot Data:');
51+
trace(value);
52+
#end
53+
case FAIL(error):
54+
trace('[NEWGROUNDS] Failed to load save slot with the ID of ${saveSlot.id}!');
55+
trace(error);
56+
}
57+
});
58+
}
59+
60+
var saveSlotObj:NGSaveSlot = new NGSaveSlot(saveSlot);
61+
return saveSlotObj;
62+
}
63+
64+
public var ngSaveSlot:Null<SaveSlot> = null;
65+
66+
public function new(?ngSaveSlot:Null<SaveSlot>)
67+
{
68+
this.ngSaveSlot = ngSaveSlot;
69+
70+
#if FLX_DEBUG
71+
FlxG.console.registerClass(NGSaveSlot);
72+
FlxG.console.registerClass(Save);
73+
#end
74+
}
75+
76+
/**
77+
* Saves `data` to the newgrounds save slot.
78+
* @param data The raw save data.
79+
*/
80+
public function save(data:RawSaveData):Void
81+
{
82+
var encodedData:String = haxe.Serializer.run(data);
83+
84+
ngSaveSlot?.save(encodedData, function(outcome:Outcome<CallError>) {
85+
switch (outcome)
86+
{
87+
case SUCCESS:
88+
trace('[NEWGROUNDS] Successfully saved save data to save slot!');
89+
case FAIL(error):
90+
trace('[NEWGROUNDS] Failed to save data to save slot!');
91+
trace(error);
92+
}
93+
});
94+
}
95+
96+
public function load():Dynamic
97+
{
98+
var encodedData:Null<String> = ngSaveSlot?.contents;
99+
100+
if (encodedData == null) return null;
101+
102+
return haxe.Unserializer.run(encodedData);
103+
}
104+
}

source/funkin/api/newgrounds/NewgroundsClient.hx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import io.newgrounds.NGLite.LoginOutcome;
1111
import io.newgrounds.NGLite.LoginFail;
1212
import io.newgrounds.objects.events.Outcome;
1313
import io.newgrounds.utils.MedalList;
14+
import io.newgrounds.utils.SaveSlotList;
1415
import io.newgrounds.utils.ScoreBoardList;
1516
import io.newgrounds.objects.User;
1617

@@ -34,6 +35,7 @@ class NewgroundsClient
3435
public var user(get, never):Null<User>;
3536
public var medals(get, never):Null<MedalList>;
3637
public var leaderboards(get, never):Null<ScoreBoardList>;
38+
public var saveSlots(get, never):Null<SaveSlotList>;
3739

3840
private function new()
3941
{
@@ -244,6 +246,8 @@ class NewgroundsClient
244246

245247
trace('[NEWGROUNDS] Submitting leaderboard request...');
246248
NG.core.scoreBoards.loadList(onFetchedLeaderboards);
249+
trace('[NEWGROUNDS] Submitting save slot request...');
250+
NG.core.saveSlots.loadList(onFetchedSaveSlots);
247251
}
248252

249253
function onLoginFailed(result:LoginFail):Void
@@ -309,6 +313,13 @@ class NewgroundsClient
309313
// trace(funkin.api.newgrounds.Leaderboards.listLeaderboardData());
310314
}
311315

316+
function onFetchedSaveSlots(outcome:Outcome<CallError>):Void
317+
{
318+
trace('[NEWGROUNDS] Fetched save slots!');
319+
320+
NGSaveSlot.instance.load();
321+
}
322+
312323
function get_user():Null<User>
313324
{
314325
if (NG.core == null || !this.isLoggedIn()) return null;
@@ -327,6 +338,12 @@ class NewgroundsClient
327338
return NG.core.scoreBoards;
328339
}
329340

341+
function get_saveSlots():Null<SaveSlotList>
342+
{
343+
if (NG.core == null || !this.isLoggedIn()) return null;
344+
return NG.core.saveSlots;
345+
}
346+
330347
static function getSessionId():Null<String>
331348
{
332349
#if js

source/funkin/save/Save.hx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1356,6 +1356,23 @@ class Save
13561356
{
13571357
FileUtil.saveFile(haxe.io.Bytes.ofString(this.serialize()), [FileUtil.FILE_FILTER_JSON], null, null, './save.json', 'Write save data as JSON...');
13581358
}
1359+
public function saveToNewgrounds():Void
1360+
{
1361+
trace('[SAVE] Saving Save Data to Newgrounds...');
1362+
funkin.api.newgrounds.NGSaveSlot.instance.save(data);
1363+
}
1364+
1365+
public function loadFromNewgrounds():Void
1366+
{
1367+
trace('[SAVE] Loading Save Data from Newgrounds...');
1368+
var data = funkin.api.newgrounds.NGSaveSlot.instance.load();
1369+
1370+
if (data == null) return;
1371+
1372+
var gameSave = SaveDataMigrator.migrate(data);
1373+
FlxG.save.erase();
1374+
FlxG.save.mergeData(gameSave.data, true);
1375+
}
13591376
}
13601377

13611378
/**

source/funkin/ui/options/OptionsState.hx

Lines changed: 6 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ class OptionsState extends MusicBeatState
7575
#if FEATURE_LAG_ADJUSTMENT
7676
var offsets:OffsetMenu = optionsCodex.addPage(Offsets, new OffsetMenu());
7777
#end
78+
var saveData:SaveDataMenu = optionsCodex.addPage(SaveData, new SaveDataMenu());
7879

7980
if (options.hasMultipleOptions())
8081
{
@@ -84,6 +85,7 @@ class OptionsState extends MusicBeatState
8485
#if FEATURE_LAG_ADJUSTMENT
8586
offsets.onExit.add(exitOffsets);
8687
#end
88+
saveData.onExit.add(optionsCodex.switchPage.bind(Options));
8789
}
8890
else
8991
{
@@ -227,8 +229,9 @@ class OptionsMenu extends Page<OptionsMenuPageName>
227229
});
228230
}
229231
#end
230-
createItem("CLEAR SAVE DATA", function() {
231-
promptClearSaveData();
232+
233+
createItem("SAVE DATA OPTIONS", function() {
234+
codex.switchPage(SaveData);
232235
});
233236
#if NO_FEATURE_TOUCH_CONTROLS
234237
createItem("EXIT", exit);
@@ -277,7 +280,6 @@ class OptionsMenu extends Page<OptionsMenuPageName>
277280

278281
override function update(elapsed:Float):Void
279282
{
280-
enabled = (prompt == null);
281283
#if FEATURE_TOUCH_CONTROLS
282284
backButton.active = (!goingBack) ? !items.busy : true;
283285
#end
@@ -298,31 +300,6 @@ class OptionsMenu extends Page<OptionsMenuPageName>
298300
{
299301
return items.length > 2;
300302
}
301-
302-
var prompt:Prompt;
303-
304-
function promptClearSaveData():Void
305-
{
306-
if (prompt != null) return;
307-
prompt = new Prompt("This will delete
308-
\nALL your save data.
309-
\nAre you sure?
310-
", Custom("Delete", "Cancel"));
311-
prompt.create();
312-
prompt.createBgFromMargin(100, 0xFFFAFD6D);
313-
prompt.back.scrollFactor.set(0, 0);
314-
add(prompt);
315-
prompt.onYes = function() {
316-
// Clear the save data.
317-
funkin.save.Save.clearData();
318-
FlxG.switchState(() -> new funkin.InitState());
319-
};
320-
prompt.onNo = function() {
321-
prompt.close();
322-
prompt.destroy();
323-
prompt = null;
324-
};
325-
}
326303
}
327304

328305
enum abstract OptionsMenuPageName(String) to PageName
@@ -333,4 +310,5 @@ enum abstract OptionsMenuPageName(String) to PageName
333310
var Mods = "mods";
334311
var Preferences = "preferences";
335312
var Offsets = "offsets";
313+
var SaveData = "saveData";
336314
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
package funkin.ui.options;
2+
3+
#if FEATURE_NEWGROUNDS
4+
import funkin.api.newgrounds.NewgroundsClient;
5+
#end
6+
import funkin.ui.Page.PageName;
7+
8+
/**
9+
* Our default Page when we enter the OptionsState, a bit of the root
10+
*/
11+
class SaveDataMenu extends Page<OptionsState.OptionsMenuPageName>
12+
{
13+
var items:TextMenuList;
14+
15+
public function new()
16+
{
17+
super();
18+
19+
add(items = new TextMenuList());
20+
21+
#if FEATURE_NEWGROUNDS
22+
if (NewgroundsClient.instance.isLoggedIn())
23+
{
24+
createItem("LOAD FROM NEWGROUNDS", function() {
25+
openConfirmPrompt("This will overwrite
26+
\nALL your save data.
27+
\nAre you sure?
28+
", "Overwrite", function() {
29+
funkin.save.Save.instance.loadFromNewgrounds();
30+
31+
FlxG.switchState(() -> new funkin.InitState());
32+
});
33+
});
34+
35+
createItem("SAVE TO NEWGROUNDS", function() {
36+
openConfirmPrompt("This will overwrite
37+
\nALL save data saved
38+
\non Newgrounds.
39+
\nAre you sure?
40+
", "Overwrite", function() {
41+
funkin.save.Save.instance.saveToNewgrounds();
42+
});
43+
});
44+
}
45+
#end
46+
47+
createItem("CLEAR SAVE DATA", function() {
48+
openConfirmPrompt("This will delete
49+
\nALL your save data.
50+
\nAre you sure?
51+
", "Delete", function() {
52+
// Clear the save data.
53+
funkin.save.Save.clearData();
54+
55+
FlxG.switchState(() -> new funkin.InitState());
56+
});
57+
});
58+
59+
createItem("EXIT", exit);
60+
}
61+
62+
function createItem(name:String, callback:Void->Void, fireInstantly = false)
63+
{
64+
var item = items.createItem(0, 100 + items.length * 100, name, BOLD, callback);
65+
item.fireInstantly = fireInstantly;
66+
item.screenCenter(X);
67+
return item;
68+
}
69+
70+
override function update(elapsed:Float)
71+
{
72+
enabled = (prompt == null);
73+
super.update(elapsed);
74+
}
75+
76+
override function set_enabled(value:Bool)
77+
{
78+
items.enabled = value;
79+
return super.set_enabled(value);
80+
}
81+
82+
var prompt:Prompt;
83+
84+
function openConfirmPrompt(text:String, yesText:String, onYes:Void->Void):Void
85+
{
86+
if (prompt != null) return;
87+
88+
prompt = new Prompt(text, Custom(yesText, "Cancel"));
89+
prompt.create();
90+
prompt.createBgFromMargin(100, 0xFFFAFD6D);
91+
prompt.back.scrollFactor.set(0, 0);
92+
add(prompt);
93+
94+
prompt.onYes = function() {
95+
onYes();
96+
97+
if (prompt != null)
98+
{
99+
prompt.close();
100+
prompt.destroy();
101+
prompt = null;
102+
}
103+
};
104+
105+
prompt.onNo = function() {
106+
prompt.close();
107+
prompt.destroy();
108+
prompt = null;
109+
}
110+
}
111+
}

0 commit comments

Comments
 (0)