update helpers/location to 'frosted' ui
[carveJwlIkooP6JGAAIwe30JlM.git] / save.c
1 #include "skaterift.h"
2 #include "save.h"
3 #include "addon.h"
4 #include "vg/vg_msg.h"
5 #include "vg/vg_log.h"
6 #include "vg/vg_loader.h"
7 #include "world.h"
8 #include "player.h"
9
10 static const char *str_skaterift_main_save = "save.bkv";
11 static f64 last_autosave;
12
13 void savedata_file_write( savedata_file *file )
14 {
15 savedata_file *sav = file;
16 FILE *fp = fopen( sav->path, "wb" );
17 if( fp ){
18 fwrite( sav->buf, sav->len, 1, fp );
19 fclose( fp );
20 vg_success( "savedata written to '%s'\n", sav->path );
21 }
22 else {
23 vg_error( "Error writing savedata (%s)\n", sav->path );
24 }
25 }
26
27 void savedata_group_write( savedata_group *group )
28 {
29 for( u32 i=0; i<group->file_count; i++ ){
30 savedata_file_write( &group->files[i] );
31 }
32 }
33
34 void savedata_file_read( savedata_file *file )
35 {
36 FILE *fp = fopen( file->path, "rb" );
37 if( fp ){
38 file->len = fread( file->buf, 1, sizeof(file->buf), fp );
39 fclose( fp );
40 }
41 else{
42 file->len = 0;
43 vg_warn( "Error reading savedata (%s)\n", file->path );
44 }
45 }
46
47 static void skaterift_write_addon_alias( vg_msg *msg, const char *key,
48 addon_alias *alias ){
49 if( alias->workshop_id )
50 vg_msg_wkvnum( msg, key, k_vg_msg_u64, 1, &alias->workshop_id );
51 else
52 vg_msg_wkvstr( msg, key, alias->foldername );
53 }
54
55 static void skaterift_write_viewslot( vg_msg *msg, const char *key,
56 enum addon_type type, u16 cache_id ){
57 if( !cache_id ) return;
58
59 struct addon_cache *cache = &addon_system.cache[type];
60 addon_cache_entry *entry = vg_pool_item( &cache->pool, cache_id );
61 addon_reg *reg = entry->reg_ptr;
62
63 if( reg )
64 skaterift_write_addon_alias( msg, key, &reg->alias );
65 }
66
67 void skaterift_read_addon_alias( vg_msg *msg, const char *key,
68 enum addon_type type,
69 addon_alias *alias )
70 {
71 alias->foldername[0] = '\0';
72 alias->workshop_id = 0;
73 alias->type = type;
74
75 vg_msg_cmd kv;
76 if( vg_msg_getkvcmd( msg, key, &kv ) ){
77 if( kv.code == k_vg_msg_kvstring ){
78 vg_strncpy( kv.value, alias->foldername, sizeof(alias->foldername),
79 k_strncpy_allow_cutoff );
80 }
81 else
82 vg_msg_cast( kv.value, kv.code, &alias->workshop_id, k_vg_msg_u64 );
83 }
84 }
85
86 static void skaterift_populate_world_savedata( savedata_file *file,
87 enum world_purpose which ){
88 file->path[0] = '\0';
89 file->len = 0;
90 addon_reg *reg = world_static.instance_addons[ which ];
91
92 if( !reg ){
93 vg_error( "Tried to save unspecified world (reg was null)\n" );
94 return;
95 }
96
97 skaterift_world_get_save_path( which, file->path );
98
99 vg_msg sav;
100 vg_msg_init( &sav, file->buf, sizeof(file->buf) );
101
102 world_instance *instance = &world_static.instances[which];
103 world_entity_serialize( instance, &sav );
104
105 vg_msg_frame( &sav, "player" );
106 {
107 vg_msg_wkvnum( &sav, "position", k_vg_msg_float|k_vg_msg_32b, 3,
108 (which == world_static.active_instance)?
109 localplayer.rb.co:
110 instance->player_co );
111 }
112 vg_msg_end_frame( &sav );
113
114 file->len = sav.cur.co;
115 }
116
117 static void skaterift_populate_main_savedata( savedata_file *file )
118 {
119 strcpy( file->path, str_skaterift_main_save );
120
121 vg_msg sav;
122 vg_msg_init( &sav, file->buf, sizeof(file->buf) );
123 vg_msg_wkvnum( &sav, "ach", k_vg_msg_u32, 1, &skaterift.achievements );
124
125 vg_msg_frame( &sav, "player" );
126 {
127 skaterift_write_viewslot( &sav, "board", k_addon_type_board,
128 localplayer.board_view_slot );
129 skaterift_write_viewslot( &sav, "playermodel", k_addon_type_player,
130 localplayer.playermodel_view_slot );
131 }
132 vg_msg_end_frame( &sav );
133
134 file->len = sav.cur.co;
135 }
136
137 void skaterift_read_main_savedata( savedata_file *file )
138 {
139 strcpy( file->path, str_skaterift_main_save );
140 savedata_file_read( file );
141 }
142
143 int skaterift_autosave( int async )
144 {
145 if( async )
146 if( !vg_loader_availible() ) return 0;
147
148 u32 save_files = 2;
149 if( world_static.instances[k_world_purpose_client].status
150 == k_world_status_loaded ){
151 save_files ++;
152 }
153
154 vg_linear_clear( vg_async.buffer );
155 u32 size = sizeof(savedata_group) + sizeof(savedata_file) * save_files;
156
157 savedata_group *group;
158 if( async ){
159 size = vg_align8( size );
160 group = vg_linear_alloc( vg_async.buffer, size );
161 }
162 else
163 group = alloca( size );
164
165 group->file_count = save_files;
166 skaterift_populate_main_savedata( &group->files[0] );
167 skaterift_populate_world_savedata( &group->files[1], k_world_purpose_hub );
168
169 if( world_static.instances[ k_world_purpose_client ].status
170 == k_world_status_loaded ){
171 skaterift_populate_world_savedata( &group->files[2],
172 k_world_purpose_client );
173 }
174
175 if( async )
176 vg_loader_start( (void *)savedata_group_write, group );
177 else
178 savedata_group_write( group );
179
180 return 1;
181 }
182
183 void skaterift_autosave_synchronous(void)
184 {
185 skaterift_autosave(0);
186 }
187
188 void skaterift_autosave_update(void)
189 {
190 if( vg.time - last_autosave > 20.0 ){
191 if( skaterift_autosave(1) ){
192 last_autosave = vg.time;
193 }
194 }
195 }