Latest compatible version of Classicube from the original GitHub repository (https://github.com/ClassiCube/ClassiCube) that can be compiled on Classicube for PowerMac PPC running Mac OS X 10.4.

This commit is contained in:
Andrei Alexandru
2025-12-17 13:17:57 +02:00
commit c71492f846
1248 changed files with 422858 additions and 0 deletions

228
src/Options.c Normal file
View File

@@ -0,0 +1,228 @@
#include "Options.h"
#include "String.h"
#include "ExtMath.h"
#include "Platform.h"
#include "Stream.h"
#include "Errors.h"
#include "Utils.h"
#include "Logger.h"
#include "PackedCol.h"
CC_BIG_VAR struct StringsBuffer Options;
static CC_BIG_VAR struct StringsBuffer changedOpts;
cc_result Options_LoadResult;
static cc_bool savingPaused;
#if defined CC_BUILD_WEB || defined CC_BUILD_MOBILE || defined CC_BUILD_CONSOLE
#define OPTIONS_SAVE_IMMEDIATELY
#endif
void Options_Free(void) {
StringsBuffer_Clear(&Options);
StringsBuffer_Clear(&changedOpts);
}
static cc_bool HasChanged(const cc_string* key) {
cc_string entry;
int i;
for (i = 0; i < changedOpts.count; i++) {
entry = StringsBuffer_UNSAFE_Get(&changedOpts, i);
if (String_CaselessEquals(&entry, key)) return true;
}
return false;
}
static cc_bool Options_LoadFilter(const cc_string* entry) {
cc_string key, value;
String_UNSAFE_Separate(entry, '=', &key, &value);
return !HasChanged(&key);
}
void Options_Load(void) {
/* Increase from max 512 to 2048 per entry */
StringsBuffer_SetLengthBits(&Options, 11);
Options_LoadResult = EntryList_Load(&Options, "options-default.txt", '=', NULL);
Options_LoadResult = EntryList_Load(&Options, "options.txt", '=', NULL);
}
void Options_Reload(void) {
cc_string entry, key, value;
int i;
/* Reset all the unchanged options */
for (i = Options.count - 1; i >= 0; i--) {
entry = StringsBuffer_UNSAFE_Get(&Options, i);
String_UNSAFE_Separate(&entry, '=', &key, &value);
if (HasChanged(&key)) continue;
StringsBuffer_Remove(&Options, i);
}
/* Load only options which have not changed */
Options_LoadResult = EntryList_Load(&Options, "options.txt", '=', Options_LoadFilter);
}
static void SaveOptions(void) {
EntryList_Save(&Options, "options.txt");
StringsBuffer_Clear(&changedOpts);
}
void Options_SaveIfChanged(void) {
if (!changedOpts.count) return;
Options_Reload();
SaveOptions();
}
void Options_PauseSaving(void) { savingPaused = true; }
void Options_ResumeSaving(void) {
savingPaused = false;
#if defined OPTIONS_SAVE_IMMEDIATELY
SaveOptions();
#endif
}
cc_bool Options_UNSAFE_Get(const char* keyRaw, cc_string* value) {
int idx;
cc_string key = String_FromReadonly(keyRaw);
*value = EntryList_UNSAFE_Get(&Options, &key, '=');
if (value->length) return true;
/* Fallback to without '-' (e.g. "hacks-fly" to "fly") */
/* Needed for some very old options.txt files */
idx = String_IndexOf(&key, '-');
if (idx == -1) return false;
key = String_UNSAFE_SubstringAt(&key, idx + 1);
*value = EntryList_UNSAFE_Get(&Options, &key, '=');
return value->length > 0;
}
void Options_Get(const char* key, cc_string* value, const char* defValue) {
cc_string str;
Options_UNSAFE_Get(key, &str);
value->length = 0;
if (str.length) {
String_AppendString(value, &str);
} else {
String_AppendConst(value, defValue);
}
}
int Options_GetInt(const char* key, int min, int max, int defValue) {
cc_string str;
int value;
if (!Options_UNSAFE_Get(key, &str)) return defValue;
if (!Convert_ParseInt(&str, &value)) return defValue;
Math_Clamp(value, min, max);
return value;
}
cc_bool Options_GetBool(const char* key, cc_bool defValue) {
cc_string str;
cc_bool value;
if (!Options_UNSAFE_Get(key, &str)) return defValue;
if (!Convert_ParseBool(&str, &value)) return defValue;
return value;
}
float Options_GetFloat(const char* key, float min, float max, float defValue) {
cc_string str;
float value;
if (!Options_UNSAFE_Get(key, &str)) return defValue;
if (!Convert_ParseFloat(&str, &value)) return defValue;
Math_Clamp(value, min, max);
return value;
}
int Options_GetEnum(const char* key, int defValue, const char* const* names, int namesCount) {
cc_string str;
if (!Options_UNSAFE_Get(key, &str)) return defValue;
return Utils_ParseEnum(&str, defValue, names, namesCount);
}
cc_bool Options_GetColor(const char* key, cc_uint8* rgb) {
cc_string value, parts[3];
if (!Options_UNSAFE_Get(key, &value)) return false;
if (PackedCol_TryParseHex(&value, rgb)) return true;
/* Try parsing as R,G,B instead */
return String_UNSAFE_Split(&value, ',', parts, 3)
&& Convert_ParseUInt8(&parts[0], &rgb[0])
&& Convert_ParseUInt8(&parts[1], &rgb[1])
&& Convert_ParseUInt8(&parts[2], &rgb[2]);
}
void Options_SetBool(const char* keyRaw, cc_bool value) {
static const cc_string str_true = String_FromConst("True");
static const cc_string str_false = String_FromConst("False");
Options_Set(keyRaw, value ? &str_true : &str_false);
}
void Options_SetInt(const char* keyRaw, int value) {
cc_string str; char strBuffer[STRING_INT_CHARS];
String_InitArray(str, strBuffer);
String_AppendInt(&str, value);
Options_Set(keyRaw, &str);
}
void Options_Set(const char* keyRaw, const cc_string* value) {
cc_string key = String_FromReadonly(keyRaw);
Options_SetString(&key, value);
}
void Options_SetString(const cc_string* key, const cc_string* value) {
if (!value || !value->length) {
if (!EntryList_Remove(&Options, key, '=')) return;
} else {
EntryList_Set(&Options, key, value, '=');
}
#if defined OPTIONS_SAVE_IMMEDIATELY
if (!savingPaused) SaveOptions();
#endif
if (HasChanged(key)) return;
StringsBuffer_Add(&changedOpts, key);
}
void Options_SetSecure(const char* opt, const cc_string* src) {
char data[2000], encData[1500+1];
cc_string tmp, enc;
cc_result res;
if (!src->length) return;
String_InitArray(enc, encData);
res = Platform_Encrypt(src->buffer, src->length, &enc);
if (res) { Platform_Log2("Error %e encrypting option %c", &res, opt); return; }
/* base64 encode the data, as user might edit options.txt with a text editor */
if (enc.length > 1500) Process_Abort("too large to base64");
tmp.buffer = data;
tmp.length = Convert_ToBase64(enc.buffer, enc.length, data);
tmp.capacity = tmp.length;
Options_Set(opt, &tmp);
}
void Options_GetSecure(const char* opt, cc_string* dst) {
cc_uint8 data[1500];
int dataLen;
cc_string raw;
cc_result res;
Options_UNSAFE_Get(opt, &raw);
if (!raw.length) return;
if (raw.length > 2000) Process_Abort("too large to base64");
dataLen = Convert_FromBase64(raw.buffer, raw.length, data);
res = Platform_Decrypt(data, dataLen, dst);
if (res) Platform_Log2("Error %e decrypting option %c", &res, opt);
}