mac replay preferences

This commit is contained in:
2024-07-29 21:07:29 -05:00
committed by Celtic Minstrel
parent 49c62aa985
commit afca0dc85d
2 changed files with 87 additions and 18 deletions

View File

@@ -286,7 +286,6 @@ void init_boe(int argc, char* argv[]) {
init_menubar(); // Do this first of all because otherwise a default File and Window menu will be seen
#endif
// TODO preferences need to be recorded in the action log for deterministic replay
sync_prefs();
init_shaders();
init_tiling();

View File

@@ -11,6 +11,8 @@
#include <unordered_map>
#include "replay.hpp"
#include <sstream>
#include <boost/lexical_cast.hpp>
#include "ticpp.h"
//static const CFStringRef prefsID = CFSTR("com.spidweb.bladesofexile");
typedef NS_ENUM(NSInteger) {
@@ -40,52 +42,62 @@ NSDictionary* prefsToRecord = @{
@"UIScaleMap": @(kFloat)
};
bool prefsLoaded = false;
static NSString* convertKey(std::string keypath) {
NSString* key = [NSString stringWithCString: keypath.c_str() encoding: NSASCIIStringEncoding];
return key;
}
NSUserDefaults* getCurrentDefaults() {
if(replaying){
return replayUserDefaults;
}else{
return [NSUserDefaults standardUserDefaults];
}
}
void set_pref(std::string keypath, bool value) {
[[NSUserDefaults standardUserDefaults] setBool: value forKey: convertKey(keypath)];
[getCurrentDefaults() setBool: value forKey: convertKey(keypath)];
}
bool get_bool_pref(std::string keypath, bool fallback) {
id val = [[NSUserDefaults standardUserDefaults] objectForKey: convertKey(keypath)];
id val = [getCurrentDefaults() objectForKey: convertKey(keypath)];
if([val isKindOfClass: [NSNumber class]]) return [val boolValue];
return fallback;
}
void set_pref(std::string keypath, int value) {
[[NSUserDefaults standardUserDefaults] setInteger: value forKey: convertKey(keypath)];
[getCurrentDefaults() setInteger: value forKey: convertKey(keypath)];
}
int get_int_pref(std::string keypath, int fallback) {
id val = [[NSUserDefaults standardUserDefaults] objectForKey: convertKey(keypath)];
id val = [getCurrentDefaults() objectForKey: convertKey(keypath)];
if([val isKindOfClass: [NSNumber class]]) return [val intValue];
return fallback;
}
void set_pref(std::string keypath, double value) {
[[NSUserDefaults standardUserDefaults] setDouble: value forKey: convertKey(keypath)];
[getCurrentDefaults() setDouble: value forKey: convertKey(keypath)];
}
double get_float_pref(std::string keypath, double fallback) {
id val = [[NSUserDefaults standardUserDefaults] objectForKey: convertKey(keypath)];
id val = [getCurrentDefaults() objectForKey: convertKey(keypath)];
if([val isKindOfClass: [NSNumber class]]) return [val doubleValue];
return fallback;
}
void append_iarray_pref(std::string keypath, int value) {
NSString* key = convertKey(keypath);
NSArray* list = [[NSUserDefaults standardUserDefaults] arrayForKey: key];
NSArray* list = [getCurrentDefaults() arrayForKey: key];
NSNumber* num = [NSNumber numberWithInt: value];
if(list == nil)
[[NSUserDefaults standardUserDefaults] setObject: [NSArray arrayWithObject: num] forKey: key] ;
else [[NSUserDefaults standardUserDefaults] setObject: [list arrayByAddingObject: num] forKey: key];
[getCurrentDefaults() setObject: [NSArray arrayWithObject: num] forKey: key] ;
else [getCurrentDefaults() setObject: [list arrayByAddingObject: num] forKey: key];
}
std::vector<int> get_iarray_pref(std::string keypath) {
NSArray* list = [[NSUserDefaults standardUserDefaults] arrayForKey: convertKey(keypath)];
NSArray* list = [getCurrentDefaults() arrayForKey: convertKey(keypath)];
if(list == nil) return {};
std::vector<int> result;
for(size_t i = 0; i < [list count]; i++)
@@ -94,11 +106,65 @@ std::vector<int> get_iarray_pref(std::string keypath) {
}
void clear_pref(std::string keypath) {
[[NSUserDefaults standardUserDefaults] setValue: nil forKey: convertKey(keypath)];
[getCurrentDefaults() setValue: nil forKey: convertKey(keypath)];
}
// When replaying, load the preferences from the action log into a
// non-synchronized UserDefaults object
static bool load_prefs(std::istream& istream) {
std::string line;
while(std::getline(istream, line)) {
if(!istream) {
perror("Error reading preferences");
return false;
}
if(line[0] == '#') continue;
int eq = line.find_first_of('=');
if(eq == std::string::npos) {
printf("Error reading preferences: line is not a comment and lacks an = sign:\n\t%s\n", line.c_str());
return false;
}
int key_end = line.find_last_not_of(' ', eq - 1), val_beg = line.find_first_not_of(' ', eq + 1);
if(val_beg == std::string::npos) {
printf("Error reading preferences: line is missing value:\n\t%s\n", line.c_str());
return false;
}
if(key_end == std::string::npos) {
printf("Error reading preferences: line is missing key:\n\t%s\n", line.c_str());
return false;
}
std::string key = line.substr(0, key_end + 1), val = line.substr(val_beg);
NSInteger type = [prefsToRecord[[NSString stringWithUTF8String: key.c_str()]] integerValue];
switch((int)type) {
case kBool:
if(val == "true") set_pref(key, true);
else if(val == "false") set_pref(key, false);
break;
case kIArray:
if(val[0] == '[') {
int arr_end = val.find_first_of(']');
std::istringstream arr_vals(val.substr(1, arr_end - 1));
int i = 0;
clear_pref(key);
while(arr_vals >> i) append_iarray_pref(key, i);
}
break;
case kFloat:
set_pref(key, boost::lexical_cast<double>(val));
break;
case kInt:
set_pref(key, boost::lexical_cast<int>(val));
break;
}
}
prefsLoaded = true;
return true;
}
bool sync_prefs() {
if(recording){
if(recording && !prefsLoaded){
std::ostringstream prefs_recording;
NSUserDefaults* standard = [NSUserDefaults standardUserDefaults];
for(id pref in prefsToRecord) {
@@ -108,7 +174,7 @@ bool sync_prefs() {
NSInteger type = [prefsToRecord[pref] integerValue];
bool bvalue;
int ivalue;
float fvalue;
double fvalue;
int count;
int c;
NSArray* arrayValue;
@@ -139,16 +205,20 @@ bool sync_prefs() {
prefs_recording << "]";
break;
case kFloat:
fvalue = (float)[standard floatForKey: pref];
fvalue = (double)[standard doubleForKey: pref];
prefs_recording << fvalue;
break;
}
prefs_recording << std::endl;
}
}
record_action("sync_prefs", prefs_recording.str());
}else if(replaying){
replayUserDefaults = [NSUserDefaults init];
record_action("load_prefs", prefs_recording.str());
prefsLoaded = true;
}else if(replaying && !prefsLoaded){
replayUserDefaults = [[NSUserDefaults alloc] init];
Element& prefs_action = pop_next_action("load_prefs");
std::istringstream istream(prefs_action.GetText());
return load_prefs(istream);
}
return [[NSUserDefaults standardUserDefaults] synchronize];
}