mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-29 00:55:41 +00:00
dep/rcheevos: Update to 8a717b1
This commit is contained in:
parent
a4127aa2ea
commit
f62a3ffbfa
|
@ -7,7 +7,7 @@ end_of_line = crlf
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
|
|
||||||
# latin1 is a type of ASCII, should work with mbcs
|
# latin1 is a type of ASCII, should work with mbcs
|
||||||
[*.{h,cpp}]
|
[*.{h,c,cpp}]
|
||||||
charset = latin1
|
charset = latin1
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|
|
@ -1,3 +1,100 @@
|
||||||
|
# v11.0.0
|
||||||
|
* add rc_client_t and related functions
|
||||||
|
* add RC_MEMSIZE_FLOAT_BE
|
||||||
|
* add Game Pak SRAM to GBA memory map
|
||||||
|
* add hash method for Super Cassettevision
|
||||||
|
* add PSP to potential consoles for chd iterator
|
||||||
|
* add content_type to rc_api_request_t for client to pass to server
|
||||||
|
* add rc_api_process_X_server_response methods to pass status_code and body_length to response processing functions
|
||||||
|
* add additional error codes to rc_api_process_login_response: RC_INVALID_CREDENTIALS, RC_EXPIRED_TOKEN, RC_ACCESS_DENIED
|
||||||
|
* rc_api_start_session now also returns unlocks without having to explicitly call rc_api_fetch_user_unlocks separately
|
||||||
|
* add validation warning for using hit target of 1 on ResetIf condition
|
||||||
|
* move compat.c up a directory and rename to rc_compat.c as it's shared by all subfolders
|
||||||
|
* move rc_libretro.c up a directory as it uses files from all subfolders
|
||||||
|
* convert loosely sized types to strongly sized types (unsigned -> uint32t, unsigned char -> uint8_t, etc)
|
||||||
|
|
||||||
|
# v10.7.1
|
||||||
|
* add rc_runtime_alloc
|
||||||
|
* add rc_libretro_memory_find_avail
|
||||||
|
* extract nginx errors from HTML returned for JSON endpoints
|
||||||
|
* fix real address for 32X extension RAM
|
||||||
|
* fix crash attempting to calculate gamecube hash for non-existent file
|
||||||
|
|
||||||
|
# v10.7.0
|
||||||
|
* add hash method and memory map for Gamecube
|
||||||
|
* add console enum, hash method, and memory map for DSi
|
||||||
|
* add console enum, hash method, and memory map for TI-83
|
||||||
|
* add console enum, hash method, and memory map for Uzebox
|
||||||
|
* add constant for rcheevos version; include in start session server API call
|
||||||
|
* fix SubSource calculations using float values
|
||||||
|
* fix game identification for homebrew Jaguar CD games
|
||||||
|
* fix game identification for CD with many files at root directory
|
||||||
|
* address _CRT_SECURE_NO_WARNINGS warnings
|
||||||
|
|
||||||
|
# v10.6.0
|
||||||
|
* add RC_RUNTIME_EVENT_ACHIEVEMENT_PROGRESS_UPDATED
|
||||||
|
* use optimized comparators for most common condition logic
|
||||||
|
* fix game identification of psx ISOs that have extra slashes in their boot path
|
||||||
|
* fix game identification of ndd files
|
||||||
|
|
||||||
|
# v10.5.0
|
||||||
|
* add RC_MEMSIZE_MBF32_LE
|
||||||
|
* add RC_OPERATOR_XOR
|
||||||
|
* add RC_CONSOLE_ATARI_JAGUAR_CD and hash/memory map for Atari Jaguar CD
|
||||||
|
* add RC_CONSOLE_ARCADIA_2001 and hash/memory map for Arcadia 2001
|
||||||
|
* add RC_CONSOLE_INTERTON_VC_4000 and hash/memory map for Interton VC 4000
|
||||||
|
* add RC_CONSOLE_ELEKTOR_TV_GAMES_COMPUTER and hash/memory map for Elektor TV Games Computer
|
||||||
|
* split RC_CONSOLE_PC_ENGINE_CD off of RC_CONSOLE_PC_ENGINE
|
||||||
|
* add hash/memory map for RC_CONSOLE_NEO_GEO_CD
|
||||||
|
* add additional 256KB of RAM to memory map for RC_CONSOLE_SEGA_32X
|
||||||
|
* validation: don't report redundancy between trigger and non-trigger conditions
|
||||||
|
* validation: don't report range validation errors for float comparisons
|
||||||
|
* change default image host to media.retroachievements.org
|
||||||
|
* fix decoding of denormalized floats
|
||||||
|
* fix full line comments in the middle of Display: section causing RC_MISSING_DISPLAY_STRING
|
||||||
|
|
||||||
|
# v10.4.0
|
||||||
|
* add rc_libretro_hash_set_t with support for #SAVEDISK: m3u extension
|
||||||
|
* add rc_libretro_is_system_allowed for finer-grain control over core support
|
||||||
|
* fix measured value from hitcount not resetting while paused
|
||||||
|
* add RC_CONSOLE_WASM and hash/memory map for WASM-4
|
||||||
|
* add scratchpad memory to RC_CONSOLE_PLAYSTATION_2 memory map
|
||||||
|
* add hash/memory map for RC_CONSOLE_FAIRCHILD_CHANNEL_F
|
||||||
|
* add hash/memory map for RC_CONSOLE_COMMODORE_64
|
||||||
|
* add memory map for RC_CONSOLE_AMIGA
|
||||||
|
|
||||||
|
# v10.3.3
|
||||||
|
* add RC_CONSOLE_ARDUBOY and hash/memory map for Arduboy
|
||||||
|
* add display_name to rc_api_login_response_t
|
||||||
|
* detect logical conflicts and redundancies in validator
|
||||||
|
* fix tab sequences in JSON responses being turned into t
|
||||||
|
* fix overflow when float value has more than 9 digits after the decimal
|
||||||
|
* fix libretro memory mapping when disconnect mask breaks a region into multiple blocks
|
||||||
|
* fix non-virtualized file system call when reading some iso files
|
||||||
|
|
||||||
|
# v10.3.2
|
||||||
|
* fix RC_OPERAND_PRIOR for bit sizes other than RC_MEMSIZE_BIT_0
|
||||||
|
* add memory map and hash for Amstrad CPC
|
||||||
|
* fix an issue where fetch_game_data and fetch_user_unlocks could return RC_MISSING_VALUE instead of acknowledging a server error
|
||||||
|
|
||||||
|
# v10.3.1
|
||||||
|
* allow empty description in rc_api_init_update_leaderboard_request
|
||||||
|
* fix buffered n64 hash when no filereader is registered
|
||||||
|
* add memory map and hash for Mega Duck
|
||||||
|
|
||||||
|
# v10.3.0
|
||||||
|
* support for floating point memory sizes and logic
|
||||||
|
* add built-in macros for rich presence: @Number, @Score, @Centisecs, @Seconds, @Minutes, @ASCIIChar, @UnicodeChar
|
||||||
|
* add rapi functions for fetch_code_notes, update_code_note, upload_achievement, update_leaderboard, fetch_badge_range, and add_game_hash
|
||||||
|
* add lower_is_better and hidden flags to leaderboards in rc_api_fetch_game_data_response_t
|
||||||
|
* add achievements_remaining to rc_api_award_achievement_response_t
|
||||||
|
* add console enums for PC6000, PICO, MEGADUCK and ZEEBO
|
||||||
|
* add memory map for Dreamcast
|
||||||
|
* capture leaderboard/rich presence state in rc_runtime_progress data
|
||||||
|
* support for hashing Dreamcast bin/cues
|
||||||
|
* support for hashing buffered NDS ROMs
|
||||||
|
* fix prior for sizes smaller than a byte sometimes returning current value
|
||||||
|
|
||||||
# v10.2.0
|
# v10.2.0
|
||||||
|
|
||||||
* add RC_MEMSIZE_16_BITS_BE, RC_MEMSIZE_24_BITS_BE, and RC_MEMSIZE_32_BITS_BE
|
* add RC_MEMSIZE_16_BITS_BE, RC_MEMSIZE_24_BITS_BE, and RC_MEMSIZE_32_BITS_BE
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
add_library(rcheevos
|
add_library(rcheevos
|
||||||
|
include/rcheevos.h
|
||||||
include/rc_api_editor.h
|
include/rc_api_editor.h
|
||||||
include/rc_api_info.h
|
include/rc_api_info.h
|
||||||
include/rc_api_request.h
|
include/rc_api_request.h
|
||||||
include/rc_api_runtime.h
|
include/rc_api_runtime.h
|
||||||
include/rc_api_user.h
|
include/rc_api_user.h
|
||||||
include/rcheevos.h
|
include/rc_client.h
|
||||||
include/rc_consoles.h
|
include/rc_consoles.h
|
||||||
include/rc_error.h
|
include/rc_error.h
|
||||||
include/rc_hash.h
|
include/rc_hash.h
|
||||||
|
@ -18,7 +19,6 @@ add_library(rcheevos
|
||||||
src/rapi/rc_api_runtime.c
|
src/rapi/rc_api_runtime.c
|
||||||
src/rapi/rc_api_user.c
|
src/rapi/rc_api_user.c
|
||||||
src/rcheevos/alloc.c
|
src/rcheevos/alloc.c
|
||||||
src/rcheevos/compat.c
|
|
||||||
src/rcheevos/condition.c
|
src/rcheevos/condition.c
|
||||||
src/rcheevos/condset.c
|
src/rcheevos/condset.c
|
||||||
src/rcheevos/consoleinfo.c
|
src/rcheevos/consoleinfo.c
|
||||||
|
@ -26,14 +26,21 @@ add_library(rcheevos
|
||||||
src/rcheevos/lboard.c
|
src/rcheevos/lboard.c
|
||||||
src/rcheevos/memref.c
|
src/rcheevos/memref.c
|
||||||
src/rcheevos/operand.c
|
src/rcheevos/operand.c
|
||||||
src/rcheevos/rc_client.c
|
|
||||||
src/rcheevos/rc_compat.h
|
|
||||||
src/rcheevos/rc_internal.h
|
src/rcheevos/rc_internal.h
|
||||||
|
src/rcheevos/rc_validate.c
|
||||||
|
src/rcheevos/rc_validate.h
|
||||||
src/rcheevos/richpresence.c
|
src/rcheevos/richpresence.c
|
||||||
src/rcheevos/runtime.c
|
src/rcheevos/runtime.c
|
||||||
src/rcheevos/runtime_progress.c
|
src/rcheevos/runtime_progress.c
|
||||||
src/rcheevos/trigger.c
|
src/rcheevos/trigger.c
|
||||||
src/rcheevos/value.c
|
src/rcheevos/value.c
|
||||||
|
src/rc_client.c
|
||||||
|
src/rc_client_internal.h
|
||||||
|
src/rc_compat.c
|
||||||
|
src/rc_compat.h
|
||||||
|
src/rc_util.c
|
||||||
|
src/rc_util.h
|
||||||
|
src/rc_version.h
|
||||||
src/rhash/cdreader.c
|
src/rhash/cdreader.c
|
||||||
src/rhash/hash.c
|
src/rhash/hash.c
|
||||||
src/rhash/md5.c
|
src/rhash/md5.c
|
||||||
|
@ -43,5 +50,5 @@ add_library(rcheevos
|
||||||
|
|
||||||
target_include_directories(rcheevos PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
target_include_directories(rcheevos PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||||
target_include_directories(rcheevos INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
target_include_directories(rcheevos INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||||
target_compile_definitions(rcheevos PRIVATE "RC_DISABLE_LUA=1")
|
target_compile_definitions(rcheevos PRIVATE "RC_DISABLE_LUA=1" "RCHEEVOS_URL_SSL=1")
|
||||||
|
|
||||||
|
|
|
@ -6,13 +6,11 @@ Keep in mind that **rcheevos** does *not* provide HTTP network connections. Clie
|
||||||
|
|
||||||
Not all structures defined by **rcheevos** can be created via the public API, but are exposed to allow interactions beyond just creation, destruction, and testing, such as the ones required by UI code that helps to create them.
|
Not all structures defined by **rcheevos** can be created via the public API, but are exposed to allow interactions beyond just creation, destruction, and testing, such as the ones required by UI code that helps to create them.
|
||||||
|
|
||||||
Finally, **rcheevos** does *not* allocate or manage memory by itself. All structures that can be returned by it have a function to determine the number of bytes needed to hold the structure, and another one that actually builds the structure using a caller-provided buffer to bake it.
|
|
||||||
|
|
||||||
## Lua
|
## Lua
|
||||||
|
|
||||||
RetroAchievements is considering the use of the [Lua](https://www.lua.org) language to expand the syntax supported for creating achievements. The current expression-based implementation is often limiting on newer systems.
|
RetroAchievements previously considered the use of the [Lua](https://www.lua.org) language to expand the syntax supported for creating achievements.
|
||||||
|
|
||||||
At this point, to enable Lua support, you must compile with an additional compilation flag: `HAVE_LUA`, as neither the backend nor the UI for editing achievements are currently Lua-enabled.
|
To enable Lua support, you must compile with an additional compilation flag: `HAVE_LUA`, as neither the backend nor the UI for editing achievements are currently Lua-enabled. We do not foresee enabling it any time soon, but the code has not yet been completely eliminated as many of the low-level API fuctions have parameters for LUA data.
|
||||||
|
|
||||||
> **rcheevos** does *not* create or maintain a Lua state, you have to create your own state and provide it to **rcheevos** to be used when Lua-coded achievements are found. Calls to **rcheevos** may allocate and/or free additional memory as part of the Lua runtime.
|
> **rcheevos** does *not* create or maintain a Lua state, you have to create your own state and provide it to **rcheevos** to be used when Lua-coded achievements are found. Calls to **rcheevos** may allocate and/or free additional memory as part of the Lua runtime.
|
||||||
|
|
||||||
|
@ -28,49 +26,9 @@ An understanding about how achievements are developed may be useful, you can rea
|
||||||
|
|
||||||
Most of the exposed APIs are documented [here](https://github.com/RetroAchievements/rcheevos/wiki)
|
Most of the exposed APIs are documented [here](https://github.com/RetroAchievements/rcheevos/wiki)
|
||||||
|
|
||||||
### User Configuration
|
|
||||||
|
|
||||||
There's only one thing that can be configured by users of **rcheevos**: `RC_ALIGNMENT`. This macro holds the alignment of allocations made in the buffer provided to the parsing functions, and the default value is `sizeof(void*)`.
|
|
||||||
|
|
||||||
If your platform will benefit from a different value, define a new value for it on your compiler flags before compiling the code. It has to be a power of 2, but no checking is done.
|
|
||||||
|
|
||||||
### Return values
|
### Return values
|
||||||
|
|
||||||
Any function in the rcheevos library that returns a success indicator will return one of the following values.
|
Any function in the rcheevos library that returns a success indicator will return `RC_OK` or one of the constants defined in `rc_error.h`.
|
||||||
|
|
||||||
These are in `rc_error.h`.
|
|
||||||
|
|
||||||
```c
|
|
||||||
enum {
|
|
||||||
RC_OK = 0,
|
|
||||||
RC_INVALID_LUA_OPERAND = -1,
|
|
||||||
RC_INVALID_MEMORY_OPERAND = -2,
|
|
||||||
RC_INVALID_CONST_OPERAND = -3,
|
|
||||||
RC_INVALID_FP_OPERAND = -4,
|
|
||||||
RC_INVALID_CONDITION_TYPE = -5,
|
|
||||||
RC_INVALID_OPERATOR = -6,
|
|
||||||
RC_INVALID_REQUIRED_HITS = -7,
|
|
||||||
RC_DUPLICATED_START = -8,
|
|
||||||
RC_DUPLICATED_CANCEL = -9,
|
|
||||||
RC_DUPLICATED_SUBMIT = -10,
|
|
||||||
RC_DUPLICATED_VALUE = -11,
|
|
||||||
RC_DUPLICATED_PROGRESS = -12,
|
|
||||||
RC_MISSING_START = -13,
|
|
||||||
RC_MISSING_CANCEL = -14,
|
|
||||||
RC_MISSING_SUBMIT = -15,
|
|
||||||
RC_MISSING_VALUE = -16,
|
|
||||||
RC_INVALID_LBOARD_FIELD = -17,
|
|
||||||
RC_MISSING_DISPLAY_STRING = -18,
|
|
||||||
RC_OUT_OF_MEMORY = -19,
|
|
||||||
RC_INVALID_VALUE_FLAG = -20,
|
|
||||||
RC_MISSING_VALUE_MEASURED = -21,
|
|
||||||
RC_MULTIPLE_MEASURED = -22,
|
|
||||||
RC_INVALID_MEASURED_TARGET = -23,
|
|
||||||
RC_INVALID_COMPARISON = -24,
|
|
||||||
RC_INVALID_STATE = -25,
|
|
||||||
RC_INVALID_JSON = -26
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
To convert the return code into something human-readable, pass it to:
|
To convert the return code into something human-readable, pass it to:
|
||||||
```c
|
```c
|
||||||
|
@ -79,193 +37,17 @@ const char* rc_error_str(int ret);
|
||||||
|
|
||||||
### Console identifiers
|
### Console identifiers
|
||||||
|
|
||||||
This enumeration uniquely identifies each of the supported platforms in RetroAchievements.
|
Platforms supported by RetroAchievements are enumerated in `rc_consoles.h`. Note that some consoles in the enum are not yet fully supported (may require a memory map or some way to uniquely identify games).
|
||||||
|
|
||||||
These are in `rc_consoles.h`.
|
|
||||||
|
|
||||||
```c
|
|
||||||
enum {
|
|
||||||
RC_CONSOLE_MEGA_DRIVE = 1,
|
|
||||||
RC_CONSOLE_NINTENDO_64 = 2,
|
|
||||||
RC_CONSOLE_SUPER_NINTENDO = 3,
|
|
||||||
RC_CONSOLE_GAMEBOY = 4,
|
|
||||||
RC_CONSOLE_GAMEBOY_ADVANCE = 5,
|
|
||||||
RC_CONSOLE_GAMEBOY_COLOR = 6,
|
|
||||||
RC_CONSOLE_NINTENDO = 7,
|
|
||||||
RC_CONSOLE_PC_ENGINE = 8,
|
|
||||||
RC_CONSOLE_SEGA_CD = 9,
|
|
||||||
RC_CONSOLE_SEGA_32X = 10,
|
|
||||||
RC_CONSOLE_MASTER_SYSTEM = 11,
|
|
||||||
RC_CONSOLE_PLAYSTATION = 12,
|
|
||||||
RC_CONSOLE_ATARI_LYNX = 13,
|
|
||||||
RC_CONSOLE_NEOGEO_POCKET = 14,
|
|
||||||
RC_CONSOLE_GAME_GEAR = 15,
|
|
||||||
RC_CONSOLE_GAMECUBE = 16,
|
|
||||||
RC_CONSOLE_ATARI_JAGUAR = 17,
|
|
||||||
RC_CONSOLE_NINTENDO_DS = 18,
|
|
||||||
RC_CONSOLE_WII = 19,
|
|
||||||
RC_CONSOLE_WII_U = 20,
|
|
||||||
RC_CONSOLE_PLAYSTATION_2 = 21,
|
|
||||||
RC_CONSOLE_XBOX = 22,
|
|
||||||
RC_CONSOLE_MAGNAVOX_ODYSSEY2 = 23,
|
|
||||||
RC_CONSOLE_POKEMON_MINI = 24,
|
|
||||||
RC_CONSOLE_ATARI_2600 = 25,
|
|
||||||
RC_CONSOLE_MS_DOS = 26,
|
|
||||||
RC_CONSOLE_ARCADE = 27,
|
|
||||||
RC_CONSOLE_VIRTUAL_BOY = 28,
|
|
||||||
RC_CONSOLE_MSX = 29,
|
|
||||||
RC_CONSOLE_COMMODORE_64 = 30,
|
|
||||||
RC_CONSOLE_ZX81 = 31,
|
|
||||||
RC_CONSOLE_ORIC = 32,
|
|
||||||
RC_CONSOLE_SG1000 = 33,
|
|
||||||
RC_CONSOLE_VIC20 = 34,
|
|
||||||
RC_CONSOLE_AMIGA = 35,
|
|
||||||
RC_CONSOLE_ATARI_ST = 36,
|
|
||||||
RC_CONSOLE_AMSTRAD_PC = 37,
|
|
||||||
RC_CONSOLE_APPLE_II = 38,
|
|
||||||
RC_CONSOLE_SATURN = 39,
|
|
||||||
RC_CONSOLE_DREAMCAST = 40,
|
|
||||||
RC_CONSOLE_PSP = 41,
|
|
||||||
RC_CONSOLE_CDI = 42,
|
|
||||||
RC_CONSOLE_3DO = 43,
|
|
||||||
RC_CONSOLE_COLECOVISION = 44,
|
|
||||||
RC_CONSOLE_INTELLIVISION = 45,
|
|
||||||
RC_CONSOLE_VECTREX = 46,
|
|
||||||
RC_CONSOLE_PC8800 = 47,
|
|
||||||
RC_CONSOLE_PC9800 = 48,
|
|
||||||
RC_CONSOLE_PCFX = 49,
|
|
||||||
RC_CONSOLE_ATARI_5200 = 50,
|
|
||||||
RC_CONSOLE_ATARI_7800 = 51,
|
|
||||||
RC_CONSOLE_X68K = 52,
|
|
||||||
RC_CONSOLE_WONDERSWAN = 53,
|
|
||||||
RC_CONSOLE_CASSETTEVISION = 54,
|
|
||||||
RC_CONSOLE_SUPER_CASSETTEVISION = 55,
|
|
||||||
RC_CONSOLE_NEO_GEO_CD = 56,
|
|
||||||
RC_CONSOLE_FAIRCHILD_CHANNEL_F = 57,
|
|
||||||
RC_CONSOLE_FM_TOWNS = 58,
|
|
||||||
RC_CONSOLE_ZX_SPECTRUM = 59,
|
|
||||||
RC_CONSOLE_GAME_AND_WATCH = 60,
|
|
||||||
RC_CONSOLE_NOKIA_NGAGE = 61,
|
|
||||||
RC_CONSOLE_NINTENDO_3DS = 62,
|
|
||||||
RC_CONSOLE_SUPERVISION = 63,
|
|
||||||
RC_CONSOLE_SHARPX1 = 64,
|
|
||||||
RC_CONSOLE_TIC80 = 65,
|
|
||||||
RC_CONSOLE_THOMSONTO8 = 66,
|
|
||||||
RC_CONSOLE_PC6000 = 67,
|
|
||||||
RC_CONSOLE_PICO = 68,
|
|
||||||
RC_CONSOLE_MEGADUCK = 69,
|
|
||||||
RC_CONSOLE_ZEEBO = 70
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
## Runtime support
|
## Runtime support
|
||||||
|
|
||||||
The runtime encapsulates a set of achievements, leaderboards, and rich presence for a game and manages processing them for each frame. When important things occur, events are raised for the caller via a callback.
|
Provides a set of functions for managing an active game - initializing and processing achievements, leaderboards, and rich presence. When important things occur, events are raised for the caller via a callback.
|
||||||
|
|
||||||
These are in `rc_runtime.h`.
|
These are in `rc_runtime.h`.
|
||||||
|
|
||||||
The `rc_runtime_t` structure uses several forward-defines. If you need access to the actual contents of any of the forward-defined structures, those definitions are in `rc_runtime_types.h`
|
Note: `rc_runtime_t` still requires the client implement all of the logic that calls the APIs to retrieve the data and perform the unlocks.
|
||||||
|
|
||||||
```c
|
The `rc_client_t` functions wrap a `rc_runtime_t` and manage the API calls and other common functionality (like managing the user information, identifying/loading a game, and building the active/inactive achievements list for the UI). Please see [the wiki](https://github.com/RetroAchievements/rcheevos/wiki/rc_client-integration) for details on using the `rc_client_t` functions.
|
||||||
typedef struct rc_runtime_t {
|
|
||||||
rc_runtime_trigger_t* triggers;
|
|
||||||
unsigned trigger_count;
|
|
||||||
unsigned trigger_capacity;
|
|
||||||
|
|
||||||
rc_runtime_lboard_t* lboards;
|
|
||||||
unsigned lboard_count;
|
|
||||||
unsigned lboard_capacity;
|
|
||||||
|
|
||||||
rc_runtime_richpresence_t* richpresence;
|
|
||||||
|
|
||||||
rc_memref_value_t* memrefs;
|
|
||||||
rc_memref_value_t** next_memref;
|
|
||||||
|
|
||||||
rc_value_t* variables;
|
|
||||||
rc_value_t** next_variable;
|
|
||||||
}
|
|
||||||
rc_runtime_t;
|
|
||||||
```
|
|
||||||
|
|
||||||
The runtime must first be initialized.
|
|
||||||
```c
|
|
||||||
void rc_runtime_init(rc_runtime_t* runtime);
|
|
||||||
```
|
|
||||||
|
|
||||||
Then individual achievements, leaderboards, and even rich presence can be loaded into the runtime. These functions return RC_OK, or one of the negative value error codes listed above.
|
|
||||||
```c
|
|
||||||
int rc_runtime_activate_achievement(rc_runtime_t* runtime, unsigned id, const char* memaddr, lua_State* L, int funcs_idx);
|
|
||||||
int rc_runtime_activate_lboard(rc_runtime_t* runtime, unsigned id, const char* memaddr, lua_State* L, int funcs_idx);
|
|
||||||
int rc_runtime_activate_richpresence(rc_runtime_t* runtime, const char* script, lua_State* L, int funcs_idx);
|
|
||||||
```
|
|
||||||
|
|
||||||
The runtime should be called once per frame to evaluate the state of the active achievements/leaderboards:
|
|
||||||
```c
|
|
||||||
void rc_runtime_do_frame(rc_runtime_t* runtime, rc_runtime_event_handler_t event_handler, rc_runtime_peek_t peek, void* ud, lua_State* L);
|
|
||||||
```
|
|
||||||
|
|
||||||
The `event_handler` is a callback function that is called for each event that occurs when processing the frame.
|
|
||||||
```c
|
|
||||||
typedef struct rc_runtime_event_t {
|
|
||||||
unsigned id;
|
|
||||||
int value;
|
|
||||||
char type;
|
|
||||||
}
|
|
||||||
rc_runtime_event_t;
|
|
||||||
|
|
||||||
typedef void (*rc_runtime_event_handler_t)(const rc_runtime_event_t* runtime_event);
|
|
||||||
```
|
|
||||||
|
|
||||||
The `event.type` field will be one of the following:
|
|
||||||
* RC_RUNTIME_EVENT_ACHIEVEMENT_ACTIVATED (id=achievement id)
|
|
||||||
An achievement starts in the RC_TRIGGER_STATE_WAITING state and cannot trigger until it has been false for at least one frame. This event indicates the achievement is no longer waiting and may trigger on a future frame.
|
|
||||||
* RC_RUNTIME_EVENT_ACHIEVEMENT_PAUSED (id=achievement id)
|
|
||||||
One or more conditions in the achievement have disabled the achievement.
|
|
||||||
* RC_RUNTIME_EVENT_ACHIEVEMENT_RESET (id=achievement id)
|
|
||||||
One or more conditions in the achievement have reset any progress captured in the achievement.
|
|
||||||
* RC_RUNTIME_EVENT_ACHIEVEMENT_TRIGGERED (id=achievement id)
|
|
||||||
All conditions for the achievement have been met and the user should be informed.
|
|
||||||
NOTE: If `rc_runtime_reset` is called without deactivating the achievement, it may trigger again.
|
|
||||||
* RC_RUNTIME_EVENT_ACHIEVEMENT_PRIMED (id=achievement id)
|
|
||||||
All non-trigger conditions for the achievement have been met. This typically indicates the achievement is a challenge achievement and the challenge is active.
|
|
||||||
* RC_RUNTIME_EVENT_LBOARD_STARTED (id=leaderboard id, value=leaderboard value)
|
|
||||||
The leaderboard's start condition has been met and the user should be informed that a leaderboard attempt has started.
|
|
||||||
* RC_RUNTIME_EVENT_LBOARD_CANCELED (id=leaderboard id, value=leaderboard value)
|
|
||||||
The leaderboard's cancel condition has been met and the user should be informed that a leaderboard attempt has failed.
|
|
||||||
* RC_RUNTIME_EVENT_LBOARD_UPDATED (id=leaderboard id, value=leaderboard value)
|
|
||||||
The leaderboard value has changed.
|
|
||||||
* RC_RUNTIME_EVENT_LBOARD_TRIGGERED (id=leaderboard id, value=leaderboard value)
|
|
||||||
The leaderboard's submit condition has been met and the user should be informed that a leaderboard attempt was successful. The value should be submitted.
|
|
||||||
* RC_RUNTIME_EVENT_ACHIEVEMENT_DISABLED (id=achievement id)
|
|
||||||
The achievement has been disabled by a call to `rc_invalidate_address`.
|
|
||||||
* RC_RUNTIME_EVENT_LBOARD_DISABLED (id=leaderboard id)
|
|
||||||
The achievement has been disabled by a call to `rc_invalidate_address`.
|
|
||||||
|
|
||||||
When an achievement triggers, it should be deactivated so it won't trigger again:
|
|
||||||
```c
|
|
||||||
void rc_runtime_deactivate_achievement(rc_runtime_t* runtime, unsigned id);
|
|
||||||
```
|
|
||||||
Additionally, the unlock should be submitted to the server.
|
|
||||||
|
|
||||||
When a leaderboard triggers, it should not be deactivated in case the player wants to try again for a better score. The value should be submitted to the server.
|
|
||||||
|
|
||||||
For `RC_RUNTIME_EVENT_LBOARD_UPDATED` and `RC_RUNTIME_EVENT_LBOARD_TRIGGERED` events, there is a helper function to call if you wish to display the leaderboard value on screen.
|
|
||||||
|
|
||||||
```c
|
|
||||||
int rc_runtime_format_lboard_value(char* buffer, int size, int value, int format);
|
|
||||||
```
|
|
||||||
|
|
||||||
`rc_runtime_do_frame` also periodically updates the rich presense string (every 60 frames). To get the current value, call
|
|
||||||
```c
|
|
||||||
const char* rc_runtime_get_richpresence(const rc_runtime_t* runtime);
|
|
||||||
```
|
|
||||||
|
|
||||||
When the game is reset, the runtime should also be reset:
|
|
||||||
```c
|
|
||||||
void rc_runtime_reset(rc_runtime_t* runtime);
|
|
||||||
```
|
|
||||||
|
|
||||||
This ensures any active achievements/leaderboards are set back to their initial states and prevents unexpected triggers when the memory changes in atypical way.
|
|
||||||
|
|
||||||
## Server Communication
|
## Server Communication
|
||||||
|
|
||||||
|
@ -275,6 +57,8 @@ This ensures any active achievements/leaderboards are set back to their initial
|
||||||
|
|
||||||
NOTE: **rapi** is a replacement for **rurl**. **rurl** has been deprecated.
|
NOTE: **rapi** is a replacement for **rurl**. **rurl** has been deprecated.
|
||||||
|
|
||||||
|
NOTE: `rc_client` is the preferred way to have a client interact with the server.
|
||||||
|
|
||||||
These are in `rc_api_user.h`, `rc_api_runtime.h` and `rc_api_common.h`.
|
These are in `rc_api_user.h`, `rc_api_runtime.h` and `rc_api_common.h`.
|
||||||
|
|
||||||
The basic process of making an **rapi** call is to initialize a params object, call a function to convert it to a URL, send that to the server, then pass the response to a function to convert it into a response object, and handle the response values.
|
The basic process of making an **rapi** call is to initialize a params object, call a function to convert it to a URL, send that to the server, then pass the response to a function to convert it into a response object, and handle the response values.
|
||||||
|
@ -295,6 +79,3 @@ These are in `rc_hash.h`.
|
||||||
int rc_hash_generate_from_buffer(char hash[33], int console_id, uint8_t* buffer, size_t buffer_size);
|
int rc_hash_generate_from_buffer(char hash[33], int console_id, uint8_t* buffer, size_t buffer_size);
|
||||||
int rc_hash_generate_from_file(char hash[33], int console_id, const char* path);
|
int rc_hash_generate_from_file(char hash[33], int console_id, const char* path);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "rc_api_request.h"
|
#include "rc_api_request.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
@ -14,14 +16,14 @@ extern "C" {
|
||||||
*/
|
*/
|
||||||
typedef struct rc_api_fetch_code_notes_request_t {
|
typedef struct rc_api_fetch_code_notes_request_t {
|
||||||
/* The unique identifier of the game */
|
/* The unique identifier of the game */
|
||||||
unsigned game_id;
|
uint32_t game_id;
|
||||||
}
|
}
|
||||||
rc_api_fetch_code_notes_request_t;
|
rc_api_fetch_code_notes_request_t;
|
||||||
|
|
||||||
/* A code note definiton */
|
/* A code note definiton */
|
||||||
typedef struct rc_api_code_note_t {
|
typedef struct rc_api_code_note_t {
|
||||||
/* The address the note is associated to */
|
/* The address the note is associated to */
|
||||||
unsigned address;
|
uint32_t address;
|
||||||
/* The name of the use who last updated the note */
|
/* The name of the use who last updated the note */
|
||||||
const char* author;
|
const char* author;
|
||||||
/* The contents of the note */
|
/* The contents of the note */
|
||||||
|
@ -35,7 +37,7 @@ typedef struct rc_api_fetch_code_notes_response_t {
|
||||||
/* An array of code notes for the game */
|
/* An array of code notes for the game */
|
||||||
rc_api_code_note_t* notes;
|
rc_api_code_note_t* notes;
|
||||||
/* The number of items in the notes array */
|
/* The number of items in the notes array */
|
||||||
unsigned num_notes;
|
uint32_t num_notes;
|
||||||
|
|
||||||
/* Common server-provided response information */
|
/* Common server-provided response information */
|
||||||
rc_api_response_t response;
|
rc_api_response_t response;
|
||||||
|
@ -58,9 +60,9 @@ typedef struct rc_api_update_code_note_request_t {
|
||||||
/* The API token from the login request */
|
/* The API token from the login request */
|
||||||
const char* api_token;
|
const char* api_token;
|
||||||
/* The unique identifier of the game */
|
/* The unique identifier of the game */
|
||||||
unsigned game_id;
|
uint32_t game_id;
|
||||||
/* The address the note is associated to */
|
/* The address the note is associated to */
|
||||||
unsigned address;
|
uint32_t address;
|
||||||
/* The contents of the note (NULL or empty to delete a note) */
|
/* The contents of the note (NULL or empty to delete a note) */
|
||||||
const char* note;
|
const char* note;
|
||||||
}
|
}
|
||||||
|
@ -91,9 +93,9 @@ typedef struct rc_api_update_achievement_request_t {
|
||||||
/* The API token from the login request */
|
/* The API token from the login request */
|
||||||
const char* api_token;
|
const char* api_token;
|
||||||
/* The unique identifier of the achievement (0 to create a new achievement) */
|
/* The unique identifier of the achievement (0 to create a new achievement) */
|
||||||
unsigned achievement_id;
|
uint32_t achievement_id;
|
||||||
/* The unique identifier of the game */
|
/* The unique identifier of the game */
|
||||||
unsigned game_id;
|
uint32_t game_id;
|
||||||
/* The name of the achievement */
|
/* The name of the achievement */
|
||||||
const char* title;
|
const char* title;
|
||||||
/* The description of the achievement */
|
/* The description of the achievement */
|
||||||
|
@ -103,9 +105,9 @@ typedef struct rc_api_update_achievement_request_t {
|
||||||
/* The serialized trigger for the achievement */
|
/* The serialized trigger for the achievement */
|
||||||
const char* trigger;
|
const char* trigger;
|
||||||
/* The number of points the achievement is worth */
|
/* The number of points the achievement is worth */
|
||||||
unsigned points;
|
uint32_t points;
|
||||||
/* The category of the achievement */
|
/* The category of the achievement */
|
||||||
unsigned category;
|
uint32_t category;
|
||||||
}
|
}
|
||||||
rc_api_update_achievement_request_t;
|
rc_api_update_achievement_request_t;
|
||||||
|
|
||||||
|
@ -114,7 +116,7 @@ rc_api_update_achievement_request_t;
|
||||||
*/
|
*/
|
||||||
typedef struct rc_api_update_achievement_response_t {
|
typedef struct rc_api_update_achievement_response_t {
|
||||||
/* The unique identifier of the achievement */
|
/* The unique identifier of the achievement */
|
||||||
unsigned achievement_id;
|
uint32_t achievement_id;
|
||||||
|
|
||||||
/* Common server-provided response information */
|
/* Common server-provided response information */
|
||||||
rc_api_response_t response;
|
rc_api_response_t response;
|
||||||
|
@ -137,9 +139,9 @@ typedef struct rc_api_update_leaderboard_request_t {
|
||||||
/* The API token from the login request */
|
/* The API token from the login request */
|
||||||
const char* api_token;
|
const char* api_token;
|
||||||
/* The unique identifier of the leaderboard (0 to create a new leaderboard) */
|
/* The unique identifier of the leaderboard (0 to create a new leaderboard) */
|
||||||
unsigned leaderboard_id;
|
uint32_t leaderboard_id;
|
||||||
/* The unique identifier of the game */
|
/* The unique identifier of the game */
|
||||||
unsigned game_id;
|
uint32_t game_id;
|
||||||
/* The name of the leaderboard */
|
/* The name of the leaderboard */
|
||||||
const char* title;
|
const char* title;
|
||||||
/* The description of the leaderboard */
|
/* The description of the leaderboard */
|
||||||
|
@ -155,7 +157,7 @@ typedef struct rc_api_update_leaderboard_request_t {
|
||||||
/* The format of leaderboard values */
|
/* The format of leaderboard values */
|
||||||
const char* format;
|
const char* format;
|
||||||
/* Whether or not lower scores are better for the leaderboard */
|
/* Whether or not lower scores are better for the leaderboard */
|
||||||
int lower_is_better;
|
uint32_t lower_is_better;
|
||||||
}
|
}
|
||||||
rc_api_update_leaderboard_request_t;
|
rc_api_update_leaderboard_request_t;
|
||||||
|
|
||||||
|
@ -164,7 +166,7 @@ rc_api_update_leaderboard_request_t;
|
||||||
*/
|
*/
|
||||||
typedef struct rc_api_update_leaderboard_response_t {
|
typedef struct rc_api_update_leaderboard_response_t {
|
||||||
/* The unique identifier of the leaderboard */
|
/* The unique identifier of the leaderboard */
|
||||||
unsigned leaderboard_id;
|
uint32_t leaderboard_id;
|
||||||
|
|
||||||
/* Common server-provided response information */
|
/* Common server-provided response information */
|
||||||
rc_api_response_t response;
|
rc_api_response_t response;
|
||||||
|
@ -183,7 +185,7 @@ void rc_api_destroy_update_leaderboard_response(rc_api_update_leaderboard_respon
|
||||||
*/
|
*/
|
||||||
typedef struct rc_api_fetch_badge_range_request_t {
|
typedef struct rc_api_fetch_badge_range_request_t {
|
||||||
/* Unused */
|
/* Unused */
|
||||||
unsigned unused;
|
uint32_t unused;
|
||||||
}
|
}
|
||||||
rc_api_fetch_badge_range_request_t;
|
rc_api_fetch_badge_range_request_t;
|
||||||
|
|
||||||
|
@ -192,9 +194,9 @@ rc_api_fetch_badge_range_request_t;
|
||||||
*/
|
*/
|
||||||
typedef struct rc_api_fetch_badge_range_response_t {
|
typedef struct rc_api_fetch_badge_range_response_t {
|
||||||
/* The numeric identifier of the first valid badge ID */
|
/* The numeric identifier of the first valid badge ID */
|
||||||
unsigned first_badge_id;
|
uint32_t first_badge_id;
|
||||||
/* The numeric identifier of the first unassigned badge ID */
|
/* The numeric identifier of the first unassigned badge ID */
|
||||||
unsigned next_badge_id;
|
uint32_t next_badge_id;
|
||||||
|
|
||||||
/* Common server-provided response information */
|
/* Common server-provided response information */
|
||||||
rc_api_response_t response;
|
rc_api_response_t response;
|
||||||
|
@ -217,9 +219,9 @@ typedef struct rc_api_add_game_hash_request_t {
|
||||||
/* The API token from the login request */
|
/* The API token from the login request */
|
||||||
const char* api_token;
|
const char* api_token;
|
||||||
/* The unique identifier of the game (0 to create a new game entry) */
|
/* The unique identifier of the game (0 to create a new game entry) */
|
||||||
unsigned game_id;
|
uint32_t game_id;
|
||||||
/* The unique identifier of the console for the game */
|
/* The unique identifier of the console for the game */
|
||||||
unsigned console_id;
|
uint32_t console_id;
|
||||||
/* The title of the game */
|
/* The title of the game */
|
||||||
const char* title;
|
const char* title;
|
||||||
/* The hash being added */
|
/* The hash being added */
|
||||||
|
@ -234,7 +236,7 @@ rc_api_add_game_hash_request_t;
|
||||||
*/
|
*/
|
||||||
typedef struct rc_api_add_game_hash_response_t {
|
typedef struct rc_api_add_game_hash_response_t {
|
||||||
/* The unique identifier of the game */
|
/* The unique identifier of the game */
|
||||||
unsigned game_id;
|
uint32_t game_id;
|
||||||
|
|
||||||
/* Common server-provided response information */
|
/* Common server-provided response information */
|
||||||
rc_api_response_t response;
|
rc_api_response_t response;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "rc_api_request.h"
|
#include "rc_api_request.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -20,13 +21,13 @@ typedef struct rc_api_fetch_achievement_info_request_t {
|
||||||
/* The API token from the login request */
|
/* The API token from the login request */
|
||||||
const char* api_token;
|
const char* api_token;
|
||||||
/* The unique identifier of the achievement */
|
/* The unique identifier of the achievement */
|
||||||
unsigned achievement_id;
|
uint32_t achievement_id;
|
||||||
/* The 1-based index of the first entry to retrieve */
|
/* The 1-based index of the first entry to retrieve */
|
||||||
unsigned first_entry;
|
uint32_t first_entry;
|
||||||
/* The number of entries to retrieve */
|
/* The number of entries to retrieve */
|
||||||
unsigned count;
|
uint32_t count;
|
||||||
/* Non-zero to only return unlocks earned by the user's friends */
|
/* Non-zero to only return unlocks earned by the user's friends */
|
||||||
unsigned friends_only;
|
uint32_t friends_only;
|
||||||
}
|
}
|
||||||
rc_api_fetch_achievement_info_request_t;
|
rc_api_fetch_achievement_info_request_t;
|
||||||
|
|
||||||
|
@ -44,18 +45,18 @@ rc_api_achievement_awarded_entry_t;
|
||||||
*/
|
*/
|
||||||
typedef struct rc_api_fetch_achievement_info_response_t {
|
typedef struct rc_api_fetch_achievement_info_response_t {
|
||||||
/* The unique identifier of the achievement */
|
/* The unique identifier of the achievement */
|
||||||
unsigned id;
|
uint32_t id;
|
||||||
/* The unique identifier of the game to which the leaderboard is associated */
|
/* The unique identifier of the game to which the leaderboard is associated */
|
||||||
unsigned game_id;
|
uint32_t game_id;
|
||||||
/* The number of times the achievement has been awarded */
|
/* The number of times the achievement has been awarded */
|
||||||
unsigned num_awarded;
|
uint32_t num_awarded;
|
||||||
/* The number of players that have earned at least one achievement for the game */
|
/* The number of players that have earned at least one achievement for the game */
|
||||||
unsigned num_players;
|
uint32_t num_players;
|
||||||
|
|
||||||
/* An array of recently rewarded entries */
|
/* An array of recently rewarded entries */
|
||||||
rc_api_achievement_awarded_entry_t* recently_awarded;
|
rc_api_achievement_awarded_entry_t* recently_awarded;
|
||||||
/* The number of items in the recently_awarded array */
|
/* The number of items in the recently_awarded array */
|
||||||
unsigned num_recently_awarded;
|
uint32_t num_recently_awarded;
|
||||||
|
|
||||||
/* Common server-provided response information */
|
/* Common server-provided response information */
|
||||||
rc_api_response_t response;
|
rc_api_response_t response;
|
||||||
|
@ -74,11 +75,11 @@ void rc_api_destroy_fetch_achievement_info_response(rc_api_fetch_achievement_inf
|
||||||
*/
|
*/
|
||||||
typedef struct rc_api_fetch_leaderboard_info_request_t {
|
typedef struct rc_api_fetch_leaderboard_info_request_t {
|
||||||
/* The unique identifier of the leaderboard */
|
/* The unique identifier of the leaderboard */
|
||||||
unsigned leaderboard_id;
|
uint32_t leaderboard_id;
|
||||||
/* The number of entries to retrieve */
|
/* The number of entries to retrieve */
|
||||||
unsigned count;
|
uint32_t count;
|
||||||
/* The 1-based index of the first entry to retrieve */
|
/* The 1-based index of the first entry to retrieve */
|
||||||
unsigned first_entry;
|
uint32_t first_entry;
|
||||||
/* The username of the player around whom the entries should be returned */
|
/* The username of the player around whom the entries should be returned */
|
||||||
const char* username;
|
const char* username;
|
||||||
}
|
}
|
||||||
|
@ -89,11 +90,11 @@ typedef struct rc_api_lboard_info_entry_t {
|
||||||
/* The user associated to the entry */
|
/* The user associated to the entry */
|
||||||
const char* username;
|
const char* username;
|
||||||
/* The rank of the entry */
|
/* The rank of the entry */
|
||||||
unsigned rank;
|
uint32_t rank;
|
||||||
/* The index of the entry */
|
/* The index of the entry */
|
||||||
unsigned index;
|
uint32_t index;
|
||||||
/* The value of the entry */
|
/* The value of the entry */
|
||||||
int score;
|
int32_t score;
|
||||||
/* When the entry was submitted */
|
/* When the entry was submitted */
|
||||||
time_t submitted;
|
time_t submitted;
|
||||||
}
|
}
|
||||||
|
@ -104,11 +105,11 @@ rc_api_lboard_info_entry_t;
|
||||||
*/
|
*/
|
||||||
typedef struct rc_api_fetch_leaderboard_info_response_t {
|
typedef struct rc_api_fetch_leaderboard_info_response_t {
|
||||||
/* The unique identifier of the leaderboard */
|
/* The unique identifier of the leaderboard */
|
||||||
unsigned id;
|
uint32_t id;
|
||||||
/* The format to pass to rc_format_value to format the leaderboard value */
|
/* The format to pass to rc_format_value to format the leaderboard value */
|
||||||
int format;
|
int format;
|
||||||
/* If non-zero, indicates that lower scores appear first */
|
/* If non-zero, indicates that lower scores appear first */
|
||||||
int lower_is_better;
|
uint32_t lower_is_better;
|
||||||
/* The title of the leaderboard */
|
/* The title of the leaderboard */
|
||||||
const char* title;
|
const char* title;
|
||||||
/* The description of the leaderboard */
|
/* The description of the leaderboard */
|
||||||
|
@ -116,7 +117,7 @@ typedef struct rc_api_fetch_leaderboard_info_response_t {
|
||||||
/* The definition of the leaderboard to be passed to rc_runtime_activate_lboard */
|
/* The definition of the leaderboard to be passed to rc_runtime_activate_lboard */
|
||||||
const char* definition;
|
const char* definition;
|
||||||
/* The unique identifier of the game to which the leaderboard is associated */
|
/* The unique identifier of the game to which the leaderboard is associated */
|
||||||
unsigned game_id;
|
uint32_t game_id;
|
||||||
/* The author of the leaderboard */
|
/* The author of the leaderboard */
|
||||||
const char* author;
|
const char* author;
|
||||||
/* When the leaderboard was first uploaded to the server */
|
/* When the leaderboard was first uploaded to the server */
|
||||||
|
@ -127,7 +128,7 @@ typedef struct rc_api_fetch_leaderboard_info_response_t {
|
||||||
/* An array of requested entries */
|
/* An array of requested entries */
|
||||||
rc_api_lboard_info_entry_t* entries;
|
rc_api_lboard_info_entry_t* entries;
|
||||||
/* The number of items in the entries array */
|
/* The number of items in the entries array */
|
||||||
unsigned num_entries;
|
uint32_t num_entries;
|
||||||
|
|
||||||
/* Common server-provided response information */
|
/* Common server-provided response information */
|
||||||
rc_api_response_t response;
|
rc_api_response_t response;
|
||||||
|
@ -146,14 +147,14 @@ void rc_api_destroy_fetch_leaderboard_info_response(rc_api_fetch_leaderboard_inf
|
||||||
*/
|
*/
|
||||||
typedef struct rc_api_fetch_games_list_request_t {
|
typedef struct rc_api_fetch_games_list_request_t {
|
||||||
/* The unique identifier of the console to query */
|
/* The unique identifier of the console to query */
|
||||||
unsigned console_id;
|
uint32_t console_id;
|
||||||
}
|
}
|
||||||
rc_api_fetch_games_list_request_t;
|
rc_api_fetch_games_list_request_t;
|
||||||
|
|
||||||
/* A game list entry */
|
/* A game list entry */
|
||||||
typedef struct rc_api_game_list_entry_t {
|
typedef struct rc_api_game_list_entry_t {
|
||||||
/* The unique identifier of the game */
|
/* The unique identifier of the game */
|
||||||
unsigned id;
|
uint32_t id;
|
||||||
/* The name of the game */
|
/* The name of the game */
|
||||||
const char* name;
|
const char* name;
|
||||||
}
|
}
|
||||||
|
@ -166,7 +167,7 @@ typedef struct rc_api_fetch_games_list_response_t {
|
||||||
/* An array of requested entries */
|
/* An array of requested entries */
|
||||||
rc_api_game_list_entry_t* entries;
|
rc_api_game_list_entry_t* entries;
|
||||||
/* The number of items in the entries array */
|
/* The number of items in the entries array */
|
||||||
unsigned num_entries;
|
uint32_t num_entries;
|
||||||
|
|
||||||
/* Common server-provided response information */
|
/* Common server-provided response information */
|
||||||
rc_api_response_t response;
|
rc_api_response_t response;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define RC_API_REQUEST_H
|
#define RC_API_REQUEST_H
|
||||||
|
|
||||||
#include "rc_error.h"
|
#include "rc_error.h"
|
||||||
|
#include "../src/rc_util.h"
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
@ -9,32 +10,6 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
|
||||||
* A block of memory for variable length data (like strings and arrays).
|
|
||||||
*/
|
|
||||||
typedef struct rc_api_buffer_chunk_t {
|
|
||||||
/* The current location where data is being written */
|
|
||||||
char* write;
|
|
||||||
/* The first byte past the end of data where writing cannot occur */
|
|
||||||
char* end;
|
|
||||||
/* The first byte of the data */
|
|
||||||
char* start;
|
|
||||||
/* The next block in the allocated memory chain */
|
|
||||||
struct rc_api_buffer_chunk_t* next;
|
|
||||||
}
|
|
||||||
rc_api_buffer_chunk_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A preallocated block of memory for variable length data (like strings and arrays).
|
|
||||||
*/
|
|
||||||
typedef struct rc_api_buffer_t {
|
|
||||||
/* The chunk data (will point at the local data member) */
|
|
||||||
struct rc_api_buffer_chunk_t chunk;
|
|
||||||
/* Small chunk of memory pre-allocated for the chunk */
|
|
||||||
char data[256];
|
|
||||||
}
|
|
||||||
rc_api_buffer_t;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A constructed request to send to the retroachievements server.
|
* A constructed request to send to the retroachievements server.
|
||||||
*/
|
*/
|
||||||
|
@ -47,7 +22,7 @@ typedef struct rc_api_request_t {
|
||||||
const char* content_type;
|
const char* content_type;
|
||||||
|
|
||||||
/* Storage for the url and post_data */
|
/* Storage for the url and post_data */
|
||||||
rc_api_buffer_t buffer;
|
rc_buffer_t buffer;
|
||||||
}
|
}
|
||||||
rc_api_request_t;
|
rc_api_request_t;
|
||||||
|
|
||||||
|
@ -59,9 +34,11 @@ typedef struct rc_api_response_t {
|
||||||
int succeeded;
|
int succeeded;
|
||||||
/* Server-provided message associated to the failure */
|
/* Server-provided message associated to the failure */
|
||||||
const char* error_message;
|
const char* error_message;
|
||||||
|
/* Server-provided error code associated to the failure */
|
||||||
|
const char* error_code;
|
||||||
|
|
||||||
/* Storage for the response data */
|
/* Storage for the response data */
|
||||||
rc_api_buffer_t buffer;
|
rc_buffer_t buffer;
|
||||||
}
|
}
|
||||||
rc_api_response_t;
|
rc_api_response_t;
|
||||||
|
|
||||||
|
@ -79,6 +56,11 @@ typedef struct rc_api_server_response_t {
|
||||||
int http_status_code;
|
int http_status_code;
|
||||||
} rc_api_server_response_t;
|
} rc_api_server_response_t;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
RC_API_SERVER_RESPONSE_CLIENT_ERROR = -1,
|
||||||
|
RC_API_SERVER_RESPONSE_RETRYABLE_CLIENT_ERROR = -2
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "rc_api_request.h"
|
#include "rc_api_request.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -19,7 +20,7 @@ typedef struct rc_api_fetch_image_request_t {
|
||||||
/* The name of the image to fetch */
|
/* The name of the image to fetch */
|
||||||
const char* image_name;
|
const char* image_name;
|
||||||
/* The type of image to fetch */
|
/* The type of image to fetch */
|
||||||
int image_type;
|
uint32_t image_type;
|
||||||
}
|
}
|
||||||
rc_api_fetch_image_request_t;
|
rc_api_fetch_image_request_t;
|
||||||
|
|
||||||
|
@ -50,7 +51,7 @@ rc_api_resolve_hash_request_t;
|
||||||
*/
|
*/
|
||||||
typedef struct rc_api_resolve_hash_response_t {
|
typedef struct rc_api_resolve_hash_response_t {
|
||||||
/* The unique identifier of the game, 0 if no match was found */
|
/* The unique identifier of the game, 0 if no match was found */
|
||||||
unsigned game_id;
|
uint32_t game_id;
|
||||||
|
|
||||||
/* Common server-provided response information */
|
/* Common server-provided response information */
|
||||||
rc_api_response_t response;
|
rc_api_response_t response;
|
||||||
|
@ -73,14 +74,14 @@ typedef struct rc_api_fetch_game_data_request_t {
|
||||||
/* The API token from the login request */
|
/* The API token from the login request */
|
||||||
const char* api_token;
|
const char* api_token;
|
||||||
/* The unique identifier of the game */
|
/* The unique identifier of the game */
|
||||||
unsigned game_id;
|
uint32_t game_id;
|
||||||
}
|
}
|
||||||
rc_api_fetch_game_data_request_t;
|
rc_api_fetch_game_data_request_t;
|
||||||
|
|
||||||
/* A leaderboard definition */
|
/* A leaderboard definition */
|
||||||
typedef struct rc_api_leaderboard_definition_t {
|
typedef struct rc_api_leaderboard_definition_t {
|
||||||
/* The unique identifier of the leaderboard */
|
/* The unique identifier of the leaderboard */
|
||||||
unsigned id;
|
uint32_t id;
|
||||||
/* The format to pass to rc_format_value to format the leaderboard value */
|
/* The format to pass to rc_format_value to format the leaderboard value */
|
||||||
int format;
|
int format;
|
||||||
/* The title of the leaderboard */
|
/* The title of the leaderboard */
|
||||||
|
@ -90,20 +91,20 @@ typedef struct rc_api_leaderboard_definition_t {
|
||||||
/* The definition of the leaderboard to be passed to rc_runtime_activate_lboard */
|
/* The definition of the leaderboard to be passed to rc_runtime_activate_lboard */
|
||||||
const char* definition;
|
const char* definition;
|
||||||
/* Non-zero if lower values are better for this leaderboard */
|
/* Non-zero if lower values are better for this leaderboard */
|
||||||
int lower_is_better;
|
uint8_t lower_is_better;
|
||||||
/* Non-zero if the leaderboard should not be displayed in a list of leaderboards */
|
/* Non-zero if the leaderboard should not be displayed in a list of leaderboards */
|
||||||
int hidden;
|
uint8_t hidden;
|
||||||
}
|
}
|
||||||
rc_api_leaderboard_definition_t;
|
rc_api_leaderboard_definition_t;
|
||||||
|
|
||||||
/* An achievement definition */
|
/* An achievement definition */
|
||||||
typedef struct rc_api_achievement_definition_t {
|
typedef struct rc_api_achievement_definition_t {
|
||||||
/* The unique identifier of the achievement */
|
/* The unique identifier of the achievement */
|
||||||
unsigned id;
|
uint32_t id;
|
||||||
/* The number of points the achievement is worth */
|
/* The number of points the achievement is worth */
|
||||||
unsigned points;
|
uint32_t points;
|
||||||
/* The achievement category (core, unofficial) */
|
/* The achievement category (core, unofficial) */
|
||||||
unsigned category;
|
uint32_t category;
|
||||||
/* The title of the achievement */
|
/* The title of the achievement */
|
||||||
const char* title;
|
const char* title;
|
||||||
/* The dscription of the achievement */
|
/* The dscription of the achievement */
|
||||||
|
@ -129,9 +130,9 @@ rc_api_achievement_definition_t;
|
||||||
*/
|
*/
|
||||||
typedef struct rc_api_fetch_game_data_response_t {
|
typedef struct rc_api_fetch_game_data_response_t {
|
||||||
/* The unique identifier of the game */
|
/* The unique identifier of the game */
|
||||||
unsigned id;
|
uint32_t id;
|
||||||
/* The console associated to the game */
|
/* The console associated to the game */
|
||||||
unsigned console_id;
|
uint32_t console_id;
|
||||||
/* The title of the game */
|
/* The title of the game */
|
||||||
const char* title;
|
const char* title;
|
||||||
/* The image name for the game badge */
|
/* The image name for the game badge */
|
||||||
|
@ -142,12 +143,12 @@ typedef struct rc_api_fetch_game_data_response_t {
|
||||||
/* An array of achievements for the game */
|
/* An array of achievements for the game */
|
||||||
rc_api_achievement_definition_t* achievements;
|
rc_api_achievement_definition_t* achievements;
|
||||||
/* The number of items in the achievements array */
|
/* The number of items in the achievements array */
|
||||||
unsigned num_achievements;
|
uint32_t num_achievements;
|
||||||
|
|
||||||
/* An array of leaderboards for the game */
|
/* An array of leaderboards for the game */
|
||||||
rc_api_leaderboard_definition_t* leaderboards;
|
rc_api_leaderboard_definition_t* leaderboards;
|
||||||
/* The number of items in the leaderboards array */
|
/* The number of items in the leaderboards array */
|
||||||
unsigned num_leaderboards;
|
uint32_t num_leaderboards;
|
||||||
|
|
||||||
/* Common server-provided response information */
|
/* Common server-provided response information */
|
||||||
rc_api_response_t response;
|
rc_api_response_t response;
|
||||||
|
@ -170,7 +171,7 @@ typedef struct rc_api_ping_request_t {
|
||||||
/* The API token from the login request */
|
/* The API token from the login request */
|
||||||
const char* api_token;
|
const char* api_token;
|
||||||
/* The unique identifier of the game */
|
/* The unique identifier of the game */
|
||||||
unsigned game_id;
|
uint32_t game_id;
|
||||||
/* (optional) The current rich presence evaluation for the user */
|
/* (optional) The current rich presence evaluation for the user */
|
||||||
const char* rich_presence;
|
const char* rich_presence;
|
||||||
}
|
}
|
||||||
|
@ -201,9 +202,9 @@ typedef struct rc_api_award_achievement_request_t {
|
||||||
/* The API token from the login request */
|
/* The API token from the login request */
|
||||||
const char* api_token;
|
const char* api_token;
|
||||||
/* The unique identifier of the achievement */
|
/* The unique identifier of the achievement */
|
||||||
unsigned achievement_id;
|
uint32_t achievement_id;
|
||||||
/* Non-zero if the achievement was earned in hardcore */
|
/* Non-zero if the achievement was earned in hardcore */
|
||||||
int hardcore;
|
uint32_t hardcore;
|
||||||
/* The hash associated to the game being played */
|
/* The hash associated to the game being played */
|
||||||
const char* game_hash;
|
const char* game_hash;
|
||||||
}
|
}
|
||||||
|
@ -214,14 +215,14 @@ rc_api_award_achievement_request_t;
|
||||||
*/
|
*/
|
||||||
typedef struct rc_api_award_achievement_response_t {
|
typedef struct rc_api_award_achievement_response_t {
|
||||||
/* The unique identifier of the achievement that was awarded */
|
/* The unique identifier of the achievement that was awarded */
|
||||||
unsigned awarded_achievement_id;
|
uint32_t awarded_achievement_id;
|
||||||
/* The updated player score */
|
/* The updated player score */
|
||||||
unsigned new_player_score;
|
uint32_t new_player_score;
|
||||||
/* The updated player softcore score */
|
/* The updated player softcore score */
|
||||||
unsigned new_player_score_softcore;
|
uint32_t new_player_score_softcore;
|
||||||
/* The number of achievements the user has not yet unlocked for this game
|
/* The number of achievements the user has not yet unlocked for this game
|
||||||
* (in hardcore/non-hardcore per hardcore flag in request) */
|
* (in hardcore/non-hardcore per hardcore flag in request) */
|
||||||
unsigned achievements_remaining;
|
uint32_t achievements_remaining;
|
||||||
|
|
||||||
/* Common server-provided response information */
|
/* Common server-provided response information */
|
||||||
rc_api_response_t response;
|
rc_api_response_t response;
|
||||||
|
@ -244,9 +245,9 @@ typedef struct rc_api_submit_lboard_entry_request_t {
|
||||||
/* The API token from the login request */
|
/* The API token from the login request */
|
||||||
const char* api_token;
|
const char* api_token;
|
||||||
/* The unique identifier of the leaderboard */
|
/* The unique identifier of the leaderboard */
|
||||||
unsigned leaderboard_id;
|
uint32_t leaderboard_id;
|
||||||
/* The value being submitted */
|
/* The value being submitted */
|
||||||
int score;
|
int32_t score;
|
||||||
/* The hash associated to the game being played */
|
/* The hash associated to the game being played */
|
||||||
const char* game_hash;
|
const char* game_hash;
|
||||||
}
|
}
|
||||||
|
@ -257,9 +258,9 @@ typedef struct rc_api_lboard_entry_t {
|
||||||
/* The user associated to the entry */
|
/* The user associated to the entry */
|
||||||
const char* username;
|
const char* username;
|
||||||
/* The rank of the entry */
|
/* The rank of the entry */
|
||||||
unsigned rank;
|
uint32_t rank;
|
||||||
/* The value of the entry */
|
/* The value of the entry */
|
||||||
int score;
|
int32_t score;
|
||||||
}
|
}
|
||||||
rc_api_lboard_entry_t;
|
rc_api_lboard_entry_t;
|
||||||
|
|
||||||
|
@ -268,18 +269,18 @@ rc_api_lboard_entry_t;
|
||||||
*/
|
*/
|
||||||
typedef struct rc_api_submit_lboard_entry_response_t {
|
typedef struct rc_api_submit_lboard_entry_response_t {
|
||||||
/* The value that was submitted */
|
/* The value that was submitted */
|
||||||
int submitted_score;
|
int32_t submitted_score;
|
||||||
/* The player's best submitted value */
|
/* The player's best submitted value */
|
||||||
int best_score;
|
int32_t best_score;
|
||||||
/* The player's new rank within the leaderboard */
|
/* The player's new rank within the leaderboard */
|
||||||
unsigned new_rank;
|
uint32_t new_rank;
|
||||||
/* The total number of entries in the leaderboard */
|
/* The total number of entries in the leaderboard */
|
||||||
unsigned num_entries;
|
uint32_t num_entries;
|
||||||
|
|
||||||
/* An array of the top entries for the leaderboard */
|
/* An array of the top entries for the leaderboard */
|
||||||
rc_api_lboard_entry_t* top_entries;
|
rc_api_lboard_entry_t* top_entries;
|
||||||
/* The number of items in the top_entries array */
|
/* The number of items in the top_entries array */
|
||||||
unsigned num_top_entries;
|
uint32_t num_top_entries;
|
||||||
|
|
||||||
/* Common server-provided response information */
|
/* Common server-provided response information */
|
||||||
rc_api_response_t response;
|
rc_api_response_t response;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "rc_api_request.h"
|
#include "rc_api_request.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -34,11 +35,11 @@ typedef struct rc_api_login_response_t {
|
||||||
/* The API token to use for all future requests */
|
/* The API token to use for all future requests */
|
||||||
const char* api_token;
|
const char* api_token;
|
||||||
/* The current score of the player */
|
/* The current score of the player */
|
||||||
unsigned score;
|
uint32_t score;
|
||||||
/* The current softcore score of the player */
|
/* The current softcore score of the player */
|
||||||
unsigned score_softcore;
|
uint32_t score_softcore;
|
||||||
/* The number of unread messages waiting for the player on the web site */
|
/* The number of unread messages waiting for the player on the web site */
|
||||||
unsigned num_unread_messages;
|
uint32_t num_unread_messages;
|
||||||
/* The preferred name to display for the player */
|
/* The preferred name to display for the player */
|
||||||
const char* display_name;
|
const char* display_name;
|
||||||
|
|
||||||
|
@ -63,7 +64,7 @@ typedef struct rc_api_start_session_request_t {
|
||||||
/* The API token from the login request */
|
/* The API token from the login request */
|
||||||
const char* api_token;
|
const char* api_token;
|
||||||
/* The unique identifier of the game */
|
/* The unique identifier of the game */
|
||||||
unsigned game_id;
|
uint32_t game_id;
|
||||||
}
|
}
|
||||||
rc_api_start_session_request_t;
|
rc_api_start_session_request_t;
|
||||||
|
|
||||||
|
@ -72,7 +73,7 @@ rc_api_start_session_request_t;
|
||||||
*/
|
*/
|
||||||
typedef struct rc_api_unlock_entry_t {
|
typedef struct rc_api_unlock_entry_t {
|
||||||
/* The unique identifier of the unlocked achievement */
|
/* The unique identifier of the unlocked achievement */
|
||||||
unsigned achievement_id;
|
uint32_t achievement_id;
|
||||||
/* When the achievement was unlocked */
|
/* When the achievement was unlocked */
|
||||||
time_t when;
|
time_t when;
|
||||||
}
|
}
|
||||||
|
@ -88,9 +89,9 @@ typedef struct rc_api_start_session_response_t {
|
||||||
rc_api_unlock_entry_t* unlocks;
|
rc_api_unlock_entry_t* unlocks;
|
||||||
|
|
||||||
/* The number of items in the hardcore_unlocks array */
|
/* The number of items in the hardcore_unlocks array */
|
||||||
unsigned num_hardcore_unlocks;
|
uint32_t num_hardcore_unlocks;
|
||||||
/* The number of items in the unlocks array */
|
/* The number of items in the unlocks array */
|
||||||
unsigned num_unlocks;
|
uint32_t num_unlocks;
|
||||||
|
|
||||||
/* The server timestamp when the response was generated */
|
/* The server timestamp when the response was generated */
|
||||||
time_t server_now;
|
time_t server_now;
|
||||||
|
@ -116,9 +117,9 @@ typedef struct rc_api_fetch_user_unlocks_request_t {
|
||||||
/* The API token from the login request */
|
/* The API token from the login request */
|
||||||
const char* api_token;
|
const char* api_token;
|
||||||
/* The unique identifier of the game */
|
/* The unique identifier of the game */
|
||||||
unsigned game_id;
|
uint32_t game_id;
|
||||||
/* Non-zero to fetch hardcore unlocks, 0 to fetch non-hardcore unlocks */
|
/* Non-zero to fetch hardcore unlocks, 0 to fetch non-hardcore unlocks */
|
||||||
int hardcore;
|
uint32_t hardcore;
|
||||||
}
|
}
|
||||||
rc_api_fetch_user_unlocks_request_t;
|
rc_api_fetch_user_unlocks_request_t;
|
||||||
|
|
||||||
|
@ -127,9 +128,9 @@ rc_api_fetch_user_unlocks_request_t;
|
||||||
*/
|
*/
|
||||||
typedef struct rc_api_fetch_user_unlocks_response_t {
|
typedef struct rc_api_fetch_user_unlocks_response_t {
|
||||||
/* An array of achievement IDs previously unlocked by the user */
|
/* An array of achievement IDs previously unlocked by the user */
|
||||||
unsigned* achievement_ids;
|
uint32_t* achievement_ids;
|
||||||
/* The number of items in the achievement_ids array */
|
/* The number of items in the achievement_ids array */
|
||||||
unsigned num_achievement_ids;
|
uint32_t num_achievement_ids;
|
||||||
|
|
||||||
/* Common server-provided response information */
|
/* Common server-provided response information */
|
||||||
rc_api_response_t response;
|
rc_api_response_t response;
|
||||||
|
|
|
@ -146,8 +146,7 @@ void rc_client_abort_async(rc_client_t* client, rc_client_async_handle_t* async_
|
||||||
* Sets the logging level and provides a callback to be called to do the logging.
|
* Sets the logging level and provides a callback to be called to do the logging.
|
||||||
*/
|
*/
|
||||||
void rc_client_enable_logging(rc_client_t* client, int level, rc_client_message_callback_t callback);
|
void rc_client_enable_logging(rc_client_t* client, int level, rc_client_message_callback_t callback);
|
||||||
enum
|
enum {
|
||||||
{
|
|
||||||
RC_CLIENT_LOG_LEVEL_NONE = 0,
|
RC_CLIENT_LOG_LEVEL_NONE = 0,
|
||||||
RC_CLIENT_LOG_LEVEL_ERROR = 1,
|
RC_CLIENT_LOG_LEVEL_ERROR = 1,
|
||||||
RC_CLIENT_LOG_LEVEL_WARN = 2,
|
RC_CLIENT_LOG_LEVEL_WARN = 2,
|
||||||
|
@ -582,6 +581,8 @@ typedef struct rc_client_server_error_t
|
||||||
{
|
{
|
||||||
const char* error_message;
|
const char* error_message;
|
||||||
const char* api;
|
const char* api;
|
||||||
|
int result;
|
||||||
|
uint32_t related_id;
|
||||||
} rc_client_server_error_t;
|
} rc_client_server_error_t;
|
||||||
|
|
||||||
typedef struct rc_client_event_t
|
typedef struct rc_client_event_t
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
/*****************************************************************************\
|
/*****************************************************************************\
|
||||||
| Console identifiers |
|
| Console identifiers |
|
||||||
\*****************************************************************************/
|
\*****************************************************************************/
|
||||||
|
@ -113,21 +115,21 @@ enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct rc_memory_region_t {
|
typedef struct rc_memory_region_t {
|
||||||
unsigned start_address; /* first address of block as queried by RetroAchievements */
|
uint32_t start_address; /* first address of block as queried by RetroAchievements */
|
||||||
unsigned end_address; /* last address of block as queried by RetroAchievements */
|
uint32_t end_address; /* last address of block as queried by RetroAchievements */
|
||||||
unsigned real_address; /* real address for first address of block */
|
uint32_t real_address; /* real address for first address of block */
|
||||||
char type; /* RC_MEMORY_TYPE_ for block */
|
uint8_t type; /* RC_MEMORY_TYPE_ for block */
|
||||||
const char* description; /* short description of block */
|
const char* description; /* short description of block */
|
||||||
}
|
}
|
||||||
rc_memory_region_t;
|
rc_memory_region_t;
|
||||||
|
|
||||||
typedef struct rc_memory_regions_t {
|
typedef struct rc_memory_regions_t {
|
||||||
const rc_memory_region_t* region;
|
const rc_memory_region_t* region;
|
||||||
unsigned num_regions;
|
uint32_t num_regions;
|
||||||
}
|
}
|
||||||
rc_memory_regions_t;
|
rc_memory_regions_t;
|
||||||
|
|
||||||
const rc_memory_regions_t* rc_console_memory_regions(int console_id);
|
const rc_memory_regions_t* rc_console_memory_regions(uint32_t console_id);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -42,7 +42,10 @@ enum {
|
||||||
RC_NO_GAME_LOADED = -29,
|
RC_NO_GAME_LOADED = -29,
|
||||||
RC_HARDCORE_DISABLED = -30,
|
RC_HARDCORE_DISABLED = -30,
|
||||||
RC_ABORTED = -31,
|
RC_ABORTED = -31,
|
||||||
RC_NO_RESPONSE = -32
|
RC_NO_RESPONSE = -32,
|
||||||
|
RC_ACCESS_DENIED = -33,
|
||||||
|
RC_INVALID_CREDENTIALS = -34,
|
||||||
|
RC_EXPIRED_TOKEN = -35
|
||||||
};
|
};
|
||||||
|
|
||||||
const char* rc_error_str(int ret);
|
const char* rc_error_str(int ret);
|
||||||
|
|
|
@ -8,6 +8,7 @@ extern "C" {
|
||||||
#include "rc_error.h"
|
#include "rc_error.h"
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
/*****************************************************************************\
|
/*****************************************************************************\
|
||||||
| Forward Declarations (defined in rc_runtime_types.h) |
|
| Forward Declarations (defined in rc_runtime_types.h) |
|
||||||
|
@ -34,32 +35,32 @@ typedef struct rc_value_t rc_value_t;
|
||||||
* num_bytes is greater than 1, the value is read in little-endian from
|
* num_bytes is greater than 1, the value is read in little-endian from
|
||||||
* memory.
|
* memory.
|
||||||
*/
|
*/
|
||||||
typedef unsigned (*rc_runtime_peek_t)(unsigned address, unsigned num_bytes, void* ud);
|
typedef uint32_t(*rc_runtime_peek_t)(uint32_t address, uint32_t num_bytes, void* ud);
|
||||||
|
|
||||||
/*****************************************************************************\
|
/*****************************************************************************\
|
||||||
| Runtime |
|
| Runtime |
|
||||||
\*****************************************************************************/
|
\*****************************************************************************/
|
||||||
|
|
||||||
typedef struct rc_runtime_trigger_t {
|
typedef struct rc_runtime_trigger_t {
|
||||||
unsigned id;
|
uint32_t id;
|
||||||
rc_trigger_t* trigger;
|
rc_trigger_t* trigger;
|
||||||
void* buffer;
|
void* buffer;
|
||||||
rc_memref_t* invalid_memref;
|
rc_memref_t* invalid_memref;
|
||||||
unsigned char md5[16];
|
uint8_t md5[16];
|
||||||
int serialized_size;
|
int32_t serialized_size;
|
||||||
char owns_memrefs;
|
uint8_t owns_memrefs;
|
||||||
}
|
}
|
||||||
rc_runtime_trigger_t;
|
rc_runtime_trigger_t;
|
||||||
|
|
||||||
typedef struct rc_runtime_lboard_t {
|
typedef struct rc_runtime_lboard_t {
|
||||||
unsigned id;
|
uint32_t id;
|
||||||
int value;
|
int32_t value;
|
||||||
rc_lboard_t* lboard;
|
rc_lboard_t* lboard;
|
||||||
void* buffer;
|
void* buffer;
|
||||||
rc_memref_t* invalid_memref;
|
rc_memref_t* invalid_memref;
|
||||||
unsigned char md5[16];
|
uint8_t md5[16];
|
||||||
int serialized_size;
|
uint32_t serialized_size;
|
||||||
char owns_memrefs;
|
uint8_t owns_memrefs;
|
||||||
}
|
}
|
||||||
rc_runtime_lboard_t;
|
rc_runtime_lboard_t;
|
||||||
|
|
||||||
|
@ -67,19 +68,19 @@ typedef struct rc_runtime_richpresence_t {
|
||||||
rc_richpresence_t* richpresence;
|
rc_richpresence_t* richpresence;
|
||||||
void* buffer;
|
void* buffer;
|
||||||
struct rc_runtime_richpresence_t* previous;
|
struct rc_runtime_richpresence_t* previous;
|
||||||
unsigned char md5[16];
|
uint8_t md5[16];
|
||||||
char owns_memrefs;
|
uint8_t owns_memrefs;
|
||||||
}
|
}
|
||||||
rc_runtime_richpresence_t;
|
rc_runtime_richpresence_t;
|
||||||
|
|
||||||
typedef struct rc_runtime_t {
|
typedef struct rc_runtime_t {
|
||||||
rc_runtime_trigger_t* triggers;
|
rc_runtime_trigger_t* triggers;
|
||||||
unsigned trigger_count;
|
uint32_t trigger_count;
|
||||||
unsigned trigger_capacity;
|
uint32_t trigger_capacity;
|
||||||
|
|
||||||
rc_runtime_lboard_t* lboards;
|
rc_runtime_lboard_t* lboards;
|
||||||
unsigned lboard_count;
|
uint32_t lboard_count;
|
||||||
unsigned lboard_capacity;
|
uint32_t lboard_capacity;
|
||||||
|
|
||||||
rc_runtime_richpresence_t* richpresence;
|
rc_runtime_richpresence_t* richpresence;
|
||||||
|
|
||||||
|
@ -89,7 +90,7 @@ typedef struct rc_runtime_t {
|
||||||
rc_value_t* variables;
|
rc_value_t* variables;
|
||||||
rc_value_t** next_variable;
|
rc_value_t** next_variable;
|
||||||
|
|
||||||
char owns_self;
|
uint8_t owns_self;
|
||||||
}
|
}
|
||||||
rc_runtime_t;
|
rc_runtime_t;
|
||||||
|
|
||||||
|
@ -97,20 +98,20 @@ rc_runtime_t* rc_runtime_alloc(void);
|
||||||
void rc_runtime_init(rc_runtime_t* runtime);
|
void rc_runtime_init(rc_runtime_t* runtime);
|
||||||
void rc_runtime_destroy(rc_runtime_t* runtime);
|
void rc_runtime_destroy(rc_runtime_t* runtime);
|
||||||
|
|
||||||
int rc_runtime_activate_achievement(rc_runtime_t* runtime, unsigned id, const char* memaddr, lua_State* L, int funcs_idx);
|
int rc_runtime_activate_achievement(rc_runtime_t* runtime, uint32_t id, const char* memaddr, lua_State* L, int funcs_idx);
|
||||||
void rc_runtime_deactivate_achievement(rc_runtime_t* runtime, unsigned id);
|
void rc_runtime_deactivate_achievement(rc_runtime_t* runtime, uint32_t id);
|
||||||
rc_trigger_t* rc_runtime_get_achievement(const rc_runtime_t* runtime, unsigned id);
|
rc_trigger_t* rc_runtime_get_achievement(const rc_runtime_t* runtime, uint32_t id);
|
||||||
int rc_runtime_get_achievement_measured(const rc_runtime_t* runtime, unsigned id, unsigned* measured_value, unsigned* measured_target);
|
int rc_runtime_get_achievement_measured(const rc_runtime_t* runtime, uint32_t id, unsigned* measured_value, unsigned* measured_target);
|
||||||
int rc_runtime_format_achievement_measured(const rc_runtime_t* runtime, unsigned id, char *buffer, size_t buffer_size);
|
int rc_runtime_format_achievement_measured(const rc_runtime_t* runtime, uint32_t id, char *buffer, size_t buffer_size);
|
||||||
|
|
||||||
int rc_runtime_activate_lboard(rc_runtime_t* runtime, unsigned id, const char* memaddr, lua_State* L, int funcs_idx);
|
int rc_runtime_activate_lboard(rc_runtime_t* runtime, uint32_t id, const char* memaddr, lua_State* L, int funcs_idx);
|
||||||
void rc_runtime_deactivate_lboard(rc_runtime_t* runtime, unsigned id);
|
void rc_runtime_deactivate_lboard(rc_runtime_t* runtime, uint32_t id);
|
||||||
rc_lboard_t* rc_runtime_get_lboard(const rc_runtime_t* runtime, unsigned id);
|
rc_lboard_t* rc_runtime_get_lboard(const rc_runtime_t* runtime, uint32_t id);
|
||||||
int rc_runtime_format_lboard_value(char* buffer, int size, int value, int format);
|
int rc_runtime_format_lboard_value(char* buffer, int size, int32_t value, int format);
|
||||||
|
|
||||||
|
|
||||||
int rc_runtime_activate_richpresence(rc_runtime_t* runtime, const char* script, lua_State* L, int funcs_idx);
|
int rc_runtime_activate_richpresence(rc_runtime_t* runtime, const char* script, lua_State* L, int funcs_idx);
|
||||||
int rc_runtime_get_richpresence(const rc_runtime_t* runtime, char* buffer, unsigned buffersize, rc_runtime_peek_t peek, void* peek_ud, lua_State* L);
|
int rc_runtime_get_richpresence(const rc_runtime_t* runtime, char* buffer, size_t buffersize, rc_runtime_peek_t peek, void* peek_ud, lua_State* L);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
RC_RUNTIME_EVENT_ACHIEVEMENT_ACTIVATED, /* from WAITING, PAUSED, or PRIMED to ACTIVE */
|
RC_RUNTIME_EVENT_ACHIEVEMENT_ACTIVATED, /* from WAITING, PAUSED, or PRIMED to ACTIVE */
|
||||||
|
@ -129,9 +130,9 @@ enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct rc_runtime_event_t {
|
typedef struct rc_runtime_event_t {
|
||||||
unsigned id;
|
uint32_t id;
|
||||||
int value;
|
int32_t value;
|
||||||
char type;
|
uint8_t type;
|
||||||
}
|
}
|
||||||
rc_runtime_event_t;
|
rc_runtime_event_t;
|
||||||
|
|
||||||
|
@ -140,13 +141,13 @@ typedef void (*rc_runtime_event_handler_t)(const rc_runtime_event_t* runtime_eve
|
||||||
void rc_runtime_do_frame(rc_runtime_t* runtime, rc_runtime_event_handler_t event_handler, rc_runtime_peek_t peek, void* ud, lua_State* L);
|
void rc_runtime_do_frame(rc_runtime_t* runtime, rc_runtime_event_handler_t event_handler, rc_runtime_peek_t peek, void* ud, lua_State* L);
|
||||||
void rc_runtime_reset(rc_runtime_t* runtime);
|
void rc_runtime_reset(rc_runtime_t* runtime);
|
||||||
|
|
||||||
typedef int (*rc_runtime_validate_address_t)(unsigned address);
|
typedef int (*rc_runtime_validate_address_t)(uint32_t address);
|
||||||
void rc_runtime_validate_addresses(rc_runtime_t* runtime, rc_runtime_event_handler_t event_handler, rc_runtime_validate_address_t validate_handler);
|
void rc_runtime_validate_addresses(rc_runtime_t* runtime, rc_runtime_event_handler_t event_handler, rc_runtime_validate_address_t validate_handler);
|
||||||
void rc_runtime_invalidate_address(rc_runtime_t* runtime, unsigned address);
|
void rc_runtime_invalidate_address(rc_runtime_t* runtime, uint32_t address);
|
||||||
|
|
||||||
int rc_runtime_progress_size(const rc_runtime_t* runtime, lua_State* L);
|
int rc_runtime_progress_size(const rc_runtime_t* runtime, lua_State* L);
|
||||||
int rc_runtime_serialize_progress(void* buffer, const rc_runtime_t* runtime, lua_State* L);
|
int rc_runtime_serialize_progress(void* buffer, const rc_runtime_t* runtime, lua_State* L);
|
||||||
int rc_runtime_deserialize_progress(rc_runtime_t* runtime, const unsigned char* serialized, lua_State* L);
|
int rc_runtime_deserialize_progress(rc_runtime_t* runtime, const uint8_t* serialized, lua_State* L);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,9 @@ extern "C" {
|
||||||
|
|
||||||
#include "rc_error.h"
|
#include "rc_error.h"
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#ifndef RC_RUNTIME_H /* prevents pedantic redefiniton error */
|
#ifndef RC_RUNTIME_H /* prevents pedantic redefiniton error */
|
||||||
|
|
||||||
typedef struct lua_State lua_State;
|
typedef struct lua_State lua_State;
|
||||||
|
@ -28,7 +31,7 @@ typedef struct rc_value_t rc_value_t;
|
||||||
* num_bytes is greater than 1, the value is read in little-endian from
|
* num_bytes is greater than 1, the value is read in little-endian from
|
||||||
* memory.
|
* memory.
|
||||||
*/
|
*/
|
||||||
typedef unsigned (*rc_peek_t)(unsigned address, unsigned num_bytes, void* ud);
|
typedef uint32_t(*rc_peek_t)(uint32_t address, uint32_t num_bytes, void* ud);
|
||||||
|
|
||||||
/*****************************************************************************\
|
/*****************************************************************************\
|
||||||
| Memory References |
|
| Memory References |
|
||||||
|
@ -63,19 +66,19 @@ enum {
|
||||||
|
|
||||||
typedef struct rc_memref_value_t {
|
typedef struct rc_memref_value_t {
|
||||||
/* The current value of this memory reference. */
|
/* The current value of this memory reference. */
|
||||||
unsigned value;
|
uint32_t value;
|
||||||
/* The last differing value of this memory reference. */
|
/* The last differing value of this memory reference. */
|
||||||
unsigned prior;
|
uint32_t prior;
|
||||||
|
|
||||||
/* The size of the value. */
|
/* The size of the value. */
|
||||||
char size;
|
uint8_t size;
|
||||||
/* True if the value changed this frame. */
|
/* True if the value changed this frame. */
|
||||||
char changed;
|
uint8_t changed;
|
||||||
/* The value type of the value (for variables) */
|
/* The value type of the value (for variables) */
|
||||||
char type;
|
uint8_t type;
|
||||||
/* True if the reference will be used in indirection.
|
/* True if the reference will be used in indirection.
|
||||||
* NOTE: This is actually a property of the rc_memref_t, but we put it here to save space */
|
* NOTE: This is actually a property of the rc_memref_t, but we put it here to save space */
|
||||||
char is_indirect;
|
uint8_t is_indirect;
|
||||||
}
|
}
|
||||||
rc_memref_value_t;
|
rc_memref_value_t;
|
||||||
|
|
||||||
|
@ -84,7 +87,7 @@ struct rc_memref_t {
|
||||||
rc_memref_value_t value;
|
rc_memref_value_t value;
|
||||||
|
|
||||||
/* The memory address of this variable. */
|
/* The memory address of this variable. */
|
||||||
unsigned address;
|
uint32_t address;
|
||||||
|
|
||||||
/* The next memory reference in the chain. */
|
/* The next memory reference in the chain. */
|
||||||
rc_memref_t* next;
|
rc_memref_t* next;
|
||||||
|
@ -112,7 +115,7 @@ typedef struct rc_operand_t {
|
||||||
rc_memref_t* memref;
|
rc_memref_t* memref;
|
||||||
|
|
||||||
/* An integer value. */
|
/* An integer value. */
|
||||||
unsigned num;
|
uint32_t num;
|
||||||
|
|
||||||
/* A floating point value. */
|
/* A floating point value. */
|
||||||
double dbl;
|
double dbl;
|
||||||
|
@ -122,10 +125,10 @@ typedef struct rc_operand_t {
|
||||||
} value;
|
} value;
|
||||||
|
|
||||||
/* specifies which member of the value union is being used */
|
/* specifies which member of the value union is being used */
|
||||||
char type;
|
uint8_t type;
|
||||||
|
|
||||||
/* the actual RC_MEMSIZE of the operand - memref.size may differ */
|
/* the actual RC_MEMSIZE of the operand - memref.size may differ */
|
||||||
char size;
|
uint8_t size;
|
||||||
}
|
}
|
||||||
rc_operand_t;
|
rc_operand_t;
|
||||||
|
|
||||||
|
@ -183,27 +186,27 @@ struct rc_condition_t {
|
||||||
rc_operand_t operand2;
|
rc_operand_t operand2;
|
||||||
|
|
||||||
/* Required hits to fire this condition. */
|
/* Required hits to fire this condition. */
|
||||||
unsigned required_hits;
|
uint32_t required_hits;
|
||||||
/* Number of hits so far. */
|
/* Number of hits so far. */
|
||||||
unsigned current_hits;
|
uint32_t current_hits;
|
||||||
|
|
||||||
/* The next condition in the chain. */
|
/* The next condition in the chain. */
|
||||||
rc_condition_t* next;
|
rc_condition_t* next;
|
||||||
|
|
||||||
/* The type of the condition. */
|
/* The type of the condition. (RC_CONDITION_*) */
|
||||||
char type;
|
uint8_t type;
|
||||||
|
|
||||||
/* The comparison operator to use. */
|
/* The comparison operator to use. (RC_OPERATOR_*) */
|
||||||
char oper; /* operator is a reserved word in C++. */
|
uint8_t oper; /* operator is a reserved word in C++. */
|
||||||
|
|
||||||
/* Set if the condition needs to processed as part of the "check if paused" pass. */
|
/* Set if the condition needs to processed as part of the "check if paused" pass. (bool) */
|
||||||
char pause;
|
uint8_t pause;
|
||||||
|
|
||||||
/* Whether or not the condition evaluated true on the last check */
|
/* Whether or not the condition evaluated true on the last check. (bool) */
|
||||||
char is_true;
|
uint8_t is_true;
|
||||||
|
|
||||||
/* Unique identifier of optimized comparator to use */
|
/* Unique identifier of optimized comparator to use. (RC_PROCESSING_COMPARE_*) */
|
||||||
char optimized_comparator;
|
uint8_t optimized_comparator;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*****************************************************************************\
|
/*****************************************************************************\
|
||||||
|
@ -220,13 +223,13 @@ struct rc_condset_t {
|
||||||
rc_condition_t* conditions;
|
rc_condition_t* conditions;
|
||||||
|
|
||||||
/* True if any condition in the set is a pause condition. */
|
/* True if any condition in the set is a pause condition. */
|
||||||
char has_pause;
|
uint8_t has_pause;
|
||||||
|
|
||||||
/* True if the set is currently paused. */
|
/* True if the set is currently paused. */
|
||||||
char is_paused;
|
uint8_t is_paused;
|
||||||
|
|
||||||
/* True if the set has indirect memory references. */
|
/* True if the set has indirect memory references. */
|
||||||
char has_indirect_memrefs;
|
uint8_t has_indirect_memrefs;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*****************************************************************************\
|
/*****************************************************************************\
|
||||||
|
@ -255,22 +258,22 @@ struct rc_trigger_t {
|
||||||
rc_memref_t* memrefs;
|
rc_memref_t* memrefs;
|
||||||
|
|
||||||
/* The current state of the MEASURED condition. */
|
/* The current state of the MEASURED condition. */
|
||||||
unsigned measured_value;
|
uint32_t measured_value;
|
||||||
|
|
||||||
/* The target state of the MEASURED condition */
|
/* The target state of the MEASURED condition */
|
||||||
unsigned measured_target;
|
uint32_t measured_target;
|
||||||
|
|
||||||
/* The current state of the trigger */
|
/* The current state of the trigger */
|
||||||
char state;
|
uint8_t state;
|
||||||
|
|
||||||
/* True if at least one condition has a non-zero hit count */
|
/* True if at least one condition has a non-zero hit count */
|
||||||
char has_hits;
|
uint8_t has_hits;
|
||||||
|
|
||||||
/* True if at least one condition has a non-zero required hit count */
|
/* True if at least one condition has a non-zero required hit count */
|
||||||
char has_required_hits;
|
uint8_t has_required_hits;
|
||||||
|
|
||||||
/* True if the measured value should be displayed as a percentage */
|
/* True if the measured value should be displayed as a percentage */
|
||||||
char measured_as_percent;
|
uint8_t measured_as_percent;
|
||||||
};
|
};
|
||||||
|
|
||||||
int rc_trigger_size(const char* memaddr);
|
int rc_trigger_size(const char* memaddr);
|
||||||
|
@ -302,7 +305,7 @@ struct rc_value_t {
|
||||||
|
|
||||||
int rc_value_size(const char* memaddr);
|
int rc_value_size(const char* memaddr);
|
||||||
rc_value_t* rc_parse_value(void* buffer, const char* memaddr, lua_State* L, int funcs_ndx);
|
rc_value_t* rc_parse_value(void* buffer, const char* memaddr, lua_State* L, int funcs_ndx);
|
||||||
int rc_evaluate_value(rc_value_t* value, rc_peek_t peek, void* ud, lua_State* L);
|
int32_t rc_evaluate_value(rc_value_t* value, rc_peek_t peek, void* ud, lua_State* L);
|
||||||
|
|
||||||
/*****************************************************************************\
|
/*****************************************************************************\
|
||||||
| Leaderboards |
|
| Leaderboards |
|
||||||
|
@ -327,12 +330,12 @@ struct rc_lboard_t {
|
||||||
rc_value_t* progress;
|
rc_value_t* progress;
|
||||||
rc_memref_t* memrefs;
|
rc_memref_t* memrefs;
|
||||||
|
|
||||||
char state;
|
uint8_t state;
|
||||||
};
|
};
|
||||||
|
|
||||||
int rc_lboard_size(const char* memaddr);
|
int rc_lboard_size(const char* memaddr);
|
||||||
rc_lboard_t* rc_parse_lboard(void* buffer, const char* memaddr, lua_State* L, int funcs_ndx);
|
rc_lboard_t* rc_parse_lboard(void* buffer, const char* memaddr, lua_State* L, int funcs_ndx);
|
||||||
int rc_evaluate_lboard(rc_lboard_t* lboard, int* value, rc_peek_t peek, void* peek_ud, lua_State* L);
|
int rc_evaluate_lboard(rc_lboard_t* lboard, int32_t* value, rc_peek_t peek, void* peek_ud, lua_State* L);
|
||||||
void rc_reset_lboard(rc_lboard_t* lboard);
|
void rc_reset_lboard(rc_lboard_t* lboard);
|
||||||
|
|
||||||
/*****************************************************************************\
|
/*****************************************************************************\
|
||||||
|
@ -357,7 +360,7 @@ enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
int rc_parse_format(const char* format_str);
|
int rc_parse_format(const char* format_str);
|
||||||
int rc_format_value(char* buffer, int size, int value, int format);
|
int rc_format_value(char* buffer, int size, int32_t value, int format);
|
||||||
|
|
||||||
/*****************************************************************************\
|
/*****************************************************************************\
|
||||||
| Rich Presence |
|
| Rich Presence |
|
||||||
|
@ -366,8 +369,8 @@ int rc_format_value(char* buffer, int size, int value, int format);
|
||||||
typedef struct rc_richpresence_lookup_item_t rc_richpresence_lookup_item_t;
|
typedef struct rc_richpresence_lookup_item_t rc_richpresence_lookup_item_t;
|
||||||
|
|
||||||
struct rc_richpresence_lookup_item_t {
|
struct rc_richpresence_lookup_item_t {
|
||||||
unsigned first;
|
uint32_t first;
|
||||||
unsigned last;
|
uint32_t last;
|
||||||
rc_richpresence_lookup_item_t* left;
|
rc_richpresence_lookup_item_t* left;
|
||||||
rc_richpresence_lookup_item_t* right;
|
rc_richpresence_lookup_item_t* right;
|
||||||
const char* label;
|
const char* label;
|
||||||
|
@ -380,7 +383,7 @@ struct rc_richpresence_lookup_t {
|
||||||
rc_richpresence_lookup_t* next;
|
rc_richpresence_lookup_t* next;
|
||||||
const char* name;
|
const char* name;
|
||||||
const char* default_label;
|
const char* default_label;
|
||||||
unsigned short format;
|
uint8_t format;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct rc_richpresence_display_part_t rc_richpresence_display_part_t;
|
typedef struct rc_richpresence_display_part_t rc_richpresence_display_part_t;
|
||||||
|
@ -390,7 +393,7 @@ struct rc_richpresence_display_part_t {
|
||||||
const char* text;
|
const char* text;
|
||||||
rc_richpresence_lookup_t* lookup;
|
rc_richpresence_lookup_t* lookup;
|
||||||
rc_memref_value_t *value;
|
rc_memref_value_t *value;
|
||||||
unsigned short display_type;
|
uint8_t display_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct rc_richpresence_display_t rc_richpresence_display_t;
|
typedef struct rc_richpresence_display_t rc_richpresence_display_t;
|
||||||
|
@ -411,9 +414,9 @@ struct rc_richpresence_t {
|
||||||
int rc_richpresence_size(const char* script);
|
int rc_richpresence_size(const char* script);
|
||||||
int rc_richpresence_size_lines(const char* script, int* lines_read);
|
int rc_richpresence_size_lines(const char* script, int* lines_read);
|
||||||
rc_richpresence_t* rc_parse_richpresence(void* buffer, const char* script, lua_State* L, int funcs_ndx);
|
rc_richpresence_t* rc_parse_richpresence(void* buffer, const char* script, lua_State* L, int funcs_ndx);
|
||||||
int rc_evaluate_richpresence(rc_richpresence_t* richpresence, char* buffer, unsigned buffersize, rc_peek_t peek, void* peek_ud, lua_State* L);
|
int rc_evaluate_richpresence(rc_richpresence_t* richpresence, char* buffer, size_t buffersize, rc_peek_t peek, void* peek_ud, lua_State* L);
|
||||||
void rc_update_richpresence(rc_richpresence_t* richpresence, rc_peek_t peek, void* peek_ud, lua_State* L);
|
void rc_update_richpresence(rc_richpresence_t* richpresence, rc_peek_t peek, void* peek_ud, lua_State* L);
|
||||||
int rc_get_richpresence_display_string(rc_richpresence_t* richpresence, char* buffer, unsigned buffersize, rc_peek_t peek, void* peek_ud, lua_State* L);
|
int rc_get_richpresence_display_string(rc_richpresence_t* richpresence, char* buffer, size_t buffersize, rc_peek_t peek, void* peek_ud, lua_State* L);
|
||||||
void rc_reset_richpresence(rc_richpresence_t* self);
|
void rc_reset_richpresence(rc_richpresence_t* self);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
<ClCompile Include="src\rapi\rc_api_runtime.c" />
|
<ClCompile Include="src\rapi\rc_api_runtime.c" />
|
||||||
<ClCompile Include="src\rapi\rc_api_user.c" />
|
<ClCompile Include="src\rapi\rc_api_user.c" />
|
||||||
<ClCompile Include="src\rcheevos\alloc.c" />
|
<ClCompile Include="src\rcheevos\alloc.c" />
|
||||||
<ClCompile Include="src\rcheevos\compat.c" />
|
|
||||||
<ClCompile Include="src\rcheevos\condition.c" />
|
<ClCompile Include="src\rcheevos\condition.c" />
|
||||||
<ClCompile Include="src\rcheevos\condset.c" />
|
<ClCompile Include="src\rcheevos\condset.c" />
|
||||||
<ClCompile Include="src\rcheevos\consoleinfo.c" />
|
<ClCompile Include="src\rcheevos\consoleinfo.c" />
|
||||||
|
@ -16,12 +15,15 @@
|
||||||
<ClCompile Include="src\rcheevos\lboard.c" />
|
<ClCompile Include="src\rcheevos\lboard.c" />
|
||||||
<ClCompile Include="src\rcheevos\memref.c" />
|
<ClCompile Include="src\rcheevos\memref.c" />
|
||||||
<ClCompile Include="src\rcheevos\operand.c" />
|
<ClCompile Include="src\rcheevos\operand.c" />
|
||||||
<ClCompile Include="src\rcheevos\rc_client.c" />
|
<ClCompile Include="src\rcheevos\rc_validate.c" />
|
||||||
<ClCompile Include="src\rcheevos\richpresence.c" />
|
<ClCompile Include="src\rcheevos\richpresence.c" />
|
||||||
<ClCompile Include="src\rcheevos\runtime.c" />
|
<ClCompile Include="src\rcheevos\runtime.c" />
|
||||||
<ClCompile Include="src\rcheevos\runtime_progress.c" />
|
<ClCompile Include="src\rcheevos\runtime_progress.c" />
|
||||||
<ClCompile Include="src\rcheevos\trigger.c" />
|
<ClCompile Include="src\rcheevos\trigger.c" />
|
||||||
<ClCompile Include="src\rcheevos\value.c" />
|
<ClCompile Include="src\rcheevos\value.c" />
|
||||||
|
<ClCompile Include="src\rc_client.c" />
|
||||||
|
<ClCompile Include="src\rc_compat.c" />
|
||||||
|
<ClCompile Include="src\rc_util.c" />
|
||||||
<ClCompile Include="src\rhash\cdreader.c" />
|
<ClCompile Include="src\rhash\cdreader.c" />
|
||||||
<ClCompile Include="src\rhash\hash.c" />
|
<ClCompile Include="src\rhash\hash.c" />
|
||||||
<ClCompile Include="src\rhash\md5.c" />
|
<ClCompile Include="src\rhash\md5.c" />
|
||||||
|
@ -42,9 +44,12 @@
|
||||||
<ClInclude Include="include\rc_runtime_types.h" />
|
<ClInclude Include="include\rc_runtime_types.h" />
|
||||||
<ClInclude Include="include\rc_url.h" />
|
<ClInclude Include="include\rc_url.h" />
|
||||||
<ClInclude Include="src\rapi\rc_api_common.h" />
|
<ClInclude Include="src\rapi\rc_api_common.h" />
|
||||||
<ClInclude Include="src\rcheevos\rc_client_internal.h" />
|
|
||||||
<ClInclude Include="src\rcheevos\rc_compat.h" />
|
|
||||||
<ClInclude Include="src\rcheevos\rc_internal.h" />
|
<ClInclude Include="src\rcheevos\rc_internal.h" />
|
||||||
|
<ClInclude Include="src\rcheevos\rc_validate.h" />
|
||||||
|
<ClInclude Include="src\rc_client_internal.h" />
|
||||||
|
<ClInclude Include="src\rc_compat.h" />
|
||||||
|
<ClInclude Include="src\rc_util.h" />
|
||||||
|
<ClInclude Include="src\rc_version.h" />
|
||||||
<ClInclude Include="src\rhash\md5.h" />
|
<ClInclude Include="src\rhash\md5.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Globals">
|
<PropertyGroup Label="Globals">
|
||||||
|
|
|
@ -21,48 +21,6 @@
|
||||||
<ClCompile Include="src\rurl\url.c">
|
<ClCompile Include="src\rurl\url.c">
|
||||||
<Filter>rurl</Filter>
|
<Filter>rurl</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="src\rcheevos\consoleinfo.c">
|
|
||||||
<Filter>rcheevos</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\rcheevos\format.c">
|
|
||||||
<Filter>rcheevos</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\rcheevos\lboard.c">
|
|
||||||
<Filter>rcheevos</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\rcheevos\memref.c">
|
|
||||||
<Filter>rcheevos</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\rcheevos\operand.c">
|
|
||||||
<Filter>rcheevos</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\rcheevos\richpresence.c">
|
|
||||||
<Filter>rcheevos</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\rcheevos\runtime.c">
|
|
||||||
<Filter>rcheevos</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\rcheevos\runtime_progress.c">
|
|
||||||
<Filter>rcheevos</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\rcheevos\trigger.c">
|
|
||||||
<Filter>rcheevos</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\rcheevos\value.c">
|
|
||||||
<Filter>rcheevos</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\rcheevos\alloc.c">
|
|
||||||
<Filter>rcheevos</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\rcheevos\compat.c">
|
|
||||||
<Filter>rcheevos</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\rcheevos\condition.c">
|
|
||||||
<Filter>rcheevos</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\rcheevos\condset.c">
|
|
||||||
<Filter>rcheevos</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="src\rhash\md5.c">
|
<ClCompile Include="src\rhash\md5.c">
|
||||||
<Filter>rhash</Filter>
|
<Filter>rhash</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -87,9 +45,51 @@
|
||||||
<ClCompile Include="src\rapi\rc_api_common.c">
|
<ClCompile Include="src\rapi\rc_api_common.c">
|
||||||
<Filter>rapi</Filter>
|
<Filter>rapi</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="src\rcheevos\rc_client.c">
|
<ClCompile Include="src\rcheevos\operand.c">
|
||||||
<Filter>rcheevos</Filter>
|
<Filter>rcheevos</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\rcheevos\rc_validate.c">
|
||||||
|
<Filter>rcheevos</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\rcheevos\richpresence.c">
|
||||||
|
<Filter>rcheevos</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\rcheevos\runtime.c">
|
||||||
|
<Filter>rcheevos</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\rcheevos\runtime_progress.c">
|
||||||
|
<Filter>rcheevos</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\rcheevos\trigger.c">
|
||||||
|
<Filter>rcheevos</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\rcheevos\value.c">
|
||||||
|
<Filter>rcheevos</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\rcheevos\alloc.c">
|
||||||
|
<Filter>rcheevos</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\rcheevos\condition.c">
|
||||||
|
<Filter>rcheevos</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\rcheevos\condset.c">
|
||||||
|
<Filter>rcheevos</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\rcheevos\consoleinfo.c">
|
||||||
|
<Filter>rcheevos</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\rcheevos\format.c">
|
||||||
|
<Filter>rcheevos</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\rcheevos\lboard.c">
|
||||||
|
<Filter>rcheevos</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\rcheevos\memref.c">
|
||||||
|
<Filter>rcheevos</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\rc_compat.c" />
|
||||||
|
<ClCompile Include="src\rc_util.c" />
|
||||||
|
<ClCompile Include="src\rc_client.c" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="include\rc_consoles.h">
|
<ClInclude Include="include\rc_consoles.h">
|
||||||
|
@ -113,12 +113,6 @@
|
||||||
<ClInclude Include="include\rcheevos.h">
|
<ClInclude Include="include\rcheevos.h">
|
||||||
<Filter>include</Filter>
|
<Filter>include</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="src\rcheevos\rc_compat.h">
|
|
||||||
<Filter>rcheevos</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\rcheevos\rc_internal.h">
|
|
||||||
<Filter>rcheevos</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="src\rhash\md5.h">
|
<ClInclude Include="src\rhash\md5.h">
|
||||||
<Filter>rhash</Filter>
|
<Filter>rhash</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -140,11 +134,18 @@
|
||||||
<ClInclude Include="src\rapi\rc_api_common.h">
|
<ClInclude Include="src\rapi\rc_api_common.h">
|
||||||
<Filter>rapi</Filter>
|
<Filter>rapi</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="src\rcheevos\rc_client_internal.h">
|
|
||||||
<Filter>rcheevos</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="include\rc_client.h">
|
<ClInclude Include="include\rc_client.h">
|
||||||
<Filter>include</Filter>
|
<Filter>include</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\rcheevos\rc_internal.h">
|
||||||
|
<Filter>rcheevos</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\rcheevos\rc_validate.h">
|
||||||
|
<Filter>rcheevos</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\rc_compat.h" />
|
||||||
|
<ClInclude Include="src\rc_util.h" />
|
||||||
|
<ClInclude Include="src\rc_version.h" />
|
||||||
|
<ClInclude Include="src\rc_client_internal.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
|
@ -2,7 +2,7 @@
|
||||||
#include "rc_api_request.h"
|
#include "rc_api_request.h"
|
||||||
#include "rc_api_runtime.h"
|
#include "rc_api_runtime.h"
|
||||||
|
|
||||||
#include "../rcheevos/rc_compat.h"
|
#include "../rc_compat.h"
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -16,11 +16,9 @@
|
||||||
static char* g_host = NULL;
|
static char* g_host = NULL;
|
||||||
static char* g_imagehost = NULL;
|
static char* g_imagehost = NULL;
|
||||||
|
|
||||||
#undef DEBUG_BUFFERS
|
|
||||||
|
|
||||||
/* --- rc_json --- */
|
/* --- rc_json --- */
|
||||||
|
|
||||||
static int rc_json_parse_object(rc_json_iterator_t* iterator, rc_json_field_t* fields, size_t field_count, unsigned* fields_seen);
|
static int rc_json_parse_object(rc_json_iterator_t* iterator, rc_json_field_t* fields, size_t field_count, uint32_t* fields_seen);
|
||||||
static int rc_json_parse_array(rc_json_iterator_t* iterator, rc_json_field_t* field);
|
static int rc_json_parse_array(rc_json_iterator_t* iterator, rc_json_field_t* field);
|
||||||
|
|
||||||
static int rc_json_match_char(rc_json_iterator_t* iterator, char c)
|
static int rc_json_match_char(rc_json_iterator_t* iterator, char c)
|
||||||
|
@ -184,9 +182,9 @@ static int rc_json_get_next_field(rc_json_iterator_t* iterator, rc_json_field_t*
|
||||||
return RC_OK;
|
return RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rc_json_parse_object(rc_json_iterator_t* iterator, rc_json_field_t* fields, size_t field_count, unsigned* fields_seen) {
|
static int rc_json_parse_object(rc_json_iterator_t* iterator, rc_json_field_t* fields, size_t field_count, uint32_t* fields_seen) {
|
||||||
size_t i;
|
size_t i;
|
||||||
unsigned num_fields = 0;
|
uint32_t num_fields = 0;
|
||||||
rc_json_field_t field;
|
rc_json_field_t field;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
|
@ -261,12 +259,7 @@ static int rc_json_extract_html_error(rc_api_response_t* response, const rc_api_
|
||||||
if (isdigit((int)*title_start)) {
|
if (isdigit((int)*title_start)) {
|
||||||
const char* title_end = strstr(title_start + 7, "</title>");
|
const char* title_end = strstr(title_start + 7, "</title>");
|
||||||
if (title_end) {
|
if (title_end) {
|
||||||
char* dst = rc_buf_reserve(&response->buffer, (title_end - title_start) + 1);
|
response->error_message = rc_buffer_strncpy(&response->buffer, title_start, title_end - title_start);
|
||||||
response->error_message = dst;
|
|
||||||
memcpy(dst, title_start, title_end - title_start);
|
|
||||||
dst += (title_end - title_start);
|
|
||||||
*dst++ = '\0';
|
|
||||||
rc_buf_consume(&response->buffer, response->error_message, dst);
|
|
||||||
response->succeeded = 0;
|
response->succeeded = 0;
|
||||||
return RC_INVALID_JSON;
|
return RC_INVALID_JSON;
|
||||||
}
|
}
|
||||||
|
@ -279,19 +272,38 @@ static int rc_json_extract_html_error(rc_api_response_t* response, const rc_api_
|
||||||
if (end > json && end[-1] == '\r')
|
if (end > json && end[-1] == '\r')
|
||||||
--end;
|
--end;
|
||||||
|
|
||||||
if (end > json) {
|
if (end > json)
|
||||||
char* dst = rc_buf_reserve(&response->buffer, (end - json) + 1);
|
response->error_message = rc_buffer_strncpy(&response->buffer, json, end - json);
|
||||||
response->error_message = dst;
|
|
||||||
memcpy(dst, json, end - json);
|
|
||||||
dst += (end - json);
|
|
||||||
*dst++ = '\0';
|
|
||||||
rc_buf_consume(&response->buffer, response->error_message, dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
response->succeeded = 0;
|
response->succeeded = 0;
|
||||||
return RC_INVALID_JSON;
|
return RC_INVALID_JSON;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rc_json_convert_error_code(const char* server_error_code)
|
||||||
|
{
|
||||||
|
switch (server_error_code[0]) {
|
||||||
|
case 'a':
|
||||||
|
if (strcmp(server_error_code, "access_denied") == 0)
|
||||||
|
return RC_ACCESS_DENIED;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'e':
|
||||||
|
if (strcmp(server_error_code, "expired_token") == 0)
|
||||||
|
return RC_EXPIRED_TOKEN;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'i':
|
||||||
|
if (strcmp(server_error_code, "invalid_credentials") == 0)
|
||||||
|
return RC_INVALID_CREDENTIALS;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RC_API_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
int rc_json_parse_server_response(rc_api_response_t* response, const rc_api_server_response_t* server_response, rc_json_field_t* fields, size_t field_count) {
|
int rc_json_parse_server_response(rc_api_response_t* response, const rc_api_server_response_t* server_response, rc_json_field_t* fields, size_t field_count) {
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
|
@ -306,7 +318,38 @@ int rc_json_parse_server_response(rc_api_response_t* response, const rc_api_serv
|
||||||
|
|
||||||
response->error_message = NULL;
|
response->error_message = NULL;
|
||||||
|
|
||||||
if (!server_response || !server_response->body || !*server_response->body) {
|
if (!server_response) {
|
||||||
|
response->succeeded = 0;
|
||||||
|
return RC_NO_RESPONSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (server_response->http_status_code == RC_API_SERVER_RESPONSE_CLIENT_ERROR ||
|
||||||
|
server_response->http_status_code == RC_API_SERVER_RESPONSE_RETRYABLE_CLIENT_ERROR) {
|
||||||
|
/* client provided error message is passed as the response body */
|
||||||
|
response->error_message = server_response->body;
|
||||||
|
response->succeeded = 0;
|
||||||
|
return RC_NO_RESPONSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!server_response->body || !*server_response->body) {
|
||||||
|
/* expect valid HTTP status codes to have bodies that we can extract the message from,
|
||||||
|
* but provide some default messages in case they don't. */
|
||||||
|
switch (server_response->http_status_code) {
|
||||||
|
case 504: /* 504 Gateway Timeout */
|
||||||
|
case 522: /* 522 Connection Timed Out */
|
||||||
|
case 524: /* 524 A Timeout Occurred */
|
||||||
|
response->error_message = "Request has timed out.";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 521: /* 521 Web Server is Down */
|
||||||
|
case 523: /* 523 Origin is Unreachable */
|
||||||
|
response->error_message = "Could not connect to server.";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
response->succeeded = 0;
|
response->succeeded = 0;
|
||||||
return RC_NO_RESPONSE;
|
return RC_NO_RESPONSE;
|
||||||
}
|
}
|
||||||
|
@ -323,6 +366,13 @@ int rc_json_parse_server_response(rc_api_response_t* response, const rc_api_serv
|
||||||
|
|
||||||
rc_json_get_optional_string(&response->error_message, response, &fields[1], "Error", NULL);
|
rc_json_get_optional_string(&response->error_message, response, &fields[1], "Error", NULL);
|
||||||
rc_json_get_optional_bool(&response->succeeded, &fields[0], "Success", 1);
|
rc_json_get_optional_bool(&response->succeeded, &fields[0], "Success", 1);
|
||||||
|
|
||||||
|
/* Code will be the third field in the fields array, but may not always be present */
|
||||||
|
if (field_count > 2 && strcmp(fields[2].name, "Code") == 0) {
|
||||||
|
rc_json_get_optional_string(&response->error_code, response, &fields[2], "Code", NULL);
|
||||||
|
if (response->error_code != NULL)
|
||||||
|
result = rc_json_convert_error_code(response->error_code);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -333,14 +383,14 @@ static int rc_json_missing_field(rc_api_response_t* response, const rc_json_fiel
|
||||||
const size_t not_found_len = strlen(not_found);
|
const size_t not_found_len = strlen(not_found);
|
||||||
const size_t field_len = strlen(field->name);
|
const size_t field_len = strlen(field->name);
|
||||||
|
|
||||||
char* write = rc_buf_reserve(&response->buffer, field_len + not_found_len + 1);
|
uint8_t* write = rc_buffer_reserve(&response->buffer, field_len + not_found_len + 1);
|
||||||
if (write) {
|
if (write) {
|
||||||
response->error_message = write;
|
response->error_message = (char*)write;
|
||||||
memcpy(write, field->name, field_len);
|
memcpy(write, field->name, field_len);
|
||||||
write += field_len;
|
write += field_len;
|
||||||
memcpy(write, not_found, not_found_len + 1);
|
memcpy(write, not_found, not_found_len + 1);
|
||||||
write += not_found_len + 1;
|
write += not_found_len + 1;
|
||||||
rc_buf_consume(&response->buffer, response->error_message, write);
|
rc_buffer_consume(&response->buffer, (uint8_t*)response->error_message, write);
|
||||||
}
|
}
|
||||||
|
|
||||||
response->succeeded = 0;
|
response->succeeded = 0;
|
||||||
|
@ -383,18 +433,18 @@ static int rc_json_get_array_entry_value(rc_json_field_t* field, rc_json_iterato
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_json_get_required_unum_array(unsigned** entries, unsigned* num_entries, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name) {
|
int rc_json_get_required_unum_array(uint32_t** entries, uint32_t* num_entries, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name) {
|
||||||
rc_json_iterator_t iterator;
|
rc_json_iterator_t iterator;
|
||||||
rc_json_field_t array;
|
rc_json_field_t array;
|
||||||
rc_json_field_t value;
|
rc_json_field_t value;
|
||||||
unsigned* entry;
|
uint32_t* entry;
|
||||||
|
|
||||||
memset(&array, 0, sizeof(array));
|
memset(&array, 0, sizeof(array));
|
||||||
if (!rc_json_get_required_array(num_entries, &array, response, field, field_name))
|
if (!rc_json_get_required_array(num_entries, &array, response, field, field_name))
|
||||||
return RC_MISSING_VALUE;
|
return RC_MISSING_VALUE;
|
||||||
|
|
||||||
if (*num_entries) {
|
if (*num_entries) {
|
||||||
*entries = (unsigned*)rc_buf_alloc(&response->buffer, *num_entries * sizeof(unsigned));
|
*entries = (uint32_t*)rc_buffer_alloc(&response->buffer, *num_entries * sizeof(uint32_t));
|
||||||
if (!*entries)
|
if (!*entries)
|
||||||
return RC_OUT_OF_MEMORY;
|
return RC_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
@ -419,7 +469,7 @@ int rc_json_get_required_unum_array(unsigned** entries, unsigned* num_entries, r
|
||||||
return RC_OK;
|
return RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_json_get_required_array(unsigned* num_entries, rc_json_field_t* array_field, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name) {
|
int rc_json_get_required_array(uint32_t* num_entries, rc_json_field_t* array_field, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name) {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (strcmp(field->name, field_name) != 0)
|
if (strcmp(field->name, field_name) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -431,7 +481,7 @@ int rc_json_get_required_array(unsigned* num_entries, rc_json_field_t* array_fie
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_json_get_optional_array(unsigned* num_entries, rc_json_field_t* array_field, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name) {
|
int rc_json_get_optional_array(uint32_t* num_entries, rc_json_field_t* array_field, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name) {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (strcmp(field->name, field_name) != 0)
|
if (strcmp(field->name, field_name) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -468,16 +518,16 @@ int rc_json_get_array_entry_object(rc_json_field_t* fields, size_t field_count,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned rc_json_decode_hex4(const char* input) {
|
static uint32_t rc_json_decode_hex4(const char* input) {
|
||||||
char hex[5];
|
char hex[5];
|
||||||
|
|
||||||
memcpy(hex, input, 4);
|
memcpy(hex, input, 4);
|
||||||
hex[4] = '\0';
|
hex[4] = '\0';
|
||||||
|
|
||||||
return (unsigned)strtoul(hex, NULL, 16);
|
return (uint32_t)strtoul(hex, NULL, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rc_json_ucs32_to_utf8(unsigned char* dst, unsigned ucs32_char) {
|
static int rc_json_ucs32_to_utf8(uint8_t* dst, uint32_t ucs32_char) {
|
||||||
if (ucs32_char < 0x80) {
|
if (ucs32_char < 0x80) {
|
||||||
dst[0] = (ucs32_char & 0x7F);
|
dst[0] = (ucs32_char & 0x7F);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -522,7 +572,7 @@ static int rc_json_ucs32_to_utf8(unsigned char* dst, unsigned ucs32_char) {
|
||||||
return 6;
|
return 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_json_get_string(const char** out, rc_api_buffer_t* buffer, const rc_json_field_t* field, const char* field_name) {
|
int rc_json_get_string(const char** out, rc_buffer_t* buffer, const rc_json_field_t* field, const char* field_name) {
|
||||||
const char* src = field->value_start;
|
const char* src = field->value_start;
|
||||||
size_t len = field->value_end - field->value_start;
|
size_t len = field->value_end - field->value_start;
|
||||||
char* dst;
|
char* dst;
|
||||||
|
@ -553,7 +603,7 @@ int rc_json_get_string(const char** out, rc_api_buffer_t* buffer, const rc_json_
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
*out = dst = rc_buf_reserve(buffer, len - 1); /* -2 for quotes, +1 for null terminator */
|
*out = dst = (char*)rc_buffer_reserve(buffer, len - 1); /* -2 for quotes, +1 for null terminator */
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (*src == '\\') {
|
if (*src == '\\') {
|
||||||
|
@ -574,13 +624,13 @@ int rc_json_get_string(const char** out, rc_api_buffer_t* buffer, const rc_json_
|
||||||
|
|
||||||
if (*src == 'u') {
|
if (*src == 'u') {
|
||||||
/* unicode character */
|
/* unicode character */
|
||||||
unsigned ucs32_char = rc_json_decode_hex4(src + 1);
|
uint32_t ucs32_char = rc_json_decode_hex4(src + 1);
|
||||||
src += 5;
|
src += 5;
|
||||||
|
|
||||||
if (ucs32_char >= 0xD800 && ucs32_char < 0xE000) {
|
if (ucs32_char >= 0xD800 && ucs32_char < 0xE000) {
|
||||||
/* surrogate lead - look for surrogate tail */
|
/* surrogate lead - look for surrogate tail */
|
||||||
if (ucs32_char < 0xDC00 && src[0] == '\\' && src[1] == 'u') {
|
if (ucs32_char < 0xDC00 && src[0] == '\\' && src[1] == 'u') {
|
||||||
const unsigned surrogate = rc_json_decode_hex4(src + 2);
|
const uint32_t surrogate = rc_json_decode_hex4(src + 2);
|
||||||
src += 6;
|
src += 6;
|
||||||
|
|
||||||
if (surrogate >= 0xDC00 && surrogate < 0xE000) {
|
if (surrogate >= 0xDC00 && surrogate < 0xE000) {
|
||||||
|
@ -613,13 +663,13 @@ int rc_json_get_string(const char** out, rc_api_buffer_t* buffer, const rc_json_
|
||||||
} while (*src != '\"');
|
} while (*src != '\"');
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
*out = dst = rc_buf_reserve(buffer, len + 1); /* +1 for null terminator */
|
*out = dst = (char*)rc_buffer_reserve(buffer, len + 1); /* +1 for null terminator */
|
||||||
memcpy(dst, src, len);
|
memcpy(dst, src, len);
|
||||||
dst += len;
|
dst += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
*dst++ = '\0';
|
*dst++ = '\0';
|
||||||
rc_buf_consume(buffer, *out, dst);
|
rc_buffer_consume(buffer, (uint8_t*)(*out), (uint8_t*)dst);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -635,9 +685,9 @@ int rc_json_get_required_string(const char** out, rc_api_response_t* response, c
|
||||||
return rc_json_missing_field(response, field);
|
return rc_json_missing_field(response, field);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_json_get_num(int* out, const rc_json_field_t* field, const char* field_name) {
|
int rc_json_get_num(int32_t* out, const rc_json_field_t* field, const char* field_name) {
|
||||||
const char* src = field->value_start;
|
const char* src = field->value_start;
|
||||||
int value = 0;
|
int32_t value = 0;
|
||||||
int negative = 0;
|
int negative = 0;
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
@ -677,21 +727,21 @@ int rc_json_get_num(int* out, const rc_json_field_t* field, const char* field_na
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_json_get_optional_num(int* out, const rc_json_field_t* field, const char* field_name, int default_value) {
|
void rc_json_get_optional_num(int32_t* out, const rc_json_field_t* field, const char* field_name, int default_value) {
|
||||||
if (!rc_json_get_num(out, field, field_name))
|
if (!rc_json_get_num(out, field, field_name))
|
||||||
*out = default_value;
|
*out = default_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_json_get_required_num(int* out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name) {
|
int rc_json_get_required_num(int32_t* out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name) {
|
||||||
if (rc_json_get_num(out, field, field_name))
|
if (rc_json_get_num(out, field, field_name))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
return rc_json_missing_field(response, field);
|
return rc_json_missing_field(response, field);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_json_get_unum(unsigned* out, const rc_json_field_t* field, const char* field_name) {
|
int rc_json_get_unum(uint32_t* out, const rc_json_field_t* field, const char* field_name) {
|
||||||
const char* src = field->value_start;
|
const char* src = field->value_start;
|
||||||
int value = 0;
|
uint32_t value = 0;
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (strcmp(field->name, field_name) != 0)
|
if (strcmp(field->name, field_name) != 0)
|
||||||
|
@ -721,12 +771,12 @@ int rc_json_get_unum(unsigned* out, const rc_json_field_t* field, const char* fi
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_json_get_optional_unum(unsigned* out, const rc_json_field_t* field, const char* field_name, unsigned default_value) {
|
void rc_json_get_optional_unum(uint32_t* out, const rc_json_field_t* field, const char* field_name, uint32_t default_value) {
|
||||||
if (!rc_json_get_unum(out, field, field_name))
|
if (!rc_json_get_unum(out, field, field_name))
|
||||||
*out = default_value;
|
*out = default_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_json_get_required_unum(unsigned* out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name) {
|
int rc_json_get_required_unum(uint32_t* out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name) {
|
||||||
if (rc_json_get_unum(out, field, field_name))
|
if (rc_json_get_unum(out, field, field_name))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
@ -819,133 +869,27 @@ int rc_json_get_required_bool(int* out, rc_api_response_t* response, const rc_js
|
||||||
return rc_json_missing_field(response, field);
|
return rc_json_missing_field(response, field);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- rc_buf --- */
|
/* --- rc_api_request --- */
|
||||||
|
|
||||||
void rc_buf_init(rc_api_buffer_t* buffer) {
|
void rc_api_destroy_request(rc_api_request_t* request)
|
||||||
buffer->chunk.write = buffer->chunk.start = &buffer->data[0];
|
{
|
||||||
buffer->chunk.end = &buffer->data[sizeof(buffer->data)];
|
rc_buffer_destroy(&request->buffer);
|
||||||
buffer->chunk.next = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rc_buf_destroy(rc_api_buffer_t* buffer) {
|
|
||||||
rc_api_buffer_chunk_t *chunk;
|
|
||||||
#ifdef DEBUG_BUFFERS
|
|
||||||
int count = 0;
|
|
||||||
int wasted = 0;
|
|
||||||
int total = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* first chunk is not allocated. skip it. */
|
|
||||||
chunk = buffer->chunk.next;
|
|
||||||
|
|
||||||
/* deallocate any additional buffers */
|
|
||||||
while (chunk) {
|
|
||||||
rc_api_buffer_chunk_t* next = chunk->next;
|
|
||||||
#ifdef DEBUG_BUFFERS
|
|
||||||
total += (int)(chunk->end - chunk->data);
|
|
||||||
wasted += (int)(chunk->end - chunk->write);
|
|
||||||
++count;
|
|
||||||
#endif
|
|
||||||
free(chunk);
|
|
||||||
chunk = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG_BUFFERS
|
|
||||||
printf("-- %d allocated buffers (%d/%d used, %d wasted, %0.2f%% efficiency)\n", count,
|
|
||||||
total - wasted, total, wasted, (float)(100.0 - (wasted * 100.0) / total));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
char* rc_buf_reserve(rc_api_buffer_t* buffer, size_t amount) {
|
|
||||||
rc_api_buffer_chunk_t* chunk = &buffer->chunk;
|
|
||||||
size_t remaining;
|
|
||||||
while (chunk) {
|
|
||||||
remaining = chunk->end - chunk->write;
|
|
||||||
if (remaining >= amount)
|
|
||||||
return chunk->write;
|
|
||||||
|
|
||||||
if (!chunk->next) {
|
|
||||||
/* allocate a chunk of memory that is a multiple of 256-bytes. the first 32 bytes will be associated
|
|
||||||
* to the chunk header, and the remaining will be used for data.
|
|
||||||
*/
|
|
||||||
const size_t chunk_header_size = sizeof(rc_api_buffer_chunk_t);
|
|
||||||
const size_t alloc_size = (chunk_header_size + amount + 0xFF) & ~0xFF;
|
|
||||||
chunk->next = (rc_api_buffer_chunk_t*)malloc(alloc_size);
|
|
||||||
if (!chunk->next)
|
|
||||||
break;
|
|
||||||
|
|
||||||
chunk->next->start = (char*)chunk->next + chunk_header_size;
|
|
||||||
chunk->next->write = chunk->next->start;
|
|
||||||
chunk->next->end = (char*)chunk->next + alloc_size;
|
|
||||||
chunk->next->next = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
chunk = chunk->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rc_buf_consume(rc_api_buffer_t* buffer, const char* start, char* end) {
|
|
||||||
rc_api_buffer_chunk_t* chunk = &buffer->chunk;
|
|
||||||
do {
|
|
||||||
if (chunk->write == start) {
|
|
||||||
size_t offset = (end - chunk->start);
|
|
||||||
offset = (offset + 7) & ~7;
|
|
||||||
chunk->write = &chunk->start[offset];
|
|
||||||
|
|
||||||
if (chunk->write > chunk->end)
|
|
||||||
chunk->write = chunk->end;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
chunk = chunk->next;
|
|
||||||
} while (chunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* rc_buf_alloc(rc_api_buffer_t* buffer, size_t amount) {
|
|
||||||
char* ptr = rc_buf_reserve(buffer, amount);
|
|
||||||
rc_buf_consume(buffer, ptr, ptr + amount);
|
|
||||||
return (void*)ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* rc_buf_strncpy(rc_api_buffer_t* buffer, const char* src, size_t len) {
|
|
||||||
char* dst = rc_buf_reserve(buffer, len + 1);
|
|
||||||
memcpy(dst, src, len);
|
|
||||||
dst[len] = '\0';
|
|
||||||
rc_buf_consume(buffer, dst, dst + len + 2);
|
|
||||||
return dst;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* rc_buf_strcpy(rc_api_buffer_t* buffer, const char* src) {
|
|
||||||
return rc_buf_strncpy(buffer, src, strlen(src));
|
|
||||||
}
|
|
||||||
|
|
||||||
void rc_api_destroy_request(rc_api_request_t* request) {
|
|
||||||
rc_buf_destroy(&request->buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rc_api_format_md5(char checksum[33], const unsigned char digest[16]) {
|
|
||||||
snprintf(checksum, 33, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
|
||||||
digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7],
|
|
||||||
digest[8], digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], digest[15]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- rc_url_builder --- */
|
/* --- rc_url_builder --- */
|
||||||
|
|
||||||
void rc_url_builder_init(rc_api_url_builder_t* builder, rc_api_buffer_t* buffer, size_t estimated_size) {
|
void rc_url_builder_init(rc_api_url_builder_t* builder, rc_buffer_t* buffer, size_t estimated_size) {
|
||||||
rc_api_buffer_chunk_t* used_buffer;
|
rc_buffer_chunk_t* used_buffer;
|
||||||
|
|
||||||
memset(builder, 0, sizeof(*builder));
|
memset(builder, 0, sizeof(*builder));
|
||||||
builder->buffer = buffer;
|
builder->buffer = buffer;
|
||||||
builder->write = builder->start = rc_buf_reserve(buffer, estimated_size);
|
builder->write = builder->start = (char*)rc_buffer_reserve(buffer, estimated_size);
|
||||||
|
|
||||||
used_buffer = &buffer->chunk;
|
used_buffer = &buffer->chunk;
|
||||||
while (used_buffer && used_buffer->write != builder->write)
|
while (used_buffer && used_buffer->write != (uint8_t*)builder->write)
|
||||||
used_buffer = used_buffer->next;
|
used_buffer = used_buffer->next;
|
||||||
|
|
||||||
builder->end = (used_buffer) ? used_buffer->end : builder->start + estimated_size;
|
builder->end = (used_buffer) ? (char*)used_buffer->end : builder->start + estimated_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* rc_url_builder_finalize(rc_api_url_builder_t* builder) {
|
const char* rc_url_builder_finalize(rc_api_url_builder_t* builder) {
|
||||||
|
@ -954,7 +898,7 @@ const char* rc_url_builder_finalize(rc_api_url_builder_t* builder) {
|
||||||
if (builder->result != RC_OK)
|
if (builder->result != RC_OK)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
rc_buf_consume(builder->buffer, builder->start, builder->write);
|
rc_buffer_consume(builder->buffer, (uint8_t*)builder->start, (uint8_t*)builder->write);
|
||||||
return builder->start;
|
return builder->start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -964,7 +908,7 @@ static int rc_url_builder_reserve(rc_api_url_builder_t* builder, size_t amount)
|
||||||
if (remaining < amount) {
|
if (remaining < amount) {
|
||||||
const size_t used = builder->write - builder->start;
|
const size_t used = builder->write - builder->start;
|
||||||
const size_t current_size = builder->end - builder->start;
|
const size_t current_size = builder->end - builder->start;
|
||||||
const size_t buffer_prefix_size = sizeof(rc_api_buffer_chunk_t);
|
const size_t buffer_prefix_size = sizeof(rc_buffer_chunk_t);
|
||||||
char* new_start;
|
char* new_start;
|
||||||
size_t new_size = (current_size < 256) ? 256 : current_size * 2;
|
size_t new_size = (current_size < 256) ? 256 : current_size * 2;
|
||||||
do {
|
do {
|
||||||
|
@ -975,11 +919,11 @@ static int rc_url_builder_reserve(rc_api_url_builder_t* builder, size_t amount)
|
||||||
new_size *= 2;
|
new_size *= 2;
|
||||||
} while (1);
|
} while (1);
|
||||||
|
|
||||||
/* rc_buf_reserve will align to 256 bytes after including the buffer prefix. attempt to account for that */
|
/* rc_buffer_reserve will align to 256 bytes after including the buffer prefix. attempt to account for that */
|
||||||
if ((remaining - amount) > buffer_prefix_size)
|
if ((remaining - amount) > buffer_prefix_size)
|
||||||
new_size -= buffer_prefix_size;
|
new_size -= buffer_prefix_size;
|
||||||
|
|
||||||
new_start = rc_buf_reserve(builder->buffer, new_size);
|
new_start = (char*)rc_buffer_reserve(builder->buffer, new_size);
|
||||||
if (!new_start) {
|
if (!new_start) {
|
||||||
builder->result = RC_OUT_OF_MEMORY;
|
builder->result = RC_OUT_OF_MEMORY;
|
||||||
return RC_OUT_OF_MEMORY;
|
return RC_OUT_OF_MEMORY;
|
||||||
|
@ -1070,7 +1014,7 @@ static int rc_url_builder_append_param_equals(rc_api_url_builder_t* builder, con
|
||||||
return builder->result;
|
return builder->result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_url_builder_append_unum_param(rc_api_url_builder_t* builder, const char* param, unsigned value) {
|
void rc_url_builder_append_unum_param(rc_api_url_builder_t* builder, const char* param, uint32_t value) {
|
||||||
if (rc_url_builder_append_param_equals(builder, param) == RC_OK) {
|
if (rc_url_builder_append_param_equals(builder, param) == RC_OK) {
|
||||||
char num[16];
|
char num[16];
|
||||||
int chars = snprintf(num, sizeof(num), "%u", value);
|
int chars = snprintf(num, sizeof(num), "%u", value);
|
||||||
|
@ -1078,7 +1022,7 @@ void rc_url_builder_append_unum_param(rc_api_url_builder_t* builder, const char*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_url_builder_append_num_param(rc_api_url_builder_t* builder, const char* param, int value) {
|
void rc_url_builder_append_num_param(rc_api_url_builder_t* builder, const char* param, int32_t value) {
|
||||||
if (rc_url_builder_append_param_equals(builder, param) == RC_OK) {
|
if (rc_url_builder_append_param_equals(builder, param) == RC_OK) {
|
||||||
char num[16];
|
char num[16];
|
||||||
int chars = snprintf(num, sizeof(num), "%d", value);
|
int chars = snprintf(num, sizeof(num), "%d", value);
|
||||||
|
@ -1093,7 +1037,7 @@ void rc_url_builder_append_str_param(rc_api_url_builder_t* builder, const char*
|
||||||
|
|
||||||
void rc_api_url_build_dorequest_url(rc_api_request_t* request) {
|
void rc_api_url_build_dorequest_url(rc_api_request_t* request) {
|
||||||
#define DOREQUEST_ENDPOINT "/dorequest.php"
|
#define DOREQUEST_ENDPOINT "/dorequest.php"
|
||||||
rc_buf_init(&request->buffer);
|
rc_buffer_init(&request->buffer);
|
||||||
|
|
||||||
if (!g_host) {
|
if (!g_host) {
|
||||||
request->url = RETROACHIEVEMENTS_HOST DOREQUEST_ENDPOINT;
|
request->url = RETROACHIEVEMENTS_HOST DOREQUEST_ENDPOINT;
|
||||||
|
@ -1102,13 +1046,13 @@ void rc_api_url_build_dorequest_url(rc_api_request_t* request) {
|
||||||
const size_t endpoint_len = sizeof(DOREQUEST_ENDPOINT);
|
const size_t endpoint_len = sizeof(DOREQUEST_ENDPOINT);
|
||||||
const size_t host_len = strlen(g_host);
|
const size_t host_len = strlen(g_host);
|
||||||
const size_t url_len = host_len + endpoint_len;
|
const size_t url_len = host_len + endpoint_len;
|
||||||
char* url = rc_buf_reserve(&request->buffer, url_len);
|
uint8_t* url = rc_buffer_reserve(&request->buffer, url_len);
|
||||||
|
|
||||||
memcpy(url, g_host, host_len);
|
memcpy(url, g_host, host_len);
|
||||||
memcpy(url + host_len, DOREQUEST_ENDPOINT, endpoint_len);
|
memcpy(url + host_len, DOREQUEST_ENDPOINT, endpoint_len);
|
||||||
rc_buf_consume(&request->buffer, url, url + url_len);
|
rc_buffer_consume(&request->buffer, url, url + url_len);
|
||||||
|
|
||||||
request->url = url;
|
request->url = (char*)url;
|
||||||
}
|
}
|
||||||
#undef DOREQUEST_ENDPOINT
|
#undef DOREQUEST_ENDPOINT
|
||||||
}
|
}
|
||||||
|
@ -1182,7 +1126,7 @@ void rc_api_set_image_host(const char* hostname) {
|
||||||
int rc_api_init_fetch_image_request(rc_api_request_t* request, const rc_api_fetch_image_request_t* api_params) {
|
int rc_api_init_fetch_image_request(rc_api_request_t* request, const rc_api_fetch_image_request_t* api_params) {
|
||||||
rc_api_url_builder_t builder;
|
rc_api_url_builder_t builder;
|
||||||
|
|
||||||
rc_buf_init(&request->buffer);
|
rc_buffer_init(&request->buffer);
|
||||||
rc_url_builder_init(&builder, &request->buffer, 64);
|
rc_url_builder_init(&builder, &request->buffer, 64);
|
||||||
|
|
||||||
if (g_imagehost) {
|
if (g_imagehost) {
|
||||||
|
|
|
@ -16,13 +16,13 @@ typedef struct rc_api_url_builder_t {
|
||||||
char* write;
|
char* write;
|
||||||
char* start;
|
char* start;
|
||||||
char* end;
|
char* end;
|
||||||
/* pointer to a preallocated rc_api_buffer_t */
|
/* pointer to a preallocated rc_buffer_t */
|
||||||
rc_api_buffer_t* buffer;
|
rc_buffer_t* buffer;
|
||||||
int result;
|
int result;
|
||||||
}
|
}
|
||||||
rc_api_url_builder_t;
|
rc_api_url_builder_t;
|
||||||
|
|
||||||
void rc_url_builder_init(rc_api_url_builder_t* builder, rc_api_buffer_t* buffer, size_t estimated_size);
|
void rc_url_builder_init(rc_api_url_builder_t* builder, rc_buffer_t* buffer, size_t estimated_size);
|
||||||
void rc_url_builder_append(rc_api_url_builder_t* builder, const char* data, size_t len);
|
void rc_url_builder_append(rc_api_url_builder_t* builder, const char* data, size_t len);
|
||||||
const char* rc_url_builder_finalize(rc_api_url_builder_t* builder);
|
const char* rc_url_builder_finalize(rc_api_url_builder_t* builder);
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ typedef struct rc_json_field_t {
|
||||||
const char* value_end;
|
const char* value_end;
|
||||||
const char* name;
|
const char* name;
|
||||||
size_t name_len;
|
size_t name_len;
|
||||||
unsigned array_size;
|
uint32_t array_size;
|
||||||
}
|
}
|
||||||
rc_json_field_t;
|
rc_json_field_t;
|
||||||
|
|
||||||
|
@ -44,44 +44,35 @@ typedef struct rc_json_iterator_t {
|
||||||
rc_json_iterator_t;
|
rc_json_iterator_t;
|
||||||
|
|
||||||
int rc_json_parse_server_response(rc_api_response_t* response, const rc_api_server_response_t* server_response, rc_json_field_t* fields, size_t field_count);
|
int rc_json_parse_server_response(rc_api_response_t* response, const rc_api_server_response_t* server_response, rc_json_field_t* fields, size_t field_count);
|
||||||
int rc_json_get_string(const char** out, rc_api_buffer_t* buffer, const rc_json_field_t* field, const char* field_name);
|
int rc_json_get_string(const char** out, rc_buffer_t* buffer, const rc_json_field_t* field, const char* field_name);
|
||||||
int rc_json_get_num(int* out, const rc_json_field_t* field, const char* field_name);
|
int rc_json_get_num(int32_t* out, const rc_json_field_t* field, const char* field_name);
|
||||||
int rc_json_get_unum(unsigned* out, const rc_json_field_t* field, const char* field_name);
|
int rc_json_get_unum(uint32_t* out, const rc_json_field_t* field, const char* field_name);
|
||||||
int rc_json_get_bool(int* out, const rc_json_field_t* field, const char* field_name);
|
int rc_json_get_bool(int* out, const rc_json_field_t* field, const char* field_name);
|
||||||
int rc_json_get_datetime(time_t* out, const rc_json_field_t* field, const char* field_name);
|
int rc_json_get_datetime(time_t* out, const rc_json_field_t* field, const char* field_name);
|
||||||
void rc_json_get_optional_string(const char** out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name, const char* default_value);
|
void rc_json_get_optional_string(const char** out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name, const char* default_value);
|
||||||
void rc_json_get_optional_num(int* out, const rc_json_field_t* field, const char* field_name, int default_value);
|
void rc_json_get_optional_num(int32_t* out, const rc_json_field_t* field, const char* field_name, int default_value);
|
||||||
void rc_json_get_optional_unum(unsigned* out, const rc_json_field_t* field, const char* field_name, unsigned default_value);
|
void rc_json_get_optional_unum(uint32_t* out, const rc_json_field_t* field, const char* field_name, uint32_t default_value);
|
||||||
void rc_json_get_optional_bool(int* out, const rc_json_field_t* field, const char* field_name, int default_value);
|
void rc_json_get_optional_bool(int* out, const rc_json_field_t* field, const char* field_name, int default_value);
|
||||||
int rc_json_get_optional_array(unsigned* num_entries, rc_json_field_t* iterator, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
|
int rc_json_get_optional_array(uint32_t* num_entries, rc_json_field_t* iterator, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
|
||||||
int rc_json_get_required_string(const char** out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
|
int rc_json_get_required_string(const char** out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
|
||||||
int rc_json_get_required_num(int* out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
|
int rc_json_get_required_num(int32_t* out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
|
||||||
int rc_json_get_required_unum(unsigned* out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
|
int rc_json_get_required_unum(uint32_t* out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
|
||||||
int rc_json_get_required_bool(int* out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
|
int rc_json_get_required_bool(int* out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
|
||||||
int rc_json_get_required_datetime(time_t* out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
|
int rc_json_get_required_datetime(time_t* out, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
|
||||||
int rc_json_get_required_object(rc_json_field_t* fields, size_t field_count, rc_api_response_t* response, rc_json_field_t* field, const char* field_name);
|
int rc_json_get_required_object(rc_json_field_t* fields, size_t field_count, rc_api_response_t* response, rc_json_field_t* field, const char* field_name);
|
||||||
int rc_json_get_required_unum_array(unsigned** entries, unsigned* num_entries, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
|
int rc_json_get_required_unum_array(uint32_t** entries, uint32_t* num_entries, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
|
||||||
int rc_json_get_required_array(unsigned* num_entries, rc_json_field_t* array_field, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
|
int rc_json_get_required_array(uint32_t* num_entries, rc_json_field_t* array_field, rc_api_response_t* response, const rc_json_field_t* field, const char* field_name);
|
||||||
int rc_json_get_array_entry_object(rc_json_field_t* fields, size_t field_count, rc_json_iterator_t* iterator);
|
int rc_json_get_array_entry_object(rc_json_field_t* fields, size_t field_count, rc_json_iterator_t* iterator);
|
||||||
int rc_json_get_next_object_field(rc_json_iterator_t* iterator, rc_json_field_t* field);
|
int rc_json_get_next_object_field(rc_json_iterator_t* iterator, rc_json_field_t* field);
|
||||||
int rc_json_get_object_string_length(const char* json);
|
int rc_json_get_object_string_length(const char* json);
|
||||||
|
|
||||||
void rc_buf_init(rc_api_buffer_t* buffer);
|
|
||||||
void rc_buf_destroy(rc_api_buffer_t* buffer);
|
|
||||||
char* rc_buf_reserve(rc_api_buffer_t* buffer, size_t amount);
|
|
||||||
void rc_buf_consume(rc_api_buffer_t* buffer, const char* start, char* end);
|
|
||||||
void* rc_buf_alloc(rc_api_buffer_t* buffer, size_t amount);
|
|
||||||
char* rc_buf_strcpy(rc_api_buffer_t* buffer, const char* src);
|
|
||||||
char* rc_buf_strncpy(rc_api_buffer_t* buffer, const char* src, size_t len);
|
|
||||||
|
|
||||||
void rc_url_builder_append_encoded_str(rc_api_url_builder_t* builder, const char* str);
|
void rc_url_builder_append_encoded_str(rc_api_url_builder_t* builder, const char* str);
|
||||||
void rc_url_builder_append_num_param(rc_api_url_builder_t* builder, const char* param, int value);
|
void rc_url_builder_append_num_param(rc_api_url_builder_t* builder, const char* param, int32_t value);
|
||||||
void rc_url_builder_append_unum_param(rc_api_url_builder_t* builder, const char* param, unsigned value);
|
void rc_url_builder_append_unum_param(rc_api_url_builder_t* builder, const char* param, uint32_t value);
|
||||||
void rc_url_builder_append_str_param(rc_api_url_builder_t* builder, const char* param, const char* value);
|
void rc_url_builder_append_str_param(rc_api_url_builder_t* builder, const char* param, const char* value);
|
||||||
|
|
||||||
void rc_api_url_build_dorequest_url(rc_api_request_t* request);
|
void rc_api_url_build_dorequest_url(rc_api_request_t* request);
|
||||||
int rc_api_url_build_dorequest(rc_api_url_builder_t* builder, const char* api, const char* username, const char* api_token);
|
int rc_api_url_build_dorequest(rc_api_url_builder_t* builder, const char* api, const char* username, const char* api_token);
|
||||||
void rc_api_format_md5(char checksum[33], const unsigned char digest[16]);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "rc_api_editor.h"
|
#include "rc_api_editor.h"
|
||||||
#include "rc_api_common.h"
|
#include "rc_api_common.h"
|
||||||
|
|
||||||
#include "../rcheevos/rc_compat.h"
|
#include "../rc_compat.h"
|
||||||
#include "../rhash/md5.h"
|
#include "../rhash/md5.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -60,7 +60,7 @@ int rc_api_process_fetch_code_notes_server_response(rc_api_fetch_code_notes_resp
|
||||||
};
|
};
|
||||||
|
|
||||||
memset(response, 0, sizeof(*response));
|
memset(response, 0, sizeof(*response));
|
||||||
rc_buf_init(&response->response.buffer);
|
rc_buffer_init(&response->response.buffer);
|
||||||
|
|
||||||
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
||||||
if (result != RC_OK || !response->response.succeeded)
|
if (result != RC_OK || !response->response.succeeded)
|
||||||
|
@ -70,7 +70,7 @@ int rc_api_process_fetch_code_notes_server_response(rc_api_fetch_code_notes_resp
|
||||||
return RC_MISSING_VALUE;
|
return RC_MISSING_VALUE;
|
||||||
|
|
||||||
if (response->num_notes) {
|
if (response->num_notes) {
|
||||||
response->notes = (rc_api_code_note_t*)rc_buf_alloc(&response->response.buffer, response->num_notes * sizeof(rc_api_code_note_t));
|
response->notes = (rc_api_code_note_t*)rc_buffer_alloc(&response->response.buffer, response->num_notes * sizeof(rc_api_code_note_t));
|
||||||
if (!response->notes)
|
if (!response->notes)
|
||||||
return RC_OUT_OF_MEMORY;
|
return RC_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ int rc_api_process_fetch_code_notes_server_response(rc_api_fetch_code_notes_resp
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_api_destroy_fetch_code_notes_response(rc_api_fetch_code_notes_response_t* response) {
|
void rc_api_destroy_fetch_code_notes_response(rc_api_fetch_code_notes_response_t* response) {
|
||||||
rc_buf_destroy(&response->response.buffer);
|
rc_buffer_destroy(&response->response.buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- Update Code Note --- */
|
/* --- Update Code Note --- */
|
||||||
|
@ -170,7 +170,7 @@ int rc_api_process_update_code_note_server_response(rc_api_update_code_note_resp
|
||||||
};
|
};
|
||||||
|
|
||||||
memset(response, 0, sizeof(*response));
|
memset(response, 0, sizeof(*response));
|
||||||
rc_buf_init(&response->response.buffer);
|
rc_buffer_init(&response->response.buffer);
|
||||||
|
|
||||||
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
||||||
if (result != RC_OK || !response->response.succeeded)
|
if (result != RC_OK || !response->response.succeeded)
|
||||||
|
@ -180,7 +180,7 @@ int rc_api_process_update_code_note_server_response(rc_api_update_code_note_resp
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_api_destroy_update_code_note_response(rc_api_update_code_note_response_t* response) {
|
void rc_api_destroy_update_code_note_response(rc_api_update_code_note_response_t* response) {
|
||||||
rc_buf_destroy(&response->response.buffer);
|
rc_buffer_destroy(&response->response.buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- Update Achievement --- */
|
/* --- Update Achievement --- */
|
||||||
|
@ -231,7 +231,7 @@ int rc_api_init_update_achievement_request(rc_api_request_t* request, const rc_a
|
||||||
snprintf(buffer, sizeof(buffer), "%u", api_params->points * 3);
|
snprintf(buffer, sizeof(buffer), "%u", api_params->points * 3);
|
||||||
md5_append(&md5, (md5_byte_t*)buffer, (int)strlen(buffer));
|
md5_append(&md5, (md5_byte_t*)buffer, (int)strlen(buffer));
|
||||||
md5_finish(&md5, hash);
|
md5_finish(&md5, hash);
|
||||||
rc_api_format_md5(buffer, hash);
|
rc_format_md5(buffer, hash);
|
||||||
rc_url_builder_append_str_param(&builder, "h", buffer);
|
rc_url_builder_append_str_param(&builder, "h", buffer);
|
||||||
|
|
||||||
request->post_data = rc_url_builder_finalize(&builder);
|
request->post_data = rc_url_builder_finalize(&builder);
|
||||||
|
@ -260,7 +260,7 @@ int rc_api_process_update_achievement_server_response(rc_api_update_achievement_
|
||||||
};
|
};
|
||||||
|
|
||||||
memset(response, 0, sizeof(*response));
|
memset(response, 0, sizeof(*response));
|
||||||
rc_buf_init(&response->response.buffer);
|
rc_buffer_init(&response->response.buffer);
|
||||||
|
|
||||||
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
||||||
if (result != RC_OK || !response->response.succeeded)
|
if (result != RC_OK || !response->response.succeeded)
|
||||||
|
@ -273,7 +273,7 @@ int rc_api_process_update_achievement_server_response(rc_api_update_achievement_
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_api_destroy_update_achievement_response(rc_api_update_achievement_response_t* response) {
|
void rc_api_destroy_update_achievement_response(rc_api_update_achievement_response_t* response) {
|
||||||
rc_buf_destroy(&response->response.buffer);
|
rc_buffer_destroy(&response->response.buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- Update Leaderboard --- */
|
/* --- Update Leaderboard --- */
|
||||||
|
@ -333,7 +333,7 @@ int rc_api_init_update_leaderboard_request(rc_api_request_t* request, const rc_a
|
||||||
md5_append(&md5, (md5_byte_t*)"RE2", 3);
|
md5_append(&md5, (md5_byte_t*)"RE2", 3);
|
||||||
md5_append(&md5, (md5_byte_t*)api_params->format, (int)strlen(api_params->format));
|
md5_append(&md5, (md5_byte_t*)api_params->format, (int)strlen(api_params->format));
|
||||||
md5_finish(&md5, hash);
|
md5_finish(&md5, hash);
|
||||||
rc_api_format_md5(buffer, hash);
|
rc_format_md5(buffer, hash);
|
||||||
rc_url_builder_append_str_param(&builder, "h", buffer);
|
rc_url_builder_append_str_param(&builder, "h", buffer);
|
||||||
|
|
||||||
request->post_data = rc_url_builder_finalize(&builder);
|
request->post_data = rc_url_builder_finalize(&builder);
|
||||||
|
@ -362,7 +362,7 @@ int rc_api_process_update_leaderboard_server_response(rc_api_update_leaderboard_
|
||||||
};
|
};
|
||||||
|
|
||||||
memset(response, 0, sizeof(*response));
|
memset(response, 0, sizeof(*response));
|
||||||
rc_buf_init(&response->response.buffer);
|
rc_buffer_init(&response->response.buffer);
|
||||||
|
|
||||||
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
||||||
if (result != RC_OK || !response->response.succeeded)
|
if (result != RC_OK || !response->response.succeeded)
|
||||||
|
@ -375,7 +375,7 @@ int rc_api_process_update_leaderboard_server_response(rc_api_update_leaderboard_
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_api_destroy_update_leaderboard_response(rc_api_update_leaderboard_response_t* response) {
|
void rc_api_destroy_update_leaderboard_response(rc_api_update_leaderboard_response_t* response) {
|
||||||
rc_buf_destroy(&response->response.buffer);
|
rc_buffer_destroy(&response->response.buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- Fetch Badge Range --- */
|
/* --- Fetch Badge Range --- */
|
||||||
|
@ -417,7 +417,7 @@ int rc_api_process_fetch_badge_range_server_response(rc_api_fetch_badge_range_re
|
||||||
};
|
};
|
||||||
|
|
||||||
memset(response, 0, sizeof(*response));
|
memset(response, 0, sizeof(*response));
|
||||||
rc_buf_init(&response->response.buffer);
|
rc_buffer_init(&response->response.buffer);
|
||||||
|
|
||||||
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
||||||
if (result != RC_OK || !response->response.succeeded)
|
if (result != RC_OK || !response->response.succeeded)
|
||||||
|
@ -432,7 +432,7 @@ int rc_api_process_fetch_badge_range_server_response(rc_api_fetch_badge_range_re
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_api_destroy_fetch_badge_range_response(rc_api_fetch_badge_range_response_t* response) {
|
void rc_api_destroy_fetch_badge_range_response(rc_api_fetch_badge_range_response_t* response) {
|
||||||
rc_buf_destroy(&response->response.buffer);
|
rc_buffer_destroy(&response->response.buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- Add Game Hash --- */
|
/* --- Add Game Hash --- */
|
||||||
|
@ -498,7 +498,7 @@ int rc_api_process_add_game_hash_server_response(rc_api_add_game_hash_response_t
|
||||||
};
|
};
|
||||||
|
|
||||||
memset(response, 0, sizeof(*response));
|
memset(response, 0, sizeof(*response));
|
||||||
rc_buf_init(&response->response.buffer);
|
rc_buffer_init(&response->response.buffer);
|
||||||
|
|
||||||
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
||||||
if (result != RC_OK || !response->response.succeeded)
|
if (result != RC_OK || !response->response.succeeded)
|
||||||
|
@ -514,5 +514,5 @@ int rc_api_process_add_game_hash_server_response(rc_api_add_game_hash_response_t
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_api_destroy_add_game_hash_response(rc_api_add_game_hash_response_t* response) {
|
void rc_api_destroy_add_game_hash_response(rc_api_add_game_hash_response_t* response) {
|
||||||
rc_buf_destroy(&response->response.buffer);
|
rc_buffer_destroy(&response->response.buffer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ int rc_api_process_fetch_achievement_info_server_response(rc_api_fetch_achieveme
|
||||||
rc_api_achievement_awarded_entry_t* entry;
|
rc_api_achievement_awarded_entry_t* entry;
|
||||||
rc_json_field_t array_field;
|
rc_json_field_t array_field;
|
||||||
rc_json_iterator_t iterator;
|
rc_json_iterator_t iterator;
|
||||||
unsigned timet;
|
uint32_t timet;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
rc_json_field_t fields[] = {
|
rc_json_field_t fields[] = {
|
||||||
|
@ -75,7 +75,7 @@ int rc_api_process_fetch_achievement_info_server_response(rc_api_fetch_achieveme
|
||||||
};
|
};
|
||||||
|
|
||||||
memset(response, 0, sizeof(*response));
|
memset(response, 0, sizeof(*response));
|
||||||
rc_buf_init(&response->response.buffer);
|
rc_buffer_init(&response->response.buffer);
|
||||||
|
|
||||||
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
||||||
if (result != RC_OK)
|
if (result != RC_OK)
|
||||||
|
@ -97,7 +97,7 @@ int rc_api_process_fetch_achievement_info_server_response(rc_api_fetch_achieveme
|
||||||
return RC_MISSING_VALUE;
|
return RC_MISSING_VALUE;
|
||||||
|
|
||||||
if (response->num_recently_awarded) {
|
if (response->num_recently_awarded) {
|
||||||
response->recently_awarded = (rc_api_achievement_awarded_entry_t*)rc_buf_alloc(&response->response.buffer, response->num_recently_awarded * sizeof(rc_api_achievement_awarded_entry_t));
|
response->recently_awarded = (rc_api_achievement_awarded_entry_t*)rc_buffer_alloc(&response->response.buffer, response->num_recently_awarded * sizeof(rc_api_achievement_awarded_entry_t));
|
||||||
if (!response->recently_awarded)
|
if (!response->recently_awarded)
|
||||||
return RC_OUT_OF_MEMORY;
|
return RC_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
@ -122,7 +122,7 @@ int rc_api_process_fetch_achievement_info_server_response(rc_api_fetch_achieveme
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_api_destroy_fetch_achievement_info_response(rc_api_fetch_achievement_info_response_t* response) {
|
void rc_api_destroy_fetch_achievement_info_response(rc_api_fetch_achievement_info_response_t* response) {
|
||||||
rc_buf_destroy(&response->response.buffer);
|
rc_buffer_destroy(&response->response.buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- Fetch Leaderboard Info --- */
|
/* --- Fetch Leaderboard Info --- */
|
||||||
|
@ -165,7 +165,7 @@ int rc_api_process_fetch_leaderboard_info_server_response(rc_api_fetch_leaderboa
|
||||||
rc_api_lboard_info_entry_t* entry;
|
rc_api_lboard_info_entry_t* entry;
|
||||||
rc_json_field_t array_field;
|
rc_json_field_t array_field;
|
||||||
rc_json_iterator_t iterator;
|
rc_json_iterator_t iterator;
|
||||||
unsigned timet;
|
uint32_t timet;
|
||||||
int result;
|
int result;
|
||||||
size_t len;
|
size_t len;
|
||||||
char format[16];
|
char format[16];
|
||||||
|
@ -206,7 +206,7 @@ int rc_api_process_fetch_leaderboard_info_server_response(rc_api_fetch_leaderboa
|
||||||
};
|
};
|
||||||
|
|
||||||
memset(response, 0, sizeof(*response));
|
memset(response, 0, sizeof(*response));
|
||||||
rc_buf_init(&response->response.buffer);
|
rc_buffer_init(&response->response.buffer);
|
||||||
|
|
||||||
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
||||||
if (result != RC_OK)
|
if (result != RC_OK)
|
||||||
|
@ -217,7 +217,7 @@ int rc_api_process_fetch_leaderboard_info_server_response(rc_api_fetch_leaderboa
|
||||||
|
|
||||||
if (!rc_json_get_required_unum(&response->id, &response->response, &leaderboarddata_fields[0], "LBID"))
|
if (!rc_json_get_required_unum(&response->id, &response->response, &leaderboarddata_fields[0], "LBID"))
|
||||||
return RC_MISSING_VALUE;
|
return RC_MISSING_VALUE;
|
||||||
if (!rc_json_get_required_num(&response->lower_is_better, &response->response, &leaderboarddata_fields[2], "LowerIsBetter"))
|
if (!rc_json_get_required_unum(&response->lower_is_better, &response->response, &leaderboarddata_fields[2], "LowerIsBetter"))
|
||||||
return RC_MISSING_VALUE;
|
return RC_MISSING_VALUE;
|
||||||
if (!rc_json_get_required_string(&response->title, &response->response, &leaderboarddata_fields[3], "LBTitle"))
|
if (!rc_json_get_required_string(&response->title, &response->response, &leaderboarddata_fields[3], "LBTitle"))
|
||||||
return RC_MISSING_VALUE;
|
return RC_MISSING_VALUE;
|
||||||
|
@ -250,7 +250,7 @@ int rc_api_process_fetch_leaderboard_info_server_response(rc_api_fetch_leaderboa
|
||||||
return RC_MISSING_VALUE;
|
return RC_MISSING_VALUE;
|
||||||
|
|
||||||
if (response->num_entries) {
|
if (response->num_entries) {
|
||||||
response->entries = (rc_api_lboard_info_entry_t*)rc_buf_alloc(&response->response.buffer, response->num_entries * sizeof(rc_api_lboard_info_entry_t));
|
response->entries = (rc_api_lboard_info_entry_t*)rc_buffer_alloc(&response->response.buffer, response->num_entries * sizeof(rc_api_lboard_info_entry_t));
|
||||||
if (!response->entries)
|
if (!response->entries)
|
||||||
return RC_OUT_OF_MEMORY;
|
return RC_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
@ -284,7 +284,7 @@ int rc_api_process_fetch_leaderboard_info_server_response(rc_api_fetch_leaderboa
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_api_destroy_fetch_leaderboard_info_response(rc_api_fetch_leaderboard_info_response_t* response) {
|
void rc_api_destroy_fetch_leaderboard_info_response(rc_api_fetch_leaderboard_info_response_t* response) {
|
||||||
rc_buf_destroy(&response->response.buffer);
|
rc_buffer_destroy(&response->response.buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- Fetch Games List --- */
|
/* --- Fetch Games List --- */
|
||||||
|
@ -331,7 +331,7 @@ int rc_api_process_fetch_games_list_server_response(rc_api_fetch_games_list_resp
|
||||||
};
|
};
|
||||||
|
|
||||||
memset(response, 0, sizeof(*response));
|
memset(response, 0, sizeof(*response));
|
||||||
rc_buf_init(&response->response.buffer);
|
rc_buffer_init(&response->response.buffer);
|
||||||
|
|
||||||
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
||||||
if (result != RC_OK)
|
if (result != RC_OK)
|
||||||
|
@ -344,9 +344,9 @@ int rc_api_process_fetch_games_list_server_response(rc_api_fetch_games_list_resp
|
||||||
}
|
}
|
||||||
|
|
||||||
response->num_entries = fields[2].array_size;
|
response->num_entries = fields[2].array_size;
|
||||||
rc_buf_reserve(&response->response.buffer, response->num_entries * (32 + sizeof(rc_api_game_list_entry_t)));
|
rc_buffer_reserve(&response->response.buffer, response->num_entries * (32 + sizeof(rc_api_game_list_entry_t)));
|
||||||
|
|
||||||
response->entries = (rc_api_game_list_entry_t*)rc_buf_alloc(&response->response.buffer, response->num_entries * sizeof(rc_api_game_list_entry_t));
|
response->entries = (rc_api_game_list_entry_t*)rc_buffer_alloc(&response->response.buffer, response->num_entries * sizeof(rc_api_game_list_entry_t));
|
||||||
if (!response->entries)
|
if (!response->entries)
|
||||||
return RC_OUT_OF_MEMORY;
|
return RC_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
@ -369,5 +369,5 @@ int rc_api_process_fetch_games_list_server_response(rc_api_fetch_games_list_resp
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_api_destroy_fetch_games_list_response(rc_api_fetch_games_list_response_t* response) {
|
void rc_api_destroy_fetch_games_list_response(rc_api_fetch_games_list_response_t* response) {
|
||||||
rc_buf_destroy(&response->response.buffer);
|
rc_buffer_destroy(&response->response.buffer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
#include "rc_runtime.h"
|
#include "rc_runtime.h"
|
||||||
#include "rc_runtime_types.h"
|
#include "rc_runtime_types.h"
|
||||||
#include "../rcheevos/rc_compat.h"
|
#include "../rc_compat.h"
|
||||||
#include "../rhash/md5.h"
|
#include "../rhash/md5.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -48,7 +48,7 @@ int rc_api_process_resolve_hash_server_response(rc_api_resolve_hash_response_t*
|
||||||
};
|
};
|
||||||
|
|
||||||
memset(response, 0, sizeof(*response));
|
memset(response, 0, sizeof(*response));
|
||||||
rc_buf_init(&response->response.buffer);
|
rc_buffer_init(&response->response.buffer);
|
||||||
|
|
||||||
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
||||||
if (result != RC_OK)
|
if (result != RC_OK)
|
||||||
|
@ -59,7 +59,7 @@ int rc_api_process_resolve_hash_server_response(rc_api_resolve_hash_response_t*
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_api_destroy_resolve_hash_response(rc_api_resolve_hash_response_t* response) {
|
void rc_api_destroy_resolve_hash_response(rc_api_resolve_hash_response_t* response) {
|
||||||
rc_buf_destroy(&response->response.buffer);
|
rc_buffer_destroy(&response->response.buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- Fetch Game Data --- */
|
/* --- Fetch Game Data --- */
|
||||||
|
@ -102,7 +102,7 @@ int rc_api_process_fetch_game_data_server_response(rc_api_fetch_game_data_respon
|
||||||
const char* last_author_field = "";
|
const char* last_author_field = "";
|
||||||
size_t last_author_len = 0;
|
size_t last_author_len = 0;
|
||||||
size_t len;
|
size_t len;
|
||||||
unsigned timet;
|
uint32_t timet;
|
||||||
int result;
|
int result;
|
||||||
char format[16];
|
char format[16];
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ int rc_api_process_fetch_game_data_server_response(rc_api_fetch_game_data_respon
|
||||||
};
|
};
|
||||||
|
|
||||||
memset(response, 0, sizeof(*response));
|
memset(response, 0, sizeof(*response));
|
||||||
rc_buf_init(&response->response.buffer);
|
rc_buffer_init(&response->response.buffer);
|
||||||
|
|
||||||
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
||||||
if (result != RC_OK || !response->response.succeeded)
|
if (result != RC_OK || !response->response.succeeded)
|
||||||
|
@ -191,7 +191,7 @@ int rc_api_process_fetch_game_data_server_response(rc_api_fetch_game_data_respon
|
||||||
len += (patchdata_fields[6].value_end - patchdata_fields[6].value_start) - /* leaderboards */
|
len += (patchdata_fields[6].value_end - patchdata_fields[6].value_start) - /* leaderboards */
|
||||||
patchdata_fields[6].array_size * (60 - sizeof(rc_api_leaderboard_definition_t));
|
patchdata_fields[6].array_size * (60 - sizeof(rc_api_leaderboard_definition_t));
|
||||||
|
|
||||||
rc_buf_reserve(&response->response.buffer, len);
|
rc_buffer_reserve(&response->response.buffer, len);
|
||||||
/* end estimation */
|
/* end estimation */
|
||||||
|
|
||||||
rc_json_get_optional_string(&response->rich_presence_script, &response->response, &patchdata_fields[4], "RichPresencePatch", "");
|
rc_json_get_optional_string(&response->rich_presence_script, &response->response, &patchdata_fields[4], "RichPresencePatch", "");
|
||||||
|
@ -202,7 +202,7 @@ int rc_api_process_fetch_game_data_server_response(rc_api_fetch_game_data_respon
|
||||||
return RC_MISSING_VALUE;
|
return RC_MISSING_VALUE;
|
||||||
|
|
||||||
if (response->num_achievements) {
|
if (response->num_achievements) {
|
||||||
response->achievements = (rc_api_achievement_definition_t*)rc_buf_alloc(&response->response.buffer, response->num_achievements * sizeof(rc_api_achievement_definition_t));
|
response->achievements = (rc_api_achievement_definition_t*)rc_buffer_alloc(&response->response.buffer, response->num_achievements * sizeof(rc_api_achievement_definition_t));
|
||||||
if (!response->achievements)
|
if (!response->achievements)
|
||||||
return RC_OUT_OF_MEMORY;
|
return RC_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
@ -255,7 +255,7 @@ int rc_api_process_fetch_game_data_server_response(rc_api_fetch_game_data_respon
|
||||||
return RC_MISSING_VALUE;
|
return RC_MISSING_VALUE;
|
||||||
|
|
||||||
if (response->num_leaderboards) {
|
if (response->num_leaderboards) {
|
||||||
response->leaderboards = (rc_api_leaderboard_definition_t*)rc_buf_alloc(&response->response.buffer, response->num_leaderboards * sizeof(rc_api_leaderboard_definition_t));
|
response->leaderboards = (rc_api_leaderboard_definition_t*)rc_buffer_alloc(&response->response.buffer, response->num_leaderboards * sizeof(rc_api_leaderboard_definition_t));
|
||||||
if (!response->leaderboards)
|
if (!response->leaderboards)
|
||||||
return RC_OUT_OF_MEMORY;
|
return RC_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
@ -273,8 +273,10 @@ int rc_api_process_fetch_game_data_server_response(rc_api_fetch_game_data_respon
|
||||||
return RC_MISSING_VALUE;
|
return RC_MISSING_VALUE;
|
||||||
if (!rc_json_get_required_string(&leaderboard->definition, &response->response, &leaderboard_fields[3], "Mem"))
|
if (!rc_json_get_required_string(&leaderboard->definition, &response->response, &leaderboard_fields[3], "Mem"))
|
||||||
return RC_MISSING_VALUE;
|
return RC_MISSING_VALUE;
|
||||||
rc_json_get_optional_bool(&leaderboard->lower_is_better, &leaderboard_fields[5], "LowerIsBetter", 0);
|
rc_json_get_optional_bool(&result, &leaderboard_fields[5], "LowerIsBetter", 0);
|
||||||
rc_json_get_optional_bool(&leaderboard->hidden, &leaderboard_fields[6], "Hidden", 0);
|
leaderboard->lower_is_better = (uint8_t)result;
|
||||||
|
rc_json_get_optional_bool(&result, &leaderboard_fields[6], "Hidden", 0);
|
||||||
|
leaderboard->hidden = (uint8_t)result;
|
||||||
|
|
||||||
if (!leaderboard_fields[4].value_end)
|
if (!leaderboard_fields[4].value_end)
|
||||||
return RC_MISSING_VALUE;
|
return RC_MISSING_VALUE;
|
||||||
|
@ -296,7 +298,7 @@ int rc_api_process_fetch_game_data_server_response(rc_api_fetch_game_data_respon
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_api_destroy_fetch_game_data_response(rc_api_fetch_game_data_response_t* response) {
|
void rc_api_destroy_fetch_game_data_response(rc_api_fetch_game_data_response_t* response) {
|
||||||
rc_buf_destroy(&response->response.buffer);
|
rc_buffer_destroy(&response->response.buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- Ping --- */
|
/* --- Ping --- */
|
||||||
|
@ -340,13 +342,13 @@ int rc_api_process_ping_server_response(rc_api_ping_response_t* response, const
|
||||||
};
|
};
|
||||||
|
|
||||||
memset(response, 0, sizeof(*response));
|
memset(response, 0, sizeof(*response));
|
||||||
rc_buf_init(&response->response.buffer);
|
rc_buffer_init(&response->response.buffer);
|
||||||
|
|
||||||
return rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
return rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_api_destroy_ping_response(rc_api_ping_response_t* response) {
|
void rc_api_destroy_ping_response(rc_api_ping_response_t* response) {
|
||||||
rc_buf_destroy(&response->response.buffer);
|
rc_buffer_destroy(&response->response.buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- Award Achievement --- */
|
/* --- Award Achievement --- */
|
||||||
|
@ -377,7 +379,7 @@ int rc_api_init_award_achievement_request(rc_api_request_t* request, const rc_ap
|
||||||
snprintf(buffer, sizeof(buffer), "%d", api_params->hardcore ? 1 : 0);
|
snprintf(buffer, sizeof(buffer), "%d", api_params->hardcore ? 1 : 0);
|
||||||
md5_append(&md5, (md5_byte_t*)buffer, (int)strlen(buffer));
|
md5_append(&md5, (md5_byte_t*)buffer, (int)strlen(buffer));
|
||||||
md5_finish(&md5, digest);
|
md5_finish(&md5, digest);
|
||||||
rc_api_format_md5(buffer, digest);
|
rc_format_md5(buffer, digest);
|
||||||
rc_url_builder_append_str_param(&builder, "v", buffer);
|
rc_url_builder_append_str_param(&builder, "v", buffer);
|
||||||
|
|
||||||
request->post_data = rc_url_builder_finalize(&builder);
|
request->post_data = rc_url_builder_finalize(&builder);
|
||||||
|
@ -409,7 +411,7 @@ int rc_api_process_award_achievement_server_response(rc_api_award_achievement_re
|
||||||
};
|
};
|
||||||
|
|
||||||
memset(response, 0, sizeof(*response));
|
memset(response, 0, sizeof(*response));
|
||||||
rc_buf_init(&response->response.buffer);
|
rc_buffer_init(&response->response.buffer);
|
||||||
|
|
||||||
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
||||||
if (result != RC_OK)
|
if (result != RC_OK)
|
||||||
|
@ -437,7 +439,7 @@ int rc_api_process_award_achievement_server_response(rc_api_award_achievement_re
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_api_destroy_award_achievement_response(rc_api_award_achievement_response_t* response) {
|
void rc_api_destroy_award_achievement_response(rc_api_award_achievement_response_t* response) {
|
||||||
rc_buf_destroy(&response->response.buffer);
|
rc_buffer_destroy(&response->response.buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- Submit Leaderboard Entry --- */
|
/* --- Submit Leaderboard Entry --- */
|
||||||
|
@ -469,7 +471,7 @@ int rc_api_init_submit_lboard_entry_request(rc_api_request_t* request, const rc_
|
||||||
snprintf(buffer, sizeof(buffer), "%d", api_params->score);
|
snprintf(buffer, sizeof(buffer), "%d", api_params->score);
|
||||||
md5_append(&md5, (md5_byte_t*)buffer, (int)strlen(buffer));
|
md5_append(&md5, (md5_byte_t*)buffer, (int)strlen(buffer));
|
||||||
md5_finish(&md5, digest);
|
md5_finish(&md5, digest);
|
||||||
rc_api_format_md5(buffer, digest);
|
rc_format_md5(buffer, digest);
|
||||||
rc_url_builder_append_str_param(&builder, "v", buffer);
|
rc_url_builder_append_str_param(&builder, "v", buffer);
|
||||||
|
|
||||||
request->post_data = rc_url_builder_finalize(&builder);
|
request->post_data = rc_url_builder_finalize(&builder);
|
||||||
|
@ -543,7 +545,7 @@ int rc_api_process_submit_lboard_entry_server_response(rc_api_submit_lboard_entr
|
||||||
};
|
};
|
||||||
|
|
||||||
memset(response, 0, sizeof(*response));
|
memset(response, 0, sizeof(*response));
|
||||||
rc_buf_init(&response->response.buffer);
|
rc_buffer_init(&response->response.buffer);
|
||||||
|
|
||||||
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
||||||
if (result != RC_OK || !response->response.succeeded)
|
if (result != RC_OK || !response->response.succeeded)
|
||||||
|
@ -568,7 +570,7 @@ int rc_api_process_submit_lboard_entry_server_response(rc_api_submit_lboard_entr
|
||||||
return RC_MISSING_VALUE;
|
return RC_MISSING_VALUE;
|
||||||
|
|
||||||
if (response->num_top_entries) {
|
if (response->num_top_entries) {
|
||||||
response->top_entries = (rc_api_lboard_entry_t*)rc_buf_alloc(&response->response.buffer, response->num_top_entries * sizeof(rc_api_lboard_entry_t));
|
response->top_entries = (rc_api_lboard_entry_t*)rc_buffer_alloc(&response->response.buffer, response->num_top_entries * sizeof(rc_api_lboard_entry_t));
|
||||||
if (!response->top_entries)
|
if (!response->top_entries)
|
||||||
return RC_OUT_OF_MEMORY;
|
return RC_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
@ -595,5 +597,5 @@ int rc_api_process_submit_lboard_entry_server_response(rc_api_submit_lboard_entr
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_api_destroy_submit_lboard_entry_response(rc_api_submit_lboard_entry_response_t* response) {
|
void rc_api_destroy_submit_lboard_entry_response(rc_api_submit_lboard_entry_response_t* response) {
|
||||||
rc_buf_destroy(&response->response.buffer);
|
rc_buffer_destroy(&response->response.buffer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "rc_api_user.h"
|
#include "rc_api_user.h"
|
||||||
#include "rc_api_common.h"
|
#include "rc_api_common.h"
|
||||||
|
|
||||||
#include "../rcheevos/rc_version.h"
|
#include "../rc_version.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ int rc_api_init_login_request(rc_api_request_t* request, const rc_api_login_requ
|
||||||
return RC_INVALID_STATE;
|
return RC_INVALID_STATE;
|
||||||
|
|
||||||
rc_url_builder_init(&builder, &request->buffer, 48);
|
rc_url_builder_init(&builder, &request->buffer, 48);
|
||||||
rc_url_builder_append_str_param(&builder, "r", "login");
|
rc_url_builder_append_str_param(&builder, "r", "login2");
|
||||||
rc_url_builder_append_str_param(&builder, "u", api_params->username);
|
rc_url_builder_append_str_param(&builder, "u", api_params->username);
|
||||||
|
|
||||||
if (api_params->password && api_params->password[0])
|
if (api_params->password && api_params->password[0])
|
||||||
|
@ -47,6 +47,7 @@ int rc_api_process_login_server_response(rc_api_login_response_t* response, cons
|
||||||
rc_json_field_t fields[] = {
|
rc_json_field_t fields[] = {
|
||||||
RC_JSON_NEW_FIELD("Success"),
|
RC_JSON_NEW_FIELD("Success"),
|
||||||
RC_JSON_NEW_FIELD("Error"),
|
RC_JSON_NEW_FIELD("Error"),
|
||||||
|
RC_JSON_NEW_FIELD("Code"),
|
||||||
RC_JSON_NEW_FIELD("User"),
|
RC_JSON_NEW_FIELD("User"),
|
||||||
RC_JSON_NEW_FIELD("Token"),
|
RC_JSON_NEW_FIELD("Token"),
|
||||||
RC_JSON_NEW_FIELD("Score"),
|
RC_JSON_NEW_FIELD("Score"),
|
||||||
|
@ -56,28 +57,28 @@ int rc_api_process_login_server_response(rc_api_login_response_t* response, cons
|
||||||
};
|
};
|
||||||
|
|
||||||
memset(response, 0, sizeof(*response));
|
memset(response, 0, sizeof(*response));
|
||||||
rc_buf_init(&response->response.buffer);
|
rc_buffer_init(&response->response.buffer);
|
||||||
|
|
||||||
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
||||||
if (result != RC_OK || !response->response.succeeded)
|
if (result != RC_OK || !response->response.succeeded)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
if (!rc_json_get_required_string(&response->username, &response->response, &fields[2], "User"))
|
if (!rc_json_get_required_string(&response->username, &response->response, &fields[3], "User"))
|
||||||
return RC_MISSING_VALUE;
|
return RC_MISSING_VALUE;
|
||||||
if (!rc_json_get_required_string(&response->api_token, &response->response, &fields[3], "Token"))
|
if (!rc_json_get_required_string(&response->api_token, &response->response, &fields[4], "Token"))
|
||||||
return RC_MISSING_VALUE;
|
return RC_MISSING_VALUE;
|
||||||
|
|
||||||
rc_json_get_optional_unum(&response->score, &fields[4], "Score", 0);
|
rc_json_get_optional_unum(&response->score, &fields[5], "Score", 0);
|
||||||
rc_json_get_optional_unum(&response->score_softcore, &fields[5], "SoftcoreScore", 0);
|
rc_json_get_optional_unum(&response->score_softcore, &fields[6], "SoftcoreScore", 0);
|
||||||
rc_json_get_optional_unum(&response->num_unread_messages, &fields[6], "Messages", 0);
|
rc_json_get_optional_unum(&response->num_unread_messages, &fields[7], "Messages", 0);
|
||||||
|
|
||||||
rc_json_get_optional_string(&response->display_name, &response->response, &fields[7], "DisplayName", response->username);
|
rc_json_get_optional_string(&response->display_name, &response->response, &fields[8], "DisplayName", response->username);
|
||||||
|
|
||||||
return RC_OK;
|
return RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_api_destroy_login_response(rc_api_login_response_t* response) {
|
void rc_api_destroy_login_response(rc_api_login_response_t* response) {
|
||||||
rc_buf_destroy(&response->response.buffer);
|
rc_buffer_destroy(&response->response.buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- Start Session --- */
|
/* --- Start Session --- */
|
||||||
|
@ -115,7 +116,7 @@ int rc_api_process_start_session_server_response(rc_api_start_session_response_t
|
||||||
rc_api_unlock_entry_t* unlock;
|
rc_api_unlock_entry_t* unlock;
|
||||||
rc_json_field_t array_field;
|
rc_json_field_t array_field;
|
||||||
rc_json_iterator_t iterator;
|
rc_json_iterator_t iterator;
|
||||||
unsigned timet;
|
uint32_t timet;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
rc_json_field_t fields[] = {
|
rc_json_field_t fields[] = {
|
||||||
|
@ -132,14 +133,14 @@ int rc_api_process_start_session_server_response(rc_api_start_session_response_t
|
||||||
};
|
};
|
||||||
|
|
||||||
memset(response, 0, sizeof(*response));
|
memset(response, 0, sizeof(*response));
|
||||||
rc_buf_init(&response->response.buffer);
|
rc_buffer_init(&response->response.buffer);
|
||||||
|
|
||||||
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
||||||
if (result != RC_OK || !response->response.succeeded)
|
if (result != RC_OK || !response->response.succeeded)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
if (rc_json_get_optional_array(&response->num_unlocks, &array_field, &response->response, &fields[2], "Unlocks") && response->num_unlocks) {
|
if (rc_json_get_optional_array(&response->num_unlocks, &array_field, &response->response, &fields[2], "Unlocks") && response->num_unlocks) {
|
||||||
response->unlocks = (rc_api_unlock_entry_t*)rc_buf_alloc(&response->response.buffer, response->num_unlocks * sizeof(rc_api_unlock_entry_t));
|
response->unlocks = (rc_api_unlock_entry_t*)rc_buffer_alloc(&response->response.buffer, response->num_unlocks * sizeof(rc_api_unlock_entry_t));
|
||||||
if (!response->unlocks)
|
if (!response->unlocks)
|
||||||
return RC_OUT_OF_MEMORY;
|
return RC_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
@ -160,7 +161,7 @@ int rc_api_process_start_session_server_response(rc_api_start_session_response_t
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rc_json_get_optional_array(&response->num_hardcore_unlocks, &array_field, &response->response, &fields[3], "HardcoreUnlocks") && response->num_hardcore_unlocks) {
|
if (rc_json_get_optional_array(&response->num_hardcore_unlocks, &array_field, &response->response, &fields[3], "HardcoreUnlocks") && response->num_hardcore_unlocks) {
|
||||||
response->hardcore_unlocks = (rc_api_unlock_entry_t*)rc_buf_alloc(&response->response.buffer, response->num_hardcore_unlocks * sizeof(rc_api_unlock_entry_t));
|
response->hardcore_unlocks = (rc_api_unlock_entry_t*)rc_buffer_alloc(&response->response.buffer, response->num_hardcore_unlocks * sizeof(rc_api_unlock_entry_t));
|
||||||
if (!response->hardcore_unlocks)
|
if (!response->hardcore_unlocks)
|
||||||
return RC_OUT_OF_MEMORY;
|
return RC_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
@ -187,7 +188,7 @@ int rc_api_process_start_session_server_response(rc_api_start_session_response_t
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_api_destroy_start_session_response(rc_api_start_session_response_t* response) {
|
void rc_api_destroy_start_session_response(rc_api_start_session_response_t* response) {
|
||||||
rc_buf_destroy(&response->response.buffer);
|
rc_buffer_destroy(&response->response.buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- Fetch User Unlocks --- */
|
/* --- Fetch User Unlocks --- */
|
||||||
|
@ -231,7 +232,7 @@ int rc_api_process_fetch_user_unlocks_server_response(rc_api_fetch_user_unlocks_
|
||||||
};
|
};
|
||||||
|
|
||||||
memset(response, 0, sizeof(*response));
|
memset(response, 0, sizeof(*response));
|
||||||
rc_buf_init(&response->response.buffer);
|
rc_buffer_init(&response->response.buffer);
|
||||||
|
|
||||||
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
||||||
if (result != RC_OK || !response->response.succeeded)
|
if (result != RC_OK || !response->response.succeeded)
|
||||||
|
@ -242,5 +243,5 @@ int rc_api_process_fetch_user_unlocks_server_response(rc_api_fetch_user_unlocks_
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_api_destroy_fetch_user_unlocks_response(rc_api_fetch_user_unlocks_response_t* response) {
|
void rc_api_destroy_fetch_user_unlocks_response(rc_api_fetch_user_unlocks_response_t* response) {
|
||||||
rc_buf_destroy(&response->response.buffer);
|
rc_buffer_destroy(&response->response.buffer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,11 @@
|
||||||
#include "rc_api_runtime.h"
|
#include "rc_api_runtime.h"
|
||||||
#include "rc_api_user.h"
|
#include "rc_api_user.h"
|
||||||
#include "rc_consoles.h"
|
#include "rc_consoles.h"
|
||||||
#include "rc_internal.h"
|
|
||||||
#include "rc_hash.h"
|
#include "rc_hash.h"
|
||||||
|
|
||||||
#include "../rapi/rc_api_common.h"
|
#include "rapi/rc_api_common.h"
|
||||||
|
|
||||||
|
#include "rcheevos/rc_internal.h"
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
@ -26,6 +27,12 @@ struct rc_client_async_handle_t {
|
||||||
uint8_t aborted;
|
uint8_t aborted;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
RC_CLIENT_ASYNC_NOT_ABORTED = 0,
|
||||||
|
RC_CLIENT_ASYNC_ABORTED = 1,
|
||||||
|
RC_CLIENT_ASYNC_DESTROYED = 2
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct rc_client_generic_callback_data_t {
|
typedef struct rc_client_generic_callback_data_t {
|
||||||
rc_client_t* client;
|
rc_client_t* client;
|
||||||
rc_client_callback_t callback;
|
rc_client_callback_t callback;
|
||||||
|
@ -71,7 +78,6 @@ static rc_client_async_handle_t* rc_client_load_game(rc_client_load_state_t* loa
|
||||||
static void rc_client_ping(rc_client_scheduled_callback_data_t* callback_data, rc_client_t* client, rc_clock_t now);
|
static void rc_client_ping(rc_client_scheduled_callback_data_t* callback_data, rc_client_t* client, rc_clock_t now);
|
||||||
static void rc_client_raise_leaderboard_events(rc_client_t* client, rc_client_subset_info_t* subset);
|
static void rc_client_raise_leaderboard_events(rc_client_t* client, rc_client_subset_info_t* subset);
|
||||||
static void rc_client_raise_pending_events(rc_client_t* client, rc_client_game_info_t* game);
|
static void rc_client_raise_pending_events(rc_client_t* client, rc_client_game_info_t* game);
|
||||||
static void rc_client_release_leaderboard_tracker(rc_client_game_info_t* game, rc_client_leaderboard_info_t* leaderboard);
|
|
||||||
static void rc_client_reschedule_callback(rc_client_t* client, rc_client_scheduled_callback_data_t* callback, rc_clock_t when);
|
static void rc_client_reschedule_callback(rc_client_t* client, rc_client_scheduled_callback_data_t* callback, rc_clock_t when);
|
||||||
static void rc_client_award_achievement_retry(rc_client_scheduled_callback_data_t* callback_data, rc_client_t* client, rc_clock_t now);
|
static void rc_client_award_achievement_retry(rc_client_scheduled_callback_data_t* callback_data, rc_client_t* client, rc_clock_t now);
|
||||||
static void rc_client_submit_leaderboard_entry_retry(rc_client_scheduled_callback_data_t* callback_data, rc_client_t* client, rc_clock_t now);
|
static void rc_client_submit_leaderboard_entry_retry(rc_client_scheduled_callback_data_t* callback_data, rc_client_t* client, rc_clock_t now);
|
||||||
|
@ -98,7 +104,7 @@ rc_client_t* rc_client_create(rc_client_read_memory_func_t read_memory_function,
|
||||||
|
|
||||||
rc_mutex_init(&client->state.mutex);
|
rc_mutex_init(&client->state.mutex);
|
||||||
|
|
||||||
rc_buf_init(&client->state.buffer);
|
rc_buffer_init(&client->state.buffer);
|
||||||
|
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
@ -108,9 +114,24 @@ void rc_client_destroy(rc_client_t* client)
|
||||||
if (!client)
|
if (!client)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
rc_mutex_lock(&client->state.mutex);
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < sizeof(client->state.async_handles) / sizeof(client->state.async_handles[0]); ++i) {
|
||||||
|
if (client->state.async_handles[i])
|
||||||
|
client->state.async_handles[i]->aborted = RC_CLIENT_ASYNC_DESTROYED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client->state.load) {
|
||||||
|
client->state.load->async_handle.aborted = RC_CLIENT_ASYNC_DESTROYED;
|
||||||
|
client->state.load = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rc_mutex_unlock(&client->state.mutex);
|
||||||
|
|
||||||
rc_client_unload_game(client);
|
rc_client_unload_game(client);
|
||||||
|
|
||||||
rc_buf_destroy(&client->state.buffer);
|
rc_buffer_destroy(&client->state.buffer);
|
||||||
|
|
||||||
rc_mutex_destroy(&client->state.mutex);
|
rc_mutex_destroy(&client->state.mutex);
|
||||||
|
|
||||||
|
@ -272,13 +293,39 @@ void rc_client_set_get_time_millisecs_function(rc_client_t* client, rc_get_time_
|
||||||
client->callbacks.get_time_millisecs = handler ? handler : rc_client_clock_get_now_millisecs;
|
client->callbacks.get_time_millisecs = handler ? handler : rc_client_clock_get_now_millisecs;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rc_client_async_handle_aborted(rc_client_t* client, rc_client_async_handle_t* async_handle)
|
static void rc_client_begin_async(rc_client_t* client, rc_client_async_handle_t* async_handle)
|
||||||
{
|
{
|
||||||
int aborted;
|
size_t i;
|
||||||
|
|
||||||
rc_mutex_lock(&client->state.mutex);
|
rc_mutex_lock(&client->state.mutex);
|
||||||
aborted = async_handle->aborted;
|
for (i = 0; i < sizeof(client->state.async_handles) / sizeof(client->state.async_handles[0]); ++i) {
|
||||||
|
if (!client->state.async_handles[i]) {
|
||||||
|
client->state.async_handles[i] = async_handle;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
rc_mutex_unlock(&client->state.mutex);
|
rc_mutex_unlock(&client->state.mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rc_client_end_async(rc_client_t* client, rc_client_async_handle_t* async_handle)
|
||||||
|
{
|
||||||
|
int aborted = async_handle->aborted;
|
||||||
|
|
||||||
|
/* if client was destroyed, mutex doesn't exist and we don't need to remove the handle from the collection */
|
||||||
|
if (aborted != RC_CLIENT_ASYNC_DESTROYED) {
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
rc_mutex_lock(&client->state.mutex);
|
||||||
|
for (i = 0; i < sizeof(client->state.async_handles) / sizeof(client->state.async_handles[0]); ++i) {
|
||||||
|
if (client->state.async_handles[i] == async_handle) {
|
||||||
|
client->state.async_handles[i] = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
aborted = async_handle->aborted;
|
||||||
|
|
||||||
|
rc_mutex_unlock(&client->state.mutex);
|
||||||
|
}
|
||||||
|
|
||||||
return aborted;
|
return aborted;
|
||||||
}
|
}
|
||||||
|
@ -287,7 +334,7 @@ void rc_client_abort_async(rc_client_t* client, rc_client_async_handle_t* async_
|
||||||
{
|
{
|
||||||
if (async_handle && client) {
|
if (async_handle && client) {
|
||||||
rc_mutex_lock(&client->state.mutex);
|
rc_mutex_lock(&client->state.mutex);
|
||||||
async_handle->aborted = 1;
|
async_handle->aborted = RC_CLIENT_ASYNC_ABORTED;
|
||||||
rc_mutex_unlock(&client->state.mutex);
|
rc_mutex_unlock(&client->state.mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -311,13 +358,16 @@ static const char* rc_client_server_error_message(int* result, int http_status_c
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rc_client_raise_server_error_event(rc_client_t* client, const char* api, const char* error_message)
|
static void rc_client_raise_server_error_event(rc_client_t* client,
|
||||||
|
const char* api, uint32_t related_id, int result, const char* error_message)
|
||||||
{
|
{
|
||||||
rc_client_server_error_t server_error;
|
rc_client_server_error_t server_error;
|
||||||
rc_client_event_t client_event;
|
rc_client_event_t client_event;
|
||||||
|
|
||||||
server_error.api = api;
|
server_error.api = api;
|
||||||
server_error.error_message = error_message;
|
server_error.error_message = error_message;
|
||||||
|
server_error.result = result;
|
||||||
|
server_error.related_id = related_id;
|
||||||
|
|
||||||
memset(&client_event, 0, sizeof(client_event));
|
memset(&client_event, 0, sizeof(client_event));
|
||||||
client_event.type = RC_CLIENT_EVENT_SERVER_ERROR;
|
client_event.type = RC_CLIENT_EVENT_SERVER_ERROR;
|
||||||
|
@ -380,11 +430,15 @@ static int rc_client_should_retry(const rc_api_server_response_t* server_respons
|
||||||
{
|
{
|
||||||
switch (server_response->http_status_code) {
|
switch (server_response->http_status_code) {
|
||||||
case 502: /* 502 Bad Gateway */
|
case 502: /* 502 Bad Gateway */
|
||||||
/* nginx connection pool full. retry */
|
/* nginx connection pool full */
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
case 503: /* 503 Service Temporarily Unavailable */
|
case 503: /* 503 Service Temporarily Unavailable */
|
||||||
/* site is in maintenance mode. retry */
|
/* site is in maintenance mode */
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case 504: /* 504 Gateway Timeout */
|
||||||
|
/* timeout between web server and database server */
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
case 429: /* 429 Too Many Requests */
|
case 429: /* 429 Too Many Requests */
|
||||||
|
@ -407,7 +461,19 @@ static int rc_client_should_retry(const rc_api_server_response_t* server_respons
|
||||||
/* connection to server from cloudfare was dropped before request was completed */
|
/* connection to server from cloudfare was dropped before request was completed */
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
case RC_API_SERVER_RESPONSE_RETRYABLE_CLIENT_ERROR:
|
||||||
|
/* client provided non-HTTP error (explicitly retryable) */
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case RC_API_SERVER_RESPONSE_CLIENT_ERROR:
|
||||||
|
/* client provided non-HTTP error (implicitly non-retryable) */
|
||||||
|
return 0;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
/* assume any error not handled above where no response was received should be retried */
|
||||||
|
if (server_response->body_length == 0 || !server_response->body || !server_response->body[0])
|
||||||
|
return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -443,8 +509,11 @@ static void rc_client_login_callback(const rc_api_server_response_t* server_resp
|
||||||
const char* error_message;
|
const char* error_message;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if (rc_client_async_handle_aborted(client, &login_callback_data->async_handle)) {
|
result = rc_client_end_async(client, &login_callback_data->async_handle);
|
||||||
RC_CLIENT_LOG_VERBOSE(client, "Login aborted");
|
if (result) {
|
||||||
|
if (result != RC_CLIENT_ASYNC_DESTROYED)
|
||||||
|
rc_client_logout(client); /* logout will reset the user state and call the load game callback */
|
||||||
|
|
||||||
free(login_callback_data);
|
free(login_callback_data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -455,6 +524,7 @@ static void rc_client_login_callback(const rc_api_server_response_t* server_resp
|
||||||
login_callback_data->callback(RC_ABORTED, "Login aborted", client, login_callback_data->callback_userdata);
|
login_callback_data->callback(RC_ABORTED, "Login aborted", client, login_callback_data->callback_userdata);
|
||||||
|
|
||||||
free(login_callback_data);
|
free(login_callback_data);
|
||||||
|
/* logout call will immediately abort load game before this callback gets called */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,14 +544,14 @@ static void rc_client_login_callback(const rc_api_server_response_t* server_resp
|
||||||
rc_client_begin_fetch_game_data(load_state);
|
rc_client_begin_fetch_game_data(load_state);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
client->user.username = rc_buf_strcpy(&client->state.buffer, login_response.username);
|
client->user.username = rc_buffer_strcpy(&client->state.buffer, login_response.username);
|
||||||
|
|
||||||
if (strcmp(login_response.username, login_response.display_name) == 0)
|
if (strcmp(login_response.username, login_response.display_name) == 0)
|
||||||
client->user.display_name = client->user.username;
|
client->user.display_name = client->user.username;
|
||||||
else
|
else
|
||||||
client->user.display_name = rc_buf_strcpy(&client->state.buffer, login_response.display_name);
|
client->user.display_name = rc_buffer_strcpy(&client->state.buffer, login_response.display_name);
|
||||||
|
|
||||||
client->user.token = rc_buf_strcpy(&client->state.buffer, login_response.api_token);
|
client->user.token = rc_buffer_strcpy(&client->state.buffer, login_response.api_token);
|
||||||
client->user.score = login_response.score;
|
client->user.score = login_response.score;
|
||||||
client->user.score_softcore = login_response.score_softcore;
|
client->user.score_softcore = login_response.score_softcore;
|
||||||
client->user.num_unread_messages = login_response.num_unread_messages;
|
client->user.num_unread_messages = login_response.num_unread_messages;
|
||||||
|
@ -539,7 +609,9 @@ static rc_client_async_handle_t* rc_client_begin_login(rc_client_t* client,
|
||||||
callback_data->callback = callback;
|
callback_data->callback = callback;
|
||||||
callback_data->callback_userdata = callback_userdata;
|
callback_data->callback_userdata = callback_userdata;
|
||||||
|
|
||||||
|
rc_client_begin_async(client, &callback_data->async_handle);
|
||||||
client->callbacks.server_call(&request, rc_client_login_callback, callback_data, client);
|
client->callbacks.server_call(&request, rc_client_login_callback, callback_data, client);
|
||||||
|
|
||||||
rc_api_destroy_request(&request);
|
rc_api_destroy_request(&request);
|
||||||
|
|
||||||
return &callback_data->async_handle;
|
return &callback_data->async_handle;
|
||||||
|
@ -702,7 +774,7 @@ static void rc_client_free_game(rc_client_game_info_t* game)
|
||||||
{
|
{
|
||||||
rc_runtime_destroy(&game->runtime);
|
rc_runtime_destroy(&game->runtime);
|
||||||
|
|
||||||
rc_buf_destroy(&game->buffer);
|
rc_buffer_destroy(&game->buffer);
|
||||||
|
|
||||||
free(game);
|
free(game);
|
||||||
}
|
}
|
||||||
|
@ -780,6 +852,8 @@ static void rc_client_load_error(rc_client_load_state_t* load_state, int result,
|
||||||
|
|
||||||
rc_mutex_unlock(&load_state->client->state.mutex);
|
rc_mutex_unlock(&load_state->client->state.mutex);
|
||||||
|
|
||||||
|
RC_CLIENT_LOG_ERR_FORMATTED(load_state->client, "Load failed (%d): %s", result, error_message);
|
||||||
|
|
||||||
if (load_state->callback)
|
if (load_state->callback)
|
||||||
load_state->callback(result, error_message, load_state->client, load_state->callback_userdata);
|
load_state->callback(result, error_message, load_state->client, load_state->callback_userdata);
|
||||||
|
|
||||||
|
@ -815,6 +889,10 @@ static void rc_client_invalidate_memref_achievements(rc_client_game_info_t* game
|
||||||
if (rc_trigger_contains_memref(achievement->trigger, memref)) {
|
if (rc_trigger_contains_memref(achievement->trigger, memref)) {
|
||||||
achievement->public_.state = RC_CLIENT_ACHIEVEMENT_STATE_DISABLED;
|
achievement->public_.state = RC_CLIENT_ACHIEVEMENT_STATE_DISABLED;
|
||||||
achievement->public_.bucket = RC_CLIENT_ACHIEVEMENT_BUCKET_UNSUPPORTED;
|
achievement->public_.bucket = RC_CLIENT_ACHIEVEMENT_BUCKET_UNSUPPORTED;
|
||||||
|
|
||||||
|
if (achievement->trigger)
|
||||||
|
achievement->trigger->state = RC_TRIGGER_STATE_DISABLED;
|
||||||
|
|
||||||
RC_CLIENT_LOG_WARN_FORMATTED(client, "Disabled achievement %u. Invalid address %06X", achievement->public_.id, memref->address);
|
RC_CLIENT_LOG_WARN_FORMATTED(client, "Disabled achievement %u. Invalid address %06X", achievement->public_.id, memref->address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -842,6 +920,9 @@ static void rc_client_invalidate_memref_leaderboards(rc_client_game_info_t* game
|
||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (leaderboard->lboard)
|
||||||
|
leaderboard->lboard->state = RC_LBOARD_STATE_DISABLED;
|
||||||
|
|
||||||
RC_CLIENT_LOG_WARN_FORMATTED(client, "Disabled leaderboard %u. Invalid address %06X", leaderboard->public_.id, memref->address);
|
RC_CLIENT_LOG_WARN_FORMATTED(client, "Disabled leaderboard %u. Invalid address %06X", leaderboard->public_.id, memref->address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -889,33 +970,33 @@ static void rc_client_update_legacy_runtime_achievements(rc_client_game_info_t*
|
||||||
rc_client_achievement_info_t* achievement;
|
rc_client_achievement_info_t* achievement;
|
||||||
rc_client_achievement_info_t* stop;
|
rc_client_achievement_info_t* stop;
|
||||||
rc_runtime_trigger_t* trigger;
|
rc_runtime_trigger_t* trigger;
|
||||||
|
rc_client_subset_info_t* subset;
|
||||||
|
|
||||||
rc_client_subset_info_t* subset = game->subsets;
|
if (active_count <= game->runtime.trigger_capacity) {
|
||||||
for (; subset; subset = subset->next) {
|
if (active_count != 0)
|
||||||
|
memset(game->runtime.triggers, 0, active_count * sizeof(rc_runtime_trigger_t));
|
||||||
|
} else {
|
||||||
|
if (game->runtime.triggers)
|
||||||
|
free(game->runtime.triggers);
|
||||||
|
|
||||||
|
game->runtime.trigger_capacity = active_count;
|
||||||
|
game->runtime.triggers = (rc_runtime_trigger_t*)calloc(1, active_count * sizeof(rc_runtime_trigger_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
trigger = game->runtime.triggers;
|
||||||
|
if (!trigger) {
|
||||||
|
/* malloc failed, no way to report error, just bail */
|
||||||
|
game->runtime.trigger_count = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (subset = game->subsets; subset; subset = subset->next) {
|
||||||
if (!subset->active)
|
if (!subset->active)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
achievement = subset->achievements;
|
achievement = subset->achievements;
|
||||||
stop = achievement + subset->public_.num_achievements;
|
stop = achievement + subset->public_.num_achievements;
|
||||||
|
|
||||||
if (active_count <= game->runtime.trigger_capacity) {
|
|
||||||
if (active_count != 0)
|
|
||||||
memset(game->runtime.triggers, 0, active_count * sizeof(rc_runtime_trigger_t));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (game->runtime.triggers)
|
|
||||||
free(game->runtime.triggers);
|
|
||||||
|
|
||||||
game->runtime.trigger_capacity = active_count;
|
|
||||||
game->runtime.triggers = (rc_runtime_trigger_t*)calloc(1, active_count * sizeof(rc_runtime_trigger_t));
|
|
||||||
if (!game->runtime.triggers) {
|
|
||||||
/* Unexpected, no callback available, just fail */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trigger = game->runtime.triggers;
|
|
||||||
achievement = subset->achievements;
|
|
||||||
for (; achievement < stop; ++achievement) {
|
for (; achievement < stop; ++achievement) {
|
||||||
if (achievement->public_.state == RC_CLIENT_ACHIEVEMENT_STATE_ACTIVE) {
|
if (achievement->public_.state == RC_CLIENT_ACHIEVEMENT_STATE_ACTIVE) {
|
||||||
trigger->id = achievement->public_.id;
|
trigger->id = achievement->public_.id;
|
||||||
|
@ -944,7 +1025,7 @@ static uint32_t rc_client_subset_count_active_achievements(const rc_client_subse
|
||||||
return active_count;
|
return active_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rc_client_update_active_achievements(rc_client_game_info_t* game)
|
void rc_client_update_active_achievements(rc_client_game_info_t* game)
|
||||||
{
|
{
|
||||||
uint32_t active_count = 0;
|
uint32_t active_count = 0;
|
||||||
rc_client_subset_info_t* subset = game->subsets;
|
rc_client_subset_info_t* subset = game->subsets;
|
||||||
|
@ -997,6 +1078,9 @@ static uint32_t rc_client_subset_toggle_hardcore_achievements(rc_client_subset_i
|
||||||
client_event.achievement = &achievement->public_;
|
client_event.achievement = &achievement->public_;
|
||||||
client->callbacks.event_handler(&client_event, client);
|
client->callbacks.event_handler(&client_event, client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (achievement->trigger && rc_trigger_state_active(achievement->trigger->state))
|
||||||
|
achievement->trigger->state = RC_TRIGGER_STATE_TRIGGERED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1024,12 +1108,89 @@ static void rc_client_activate_achievements(rc_client_game_info_t* game, rc_clie
|
||||||
rc_client_toggle_hardcore_achievements(game, client, active_bit);
|
rc_client_toggle_hardcore_achievements(game, client, active_bit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rc_client_update_legacy_runtime_leaderboards(rc_client_game_info_t* game, uint32_t active_count)
|
||||||
|
{
|
||||||
|
if (active_count > 0) {
|
||||||
|
rc_client_leaderboard_info_t* leaderboard;
|
||||||
|
rc_client_leaderboard_info_t* stop;
|
||||||
|
rc_client_subset_info_t* subset;
|
||||||
|
rc_runtime_lboard_t* lboard;
|
||||||
|
|
||||||
|
if (active_count <= game->runtime.lboard_capacity) {
|
||||||
|
if (active_count != 0)
|
||||||
|
memset(game->runtime.lboards, 0, active_count * sizeof(rc_runtime_lboard_t));
|
||||||
|
} else {
|
||||||
|
if (game->runtime.lboards)
|
||||||
|
free(game->runtime.lboards);
|
||||||
|
|
||||||
|
game->runtime.lboard_capacity = active_count;
|
||||||
|
game->runtime.lboards = (rc_runtime_lboard_t*)calloc(1, active_count * sizeof(rc_runtime_lboard_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
lboard = game->runtime.lboards;
|
||||||
|
if (!lboard) {
|
||||||
|
/* malloc failed. no way to report error, just bail */
|
||||||
|
game->runtime.lboard_count = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (subset = game->subsets; subset; subset = subset->next) {
|
||||||
|
if (!subset->active)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
leaderboard = subset->leaderboards;
|
||||||
|
stop = leaderboard + subset->public_.num_leaderboards;
|
||||||
|
for (; leaderboard < stop; ++leaderboard) {
|
||||||
|
if (leaderboard->public_.state == RC_CLIENT_LEADERBOARD_STATE_ACTIVE ||
|
||||||
|
leaderboard->public_.state == RC_CLIENT_LEADERBOARD_STATE_TRACKING) {
|
||||||
|
lboard->id = leaderboard->public_.id;
|
||||||
|
memcpy(lboard->md5, leaderboard->md5, 16);
|
||||||
|
lboard->lboard = leaderboard->lboard;
|
||||||
|
++lboard;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
game->runtime.lboard_count = active_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rc_client_update_active_leaderboards(rc_client_game_info_t* game)
|
||||||
|
{
|
||||||
|
rc_client_leaderboard_info_t* leaderboard;
|
||||||
|
rc_client_leaderboard_info_t* stop;
|
||||||
|
|
||||||
|
uint32_t active_count = 0;
|
||||||
|
rc_client_subset_info_t* subset = game->subsets;
|
||||||
|
for (; subset; subset = subset->next)
|
||||||
|
{
|
||||||
|
if (!subset->active)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
leaderboard = subset->leaderboards;
|
||||||
|
stop = leaderboard + subset->public_.num_leaderboards;
|
||||||
|
|
||||||
|
for (; leaderboard < stop; ++leaderboard)
|
||||||
|
{
|
||||||
|
switch (leaderboard->public_.state)
|
||||||
|
{
|
||||||
|
case RC_CLIENT_LEADERBOARD_STATE_ACTIVE:
|
||||||
|
case RC_CLIENT_LEADERBOARD_STATE_TRACKING:
|
||||||
|
++active_count;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_client_update_legacy_runtime_leaderboards(game, active_count);
|
||||||
|
}
|
||||||
|
|
||||||
static void rc_client_activate_leaderboards(rc_client_game_info_t* game, rc_client_t* client)
|
static void rc_client_activate_leaderboards(rc_client_game_info_t* game, rc_client_t* client)
|
||||||
{
|
{
|
||||||
rc_client_leaderboard_info_t* leaderboard;
|
rc_client_leaderboard_info_t* leaderboard;
|
||||||
rc_client_leaderboard_info_t* stop;
|
rc_client_leaderboard_info_t* stop;
|
||||||
|
|
||||||
unsigned active_count = 0;
|
uint32_t active_count = 0;
|
||||||
rc_client_subset_info_t* subset = game->subsets;
|
rc_client_subset_info_t* subset = game->subsets;
|
||||||
for (; subset; subset = subset->next) {
|
for (; subset; subset = subset->next) {
|
||||||
if (!subset->active)
|
if (!subset->active)
|
||||||
|
@ -1061,43 +1222,7 @@ static void rc_client_activate_leaderboards(rc_client_game_info_t* game, rc_clie
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (active_count > 0) {
|
rc_client_update_legacy_runtime_leaderboards(game, active_count);
|
||||||
rc_runtime_lboard_t* lboard;
|
|
||||||
|
|
||||||
if (active_count <= game->runtime.lboard_capacity) {
|
|
||||||
if (active_count != 0)
|
|
||||||
memset(game->runtime.lboards, 0, active_count * sizeof(rc_runtime_lboard_t));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (game->runtime.lboards)
|
|
||||||
free(game->runtime.lboards);
|
|
||||||
|
|
||||||
game->runtime.lboard_capacity = active_count;
|
|
||||||
game->runtime.lboards = (rc_runtime_lboard_t*)calloc(1, active_count * sizeof(rc_runtime_lboard_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
lboard = game->runtime.lboards;
|
|
||||||
|
|
||||||
subset = game->subsets;
|
|
||||||
for (; subset; subset = subset->next) {
|
|
||||||
if (!subset->active)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
leaderboard = subset->leaderboards;
|
|
||||||
stop = leaderboard + subset->public_.num_leaderboards;
|
|
||||||
for (; leaderboard < stop; ++leaderboard) {
|
|
||||||
if (leaderboard->public_.state == RC_CLIENT_LEADERBOARD_STATE_ACTIVE ||
|
|
||||||
leaderboard->public_.state == RC_CLIENT_LEADERBOARD_STATE_TRACKING) {
|
|
||||||
lboard->id = leaderboard->public_.id;
|
|
||||||
memcpy(lboard->md5, leaderboard->md5, 16);
|
|
||||||
lboard->lboard = leaderboard->lboard;
|
|
||||||
++lboard;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
game->runtime.lboard_count = active_count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rc_client_deactivate_leaderboards(rc_client_game_info_t* game, rc_client_t* client)
|
static void rc_client_deactivate_leaderboards(rc_client_game_info_t* game, rc_client_t* client)
|
||||||
|
@ -1225,7 +1350,7 @@ static void rc_client_activate_game(rc_client_load_state_t* load_state, rc_api_s
|
||||||
if (load_state->hash->hash[0] != '[') {
|
if (load_state->hash->hash[0] != '[') {
|
||||||
if (load_state->client->state.spectator_mode != RC_CLIENT_SPECTATOR_MODE_LOCKED) {
|
if (load_state->client->state.spectator_mode != RC_CLIENT_SPECTATOR_MODE_LOCKED) {
|
||||||
/* schedule the periodic ping */
|
/* schedule the periodic ping */
|
||||||
rc_client_scheduled_callback_data_t* callback_data = rc_buf_alloc(&load_state->game->buffer, sizeof(rc_client_scheduled_callback_data_t));
|
rc_client_scheduled_callback_data_t* callback_data = rc_buffer_alloc(&load_state->game->buffer, sizeof(rc_client_scheduled_callback_data_t));
|
||||||
memset(callback_data, 0, sizeof(*callback_data));
|
memset(callback_data, 0, sizeof(*callback_data));
|
||||||
callback_data->callback = rc_client_ping;
|
callback_data->callback = rc_client_ping;
|
||||||
callback_data->related_id = load_state->game->public_.id;
|
callback_data->related_id = load_state->game->public_.id;
|
||||||
|
@ -1260,10 +1385,15 @@ static void rc_client_start_session_callback(const rc_api_server_response_t* ser
|
||||||
const char* error_message;
|
const char* error_message;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if (rc_client_async_handle_aborted(load_state->client, &load_state->async_handle)) {
|
result = rc_client_end_async(load_state->client, &load_state->async_handle);
|
||||||
rc_client_t* client = load_state->client;
|
if (result) {
|
||||||
rc_client_load_aborted(load_state);
|
if (result != RC_CLIENT_ASYNC_DESTROYED) {
|
||||||
RC_CLIENT_LOG_VERBOSE(client, "Load aborted while starting session");
|
rc_client_t* client = load_state->client;
|
||||||
|
rc_client_load_aborted(load_state);
|
||||||
|
RC_CLIENT_LOG_VERBOSE(client, "Load aborted while starting session");
|
||||||
|
} else {
|
||||||
|
rc_client_free_load_state(load_state);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1315,6 +1445,7 @@ static void rc_client_begin_start_session(rc_client_load_state_t* load_state)
|
||||||
else {
|
else {
|
||||||
rc_client_begin_load_state(load_state, RC_CLIENT_LOAD_STATE_STARTING_SESSION, 1);
|
rc_client_begin_load_state(load_state, RC_CLIENT_LOAD_STATE_STARTING_SESSION, 1);
|
||||||
RC_CLIENT_LOG_VERBOSE_FORMATTED(client, "Starting session for game %u", start_session_params.game_id);
|
RC_CLIENT_LOG_VERBOSE_FORMATTED(client, "Starting session for game %u", start_session_params.game_id);
|
||||||
|
rc_client_begin_async(client, &load_state->async_handle);
|
||||||
client->callbacks.server_call(&start_session_request, rc_client_start_session_callback, load_state, client);
|
client->callbacks.server_call(&start_session_request, rc_client_start_session_callback, load_state, client);
|
||||||
rc_api_destroy_request(&start_session_request);
|
rc_api_destroy_request(&start_session_request);
|
||||||
}
|
}
|
||||||
|
@ -1329,7 +1460,7 @@ static void rc_client_copy_achievements(rc_client_load_state_t* load_state,
|
||||||
rc_client_achievement_info_t* achievements;
|
rc_client_achievement_info_t* achievements;
|
||||||
rc_client_achievement_info_t* achievement;
|
rc_client_achievement_info_t* achievement;
|
||||||
rc_client_achievement_info_t* scan;
|
rc_client_achievement_info_t* scan;
|
||||||
rc_api_buffer_t* buffer;
|
rc_buffer_t* buffer;
|
||||||
rc_parse_state_t parse;
|
rc_parse_state_t parse;
|
||||||
const char* memaddr;
|
const char* memaddr;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
@ -1362,12 +1493,12 @@ static void rc_client_copy_achievements(rc_client_load_state_t* load_state,
|
||||||
+ sizeof(rc_trigger_t) + sizeof(rc_condset_t) * 2 /* trigger container */
|
+ sizeof(rc_trigger_t) + sizeof(rc_condset_t) * 2 /* trigger container */
|
||||||
+ sizeof(rc_condition_t) * 8 /* assume average trigger length of 8 conditions */
|
+ sizeof(rc_condition_t) * 8 /* assume average trigger length of 8 conditions */
|
||||||
+ sizeof(rc_client_achievement_info_t);
|
+ sizeof(rc_client_achievement_info_t);
|
||||||
rc_buf_reserve(&load_state->game->buffer, size * num_achievements);
|
rc_buffer_reserve(&load_state->game->buffer, size * num_achievements);
|
||||||
|
|
||||||
/* allocate the achievement array */
|
/* allocate the achievement array */
|
||||||
size = sizeof(rc_client_achievement_info_t) * num_achievements;
|
size = sizeof(rc_client_achievement_info_t) * num_achievements;
|
||||||
buffer = &load_state->game->buffer;
|
buffer = &load_state->game->buffer;
|
||||||
achievement = achievements = rc_buf_alloc(buffer, size);
|
achievement = achievements = rc_buffer_alloc(buffer, size);
|
||||||
memset(achievements, 0, size);
|
memset(achievements, 0, size);
|
||||||
|
|
||||||
/* copy the achievement data */
|
/* copy the achievement data */
|
||||||
|
@ -1375,8 +1506,8 @@ static void rc_client_copy_achievements(rc_client_load_state_t* load_state,
|
||||||
if (read->category != RC_ACHIEVEMENT_CATEGORY_CORE && !load_state->client->state.unofficial_enabled)
|
if (read->category != RC_ACHIEVEMENT_CATEGORY_CORE && !load_state->client->state.unofficial_enabled)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
achievement->public_.title = rc_buf_strcpy(buffer, read->title);
|
achievement->public_.title = rc_buffer_strcpy(buffer, read->title);
|
||||||
achievement->public_.description = rc_buf_strcpy(buffer, read->description);
|
achievement->public_.description = rc_buffer_strcpy(buffer, read->description);
|
||||||
snprintf(achievement->public_.badge_name, sizeof(achievement->public_.badge_name), "%s", read->badge_name);
|
snprintf(achievement->public_.badge_name, sizeof(achievement->public_.badge_name), "%s", read->badge_name);
|
||||||
achievement->public_.id = read->id;
|
achievement->public_.id = read->id;
|
||||||
achievement->public_.points = read->points;
|
achievement->public_.points = read->points;
|
||||||
|
@ -1394,7 +1525,7 @@ static void rc_client_copy_achievements(rc_client_load_state_t* load_state,
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* populate the item, using the communal memrefs pool */
|
/* populate the item, using the communal memrefs pool */
|
||||||
rc_init_parse_state(&parse, rc_buf_reserve(buffer, trigger_size), NULL, 0);
|
rc_init_parse_state(&parse, rc_buffer_reserve(buffer, trigger_size), NULL, 0);
|
||||||
parse.first_memref = &load_state->game->runtime.memrefs;
|
parse.first_memref = &load_state->game->runtime.memrefs;
|
||||||
parse.variables = &load_state->game->runtime.variables;
|
parse.variables = &load_state->game->runtime.variables;
|
||||||
achievement->trigger = RC_ALLOC(rc_trigger_t, &parse);
|
achievement->trigger = RC_ALLOC(rc_trigger_t, &parse);
|
||||||
|
@ -1406,7 +1537,7 @@ static void rc_client_copy_achievements(rc_client_load_state_t* load_state,
|
||||||
achievement->public_.bucket = RC_CLIENT_ACHIEVEMENT_BUCKET_UNSUPPORTED;
|
achievement->public_.bucket = RC_CLIENT_ACHIEVEMENT_BUCKET_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rc_buf_consume(buffer, parse.buffer, (char*)parse.buffer + parse.offset);
|
rc_buffer_consume(buffer, parse.buffer, (uint8_t*)parse.buffer + parse.offset);
|
||||||
achievement->trigger->memrefs = NULL; /* memrefs managed by runtime */
|
achievement->trigger->memrefs = NULL; /* memrefs managed by runtime */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1425,7 +1556,7 @@ static void rc_client_copy_achievements(rc_client_load_state_t* load_state,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!achievement->author)
|
if (!achievement->author)
|
||||||
achievement->author = rc_buf_strcpy(buffer, read->author);
|
achievement->author = rc_buffer_strcpy(buffer, read->author);
|
||||||
|
|
||||||
++achievement;
|
++achievement;
|
||||||
}
|
}
|
||||||
|
@ -1433,9 +1564,9 @@ static void rc_client_copy_achievements(rc_client_load_state_t* load_state,
|
||||||
subset->achievements = achievements;
|
subset->achievements = achievements;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t rc_client_map_leaderboard_format(const rc_api_leaderboard_definition_t* defn)
|
uint8_t rc_client_map_leaderboard_format(int format)
|
||||||
{
|
{
|
||||||
switch (defn->format) {
|
switch (format) {
|
||||||
case RC_FORMAT_SECONDS:
|
case RC_FORMAT_SECONDS:
|
||||||
case RC_FORMAT_CENTISECS:
|
case RC_FORMAT_CENTISECS:
|
||||||
case RC_FORMAT_MINUTES:
|
case RC_FORMAT_MINUTES:
|
||||||
|
@ -1466,7 +1597,7 @@ static void rc_client_copy_leaderboards(rc_client_load_state_t* load_state,
|
||||||
const rc_api_leaderboard_definition_t* stop;
|
const rc_api_leaderboard_definition_t* stop;
|
||||||
rc_client_leaderboard_info_t* leaderboards;
|
rc_client_leaderboard_info_t* leaderboards;
|
||||||
rc_client_leaderboard_info_t* leaderboard;
|
rc_client_leaderboard_info_t* leaderboard;
|
||||||
rc_api_buffer_t* buffer;
|
rc_buffer_t* buffer;
|
||||||
rc_parse_state_t parse;
|
rc_parse_state_t parse;
|
||||||
const char* memaddr;
|
const char* memaddr;
|
||||||
const char* ptr;
|
const char* ptr;
|
||||||
|
@ -1487,22 +1618,22 @@ static void rc_client_copy_leaderboards(rc_client_load_state_t* load_state,
|
||||||
+ (sizeof(rc_value_t) + sizeof(rc_condset_t)) /* value */
|
+ (sizeof(rc_value_t) + sizeof(rc_condset_t)) /* value */
|
||||||
+ sizeof(rc_condition_t) * 4 * 4 /* assume average of 4 conditions in each start/submit/cancel/value */
|
+ sizeof(rc_condition_t) * 4 * 4 /* assume average of 4 conditions in each start/submit/cancel/value */
|
||||||
+ sizeof(rc_client_leaderboard_info_t);
|
+ sizeof(rc_client_leaderboard_info_t);
|
||||||
rc_buf_reserve(&load_state->game->buffer, size * num_leaderboards);
|
rc_buffer_reserve(&load_state->game->buffer, size * num_leaderboards);
|
||||||
|
|
||||||
/* allocate the achievement array */
|
/* allocate the achievement array */
|
||||||
size = sizeof(rc_client_leaderboard_info_t) * num_leaderboards;
|
size = sizeof(rc_client_leaderboard_info_t) * num_leaderboards;
|
||||||
buffer = &load_state->game->buffer;
|
buffer = &load_state->game->buffer;
|
||||||
leaderboard = leaderboards = rc_buf_alloc(buffer, size);
|
leaderboard = leaderboards = rc_buffer_alloc(buffer, size);
|
||||||
memset(leaderboards, 0, size);
|
memset(leaderboards, 0, size);
|
||||||
|
|
||||||
/* copy the achievement data */
|
/* copy the achievement data */
|
||||||
read = leaderboard_definitions;
|
read = leaderboard_definitions;
|
||||||
stop = read + num_leaderboards;
|
stop = read + num_leaderboards;
|
||||||
do {
|
do {
|
||||||
leaderboard->public_.title = rc_buf_strcpy(buffer, read->title);
|
leaderboard->public_.title = rc_buffer_strcpy(buffer, read->title);
|
||||||
leaderboard->public_.description = rc_buf_strcpy(buffer, read->description);
|
leaderboard->public_.description = rc_buffer_strcpy(buffer, read->description);
|
||||||
leaderboard->public_.id = read->id;
|
leaderboard->public_.id = read->id;
|
||||||
leaderboard->public_.format = rc_client_map_leaderboard_format(read);
|
leaderboard->public_.format = rc_client_map_leaderboard_format(read->format);
|
||||||
leaderboard->public_.lower_is_better = read->lower_is_better;
|
leaderboard->public_.lower_is_better = read->lower_is_better;
|
||||||
leaderboard->format = (uint8_t)read->format;
|
leaderboard->format = (uint8_t)read->format;
|
||||||
leaderboard->hidden = (uint8_t)read->hidden;
|
leaderboard->hidden = (uint8_t)read->hidden;
|
||||||
|
@ -1527,7 +1658,7 @@ static void rc_client_copy_leaderboards(rc_client_load_state_t* load_state,
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* populate the item, using the communal memrefs pool */
|
/* populate the item, using the communal memrefs pool */
|
||||||
rc_init_parse_state(&parse, rc_buf_reserve(buffer, lboard_size), NULL, 0);
|
rc_init_parse_state(&parse, rc_buffer_reserve(buffer, lboard_size), NULL, 0);
|
||||||
parse.first_memref = &load_state->game->runtime.memrefs;
|
parse.first_memref = &load_state->game->runtime.memrefs;
|
||||||
parse.variables = &load_state->game->runtime.variables;
|
parse.variables = &load_state->game->runtime.variables;
|
||||||
leaderboard->lboard = RC_ALLOC(rc_lboard_t, &parse);
|
leaderboard->lboard = RC_ALLOC(rc_lboard_t, &parse);
|
||||||
|
@ -1538,7 +1669,7 @@ static void rc_client_copy_leaderboards(rc_client_load_state_t* load_state,
|
||||||
leaderboard->public_.state = RC_CLIENT_LEADERBOARD_STATE_DISABLED;
|
leaderboard->public_.state = RC_CLIENT_LEADERBOARD_STATE_DISABLED;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rc_buf_consume(buffer, parse.buffer, (char*)parse.buffer + parse.offset);
|
rc_buffer_consume(buffer, parse.buffer, (uint8_t*)parse.buffer + parse.offset);
|
||||||
leaderboard->lboard->memrefs = NULL; /* memrefs managed by runtime */
|
leaderboard->lboard->memrefs = NULL; /* memrefs managed by runtime */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1559,7 +1690,7 @@ static const char* rc_client_subset_extract_title(rc_client_game_info_t* game, c
|
||||||
const char* start = subset_prefix + 10;
|
const char* start = subset_prefix + 10;
|
||||||
const char* stop = strstr(start, "]");
|
const char* stop = strstr(start, "]");
|
||||||
const size_t len = stop - start;
|
const size_t len = stop - start;
|
||||||
char* result = (char*)rc_buf_alloc(&game->buffer, len + 1);
|
char* result = (char*)rc_buffer_alloc(&game->buffer, len + 1);
|
||||||
|
|
||||||
memcpy(result, start, len);
|
memcpy(result, start, len);
|
||||||
result[len] = '\0';
|
result[len] = '\0';
|
||||||
|
@ -1577,10 +1708,15 @@ static void rc_client_fetch_game_data_callback(const rc_api_server_response_t* s
|
||||||
const char* error_message;
|
const char* error_message;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if (rc_client_async_handle_aborted(load_state->client, &load_state->async_handle)) {
|
result = rc_client_end_async(load_state->client, &load_state->async_handle);
|
||||||
rc_client_t* client = load_state->client;
|
if (result) {
|
||||||
rc_client_load_aborted(load_state);
|
if (result != RC_CLIENT_ASYNC_DESTROYED) {
|
||||||
RC_CLIENT_LOG_VERBOSE(client, "Load aborted while fetching game data");
|
rc_client_t* client = load_state->client;
|
||||||
|
rc_client_load_aborted(load_state);
|
||||||
|
RC_CLIENT_LOG_VERBOSE(client, "Load aborted while fetching game data");
|
||||||
|
} else {
|
||||||
|
rc_client_free_load_state(load_state);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1598,7 +1734,7 @@ static void rc_client_fetch_game_data_callback(const rc_api_server_response_t* s
|
||||||
else {
|
else {
|
||||||
rc_client_subset_info_t* subset;
|
rc_client_subset_info_t* subset;
|
||||||
|
|
||||||
subset = (rc_client_subset_info_t*)rc_buf_alloc(&load_state->game->buffer, sizeof(rc_client_subset_info_t));
|
subset = (rc_client_subset_info_t*)rc_buffer_alloc(&load_state->game->buffer, sizeof(rc_client_subset_info_t));
|
||||||
memset(subset, 0, sizeof(*subset));
|
memset(subset, 0, sizeof(*subset));
|
||||||
subset->public_.id = fetch_game_data_response.id;
|
subset->public_.id = fetch_game_data_response.id;
|
||||||
subset->active = 1;
|
subset->active = 1;
|
||||||
|
@ -1630,7 +1766,7 @@ static void rc_client_fetch_game_data_callback(const rc_api_server_response_t* s
|
||||||
if (!load_state->game->subsets) {
|
if (!load_state->game->subsets) {
|
||||||
/* core set */
|
/* core set */
|
||||||
rc_mutex_lock(&load_state->client->state.mutex);
|
rc_mutex_lock(&load_state->client->state.mutex);
|
||||||
load_state->game->public_.title = rc_buf_strcpy(&load_state->game->buffer, fetch_game_data_response.title);
|
load_state->game->public_.title = rc_buffer_strcpy(&load_state->game->buffer, fetch_game_data_response.title);
|
||||||
load_state->game->subsets = subset;
|
load_state->game->subsets = subset;
|
||||||
load_state->game->public_.badge_name = subset->public_.badge_name;
|
load_state->game->public_.badge_name = subset->public_.badge_name;
|
||||||
load_state->game->public_.console_id = fetch_game_data_response.console_id;
|
load_state->game->public_.console_id = fetch_game_data_response.console_id;
|
||||||
|
@ -1662,7 +1798,7 @@ static void rc_client_fetch_game_data_callback(const rc_api_server_response_t* s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
subset->public_.title = rc_buf_strcpy(&load_state->game->buffer, fetch_game_data_response.title);
|
subset->public_.title = rc_buffer_strcpy(&load_state->game->buffer, fetch_game_data_response.title);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* append to subset list */
|
/* append to subset list */
|
||||||
|
@ -1723,7 +1859,7 @@ static void rc_client_begin_fetch_game_data(rc_client_load_state_t* load_state)
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr = (char*)rc_buf_alloc(&load_state->game->buffer, size);
|
ptr = (char*)rc_buffer_alloc(&load_state->game->buffer, size);
|
||||||
ptr += size - 1;
|
ptr += size - 1;
|
||||||
*ptr = '\0';
|
*ptr = '\0';
|
||||||
game_hash = load_state->game->media_hash->game_hash;
|
game_hash = load_state->game->media_hash->game_hash;
|
||||||
|
@ -1798,7 +1934,9 @@ static void rc_client_begin_fetch_game_data(rc_client_load_state_t* load_state)
|
||||||
rc_client_begin_load_state(load_state, RC_CLIENT_LOAD_STATE_FETCHING_GAME_DATA, 1);
|
rc_client_begin_load_state(load_state, RC_CLIENT_LOAD_STATE_FETCHING_GAME_DATA, 1);
|
||||||
|
|
||||||
RC_CLIENT_LOG_VERBOSE_FORMATTED(client, "Fetching data for game %u", fetch_game_data_request.game_id);
|
RC_CLIENT_LOG_VERBOSE_FORMATTED(client, "Fetching data for game %u", fetch_game_data_request.game_id);
|
||||||
|
rc_client_begin_async(client, &load_state->async_handle);
|
||||||
client->callbacks.server_call(&request, rc_client_fetch_game_data_callback, load_state, client);
|
client->callbacks.server_call(&request, rc_client_fetch_game_data_callback, load_state, client);
|
||||||
|
|
||||||
rc_api_destroy_request(&request);
|
rc_api_destroy_request(&request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1811,9 +1949,14 @@ static void rc_client_identify_game_callback(const rc_api_server_response_t* ser
|
||||||
const char* error_message;
|
const char* error_message;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if (rc_client_async_handle_aborted(client, &load_state->async_handle)) {
|
result = rc_client_end_async(client, &load_state->async_handle);
|
||||||
rc_client_load_aborted(load_state);
|
if (result) {
|
||||||
RC_CLIENT_LOG_VERBOSE(client, "Load aborted during game identification");
|
if (result != RC_CLIENT_ASYNC_DESTROYED) {
|
||||||
|
rc_client_load_aborted(load_state);
|
||||||
|
RC_CLIENT_LOG_VERBOSE(client, "Load aborted during game identification");
|
||||||
|
} else {
|
||||||
|
rc_client_free_load_state(load_state);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1856,7 +1999,7 @@ rc_client_game_hash_t* rc_client_find_game_hash(rc_client_t* client, const char*
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!game_hash) {
|
if (!game_hash) {
|
||||||
game_hash = rc_buf_alloc(&client->state.buffer, sizeof(rc_client_game_hash_t));
|
game_hash = rc_buffer_alloc(&client->state.buffer, sizeof(rc_client_game_hash_t));
|
||||||
memset(game_hash, 0, sizeof(*game_hash));
|
memset(game_hash, 0, sizeof(*game_hash));
|
||||||
snprintf(game_hash->hash, sizeof(game_hash->hash), "%s", hash);
|
snprintf(game_hash->hash, sizeof(game_hash->hash), "%s", hash);
|
||||||
game_hash->game_id = RC_CLIENT_UNKNOWN_GAME_ID;
|
game_hash->game_id = RC_CLIENT_UNKNOWN_GAME_ID;
|
||||||
|
@ -1888,7 +2031,7 @@ static rc_client_async_handle_t* rc_client_load_game(rc_client_load_state_t* loa
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc_buf_init(&load_state->game->buffer);
|
rc_buffer_init(&load_state->game->buffer);
|
||||||
rc_runtime_init(&load_state->game->runtime);
|
rc_runtime_init(&load_state->game->runtime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1906,7 +2049,7 @@ static rc_client_async_handle_t* rc_client_load_game(rc_client_load_state_t* loa
|
||||||
|
|
||||||
if (file_path) {
|
if (file_path) {
|
||||||
rc_client_media_hash_t* media_hash =
|
rc_client_media_hash_t* media_hash =
|
||||||
(rc_client_media_hash_t*)rc_buf_alloc(&load_state->game->buffer, sizeof(*media_hash));
|
(rc_client_media_hash_t*)rc_buffer_alloc(&load_state->game->buffer, sizeof(*media_hash));
|
||||||
media_hash->game_hash = load_state->hash;
|
media_hash->game_hash = load_state->hash;
|
||||||
media_hash->path_djb2 = rc_djb2(file_path);
|
media_hash->path_djb2 = rc_djb2(file_path);
|
||||||
media_hash->next = load_state->game->media_hash;
|
media_hash->next = load_state->game->media_hash;
|
||||||
|
@ -1932,6 +2075,7 @@ static rc_client_async_handle_t* rc_client_load_game(rc_client_load_state_t* loa
|
||||||
|
|
||||||
rc_client_begin_load_state(load_state, RC_CLIENT_LOAD_STATE_IDENTIFYING_GAME, 1);
|
rc_client_begin_load_state(load_state, RC_CLIENT_LOAD_STATE_IDENTIFYING_GAME, 1);
|
||||||
|
|
||||||
|
rc_client_begin_async(client, &load_state->async_handle);
|
||||||
client->callbacks.server_call(&request, rc_client_identify_game_callback, load_state, client);
|
client->callbacks.server_call(&request, rc_client_identify_game_callback, load_state, client);
|
||||||
|
|
||||||
rc_api_destroy_request(&request);
|
rc_api_destroy_request(&request);
|
||||||
|
@ -2101,7 +2245,12 @@ void rc_client_unload_game(rc_client_t* client)
|
||||||
|
|
||||||
game = client->game;
|
game = client->game;
|
||||||
client->game = NULL;
|
client->game = NULL;
|
||||||
client->state.load = NULL;
|
|
||||||
|
if (client->state.load) {
|
||||||
|
/* this mimics rc_client_abort_async without nesting the lock */
|
||||||
|
client->state.load->async_handle.aborted = RC_CLIENT_ASYNC_ABORTED;
|
||||||
|
client->state.load = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (client->state.spectator_mode == RC_CLIENT_SPECTATOR_MODE_LOCKED)
|
if (client->state.spectator_mode == RC_CLIENT_SPECTATOR_MODE_LOCKED)
|
||||||
client->state.spectator_mode = RC_CLIENT_SPECTATOR_MODE_ON;
|
client->state.spectator_mode = RC_CLIENT_SPECTATOR_MODE_ON;
|
||||||
|
@ -2162,11 +2311,14 @@ static void rc_client_identify_changed_media_callback(const rc_api_server_respon
|
||||||
int result = rc_api_process_resolve_hash_server_response(&resolve_hash_response, server_response);
|
int result = rc_api_process_resolve_hash_server_response(&resolve_hash_response, server_response);
|
||||||
const char* error_message = rc_client_server_error_message(&result, server_response->http_status_code, &resolve_hash_response.response);
|
const char* error_message = rc_client_server_error_message(&result, server_response->http_status_code, &resolve_hash_response.response);
|
||||||
|
|
||||||
if (rc_client_async_handle_aborted(client, &load_state->async_handle)) {
|
const int async_aborted = rc_client_end_async(client, &load_state->async_handle);
|
||||||
RC_CLIENT_LOG_VERBOSE(client, "Media change aborted");
|
if (async_aborted) {
|
||||||
/* if lookup succeeded, still capture the new hash */
|
if (async_aborted != RC_CLIENT_ASYNC_DESTROYED) {
|
||||||
if (result == RC_OK)
|
RC_CLIENT_LOG_VERBOSE(client, "Media change aborted");
|
||||||
load_state->hash->game_id = resolve_hash_response.game_id;
|
/* if lookup succeeded, still capture the new hash */
|
||||||
|
if (result == RC_OK)
|
||||||
|
load_state->hash->game_id = resolve_hash_response.game_id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (client->game != load_state->game) {
|
else if (client->game != load_state->game) {
|
||||||
/* loaded game changed. return success regardless of result */
|
/* loaded game changed. return success regardless of result */
|
||||||
|
@ -2301,7 +2453,7 @@ rc_client_async_handle_t* rc_client_begin_change_media(rc_client_t* client, cons
|
||||||
|
|
||||||
game_hash = rc_client_find_game_hash(client, hash);
|
game_hash = rc_client_find_game_hash(client, hash);
|
||||||
|
|
||||||
media_hash = (rc_client_media_hash_t*)rc_buf_alloc(&game->buffer, sizeof(*media_hash));
|
media_hash = (rc_client_media_hash_t*)rc_buffer_alloc(&game->buffer, sizeof(*media_hash));
|
||||||
media_hash->game_hash = game_hash;
|
media_hash->game_hash = game_hash;
|
||||||
media_hash->path_djb2 = path_djb2;
|
media_hash->path_djb2 = path_djb2;
|
||||||
|
|
||||||
|
@ -2348,6 +2500,7 @@ rc_client_async_handle_t* rc_client_begin_change_media(rc_client_t* client, cons
|
||||||
callback_data->hash = game_hash;
|
callback_data->hash = game_hash;
|
||||||
callback_data->game = game;
|
callback_data->game = game;
|
||||||
|
|
||||||
|
rc_client_begin_async(client, &callback_data->async_handle);
|
||||||
client->callbacks.server_call(&request, rc_client_identify_changed_media_callback, callback_data, client);
|
client->callbacks.server_call(&request, rc_client_identify_changed_media_callback, callback_data, client);
|
||||||
|
|
||||||
rc_api_destroy_request(&request);
|
rc_api_destroy_request(&request);
|
||||||
|
@ -2515,7 +2668,7 @@ static const char* rc_client_get_subset_achievement_bucket_label(uint8_t bucket_
|
||||||
|
|
||||||
label = rc_client_get_achievement_bucket_label(bucket_type);
|
label = rc_client_get_achievement_bucket_label(bucket_type);
|
||||||
new_label_len = strlen(subset->public_.title) + strlen(label) + 4;
|
new_label_len = strlen(subset->public_.title) + strlen(label) + 4;
|
||||||
new_label = (char*)rc_buf_alloc(&game->buffer, new_label_len);
|
new_label = (char*)rc_buffer_alloc(&game->buffer, new_label_len);
|
||||||
snprintf(new_label, new_label_len, "%s - %s", subset->public_.title, label);
|
snprintf(new_label, new_label_len, "%s - %s", subset->public_.title, label);
|
||||||
|
|
||||||
*ptr = new_label;
|
*ptr = new_label;
|
||||||
|
@ -2856,7 +3009,7 @@ static void rc_client_award_achievement_callback(const rc_api_server_response_t*
|
||||||
if (award_achievement_response.response.error_message && !rc_client_should_retry(server_response)) {
|
if (award_achievement_response.response.error_message && !rc_client_should_retry(server_response)) {
|
||||||
/* actual error from server */
|
/* actual error from server */
|
||||||
RC_CLIENT_LOG_ERR_FORMATTED(ach_data->client, "Error awarding achievement %u: %s", ach_data->id, error_message);
|
RC_CLIENT_LOG_ERR_FORMATTED(ach_data->client, "Error awarding achievement %u: %s", ach_data->id, error_message);
|
||||||
rc_client_raise_server_error_event(ach_data->client, "award_achievement", award_achievement_response.response.error_message);
|
rc_client_raise_server_error_event(ach_data->client, "award_achievement", ach_data->id, result, award_achievement_response.response.error_message);
|
||||||
}
|
}
|
||||||
else if (ach_data->retry_count++ == 0) {
|
else if (ach_data->retry_count++ == 0) {
|
||||||
/* first retry is immediate */
|
/* first retry is immediate */
|
||||||
|
@ -2874,7 +3027,7 @@ static void rc_client_award_achievement_callback(const rc_api_server_response_t*
|
||||||
ach_data->scheduled_callback_data = (rc_client_scheduled_callback_data_t*)calloc(1, sizeof(*ach_data->scheduled_callback_data));
|
ach_data->scheduled_callback_data = (rc_client_scheduled_callback_data_t*)calloc(1, sizeof(*ach_data->scheduled_callback_data));
|
||||||
if (!ach_data->scheduled_callback_data) {
|
if (!ach_data->scheduled_callback_data) {
|
||||||
RC_CLIENT_LOG_ERR_FORMATTED(ach_data->client, "Failed to allocate scheduled callback data for reattempt to unlock achievement %u", ach_data->id);
|
RC_CLIENT_LOG_ERR_FORMATTED(ach_data->client, "Failed to allocate scheduled callback data for reattempt to unlock achievement %u", ach_data->id);
|
||||||
rc_client_raise_server_error_event(ach_data->client, "award_achievement", rc_error_str(RC_OUT_OF_MEMORY));
|
rc_client_raise_server_error_event(ach_data->client, "award_achievement", ach_data->id, RC_OUT_OF_MEMORY, rc_error_str(RC_OUT_OF_MEMORY));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ach_data->scheduled_callback_data->callback = rc_client_award_achievement_retry;
|
ach_data->scheduled_callback_data->callback = rc_client_award_achievement_retry;
|
||||||
|
@ -3018,7 +3171,7 @@ static void rc_client_award_achievement(rc_client_t* client, rc_client_achieveme
|
||||||
callback_data = (rc_client_award_achievement_callback_data_t*)calloc(1, sizeof(*callback_data));
|
callback_data = (rc_client_award_achievement_callback_data_t*)calloc(1, sizeof(*callback_data));
|
||||||
if (!callback_data) {
|
if (!callback_data) {
|
||||||
RC_CLIENT_LOG_ERR_FORMATTED(client, "Failed to allocate callback data for unlocking achievement %u", achievement->public_.id);
|
RC_CLIENT_LOG_ERR_FORMATTED(client, "Failed to allocate callback data for unlocking achievement %u", achievement->public_.id);
|
||||||
rc_client_raise_server_error_event(client, "award_achievement", rc_error_str(RC_OUT_OF_MEMORY));
|
rc_client_raise_server_error_event(client, "award_achievement", achievement->public_.id, RC_OUT_OF_MEMORY, rc_error_str(RC_OUT_OF_MEMORY));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
callback_data->client = client;
|
callback_data->client = client;
|
||||||
|
@ -3118,7 +3271,7 @@ static const char* rc_client_get_subset_leaderboard_bucket_label(uint8_t bucket_
|
||||||
|
|
||||||
label = rc_client_get_leaderboard_bucket_label(bucket_type);
|
label = rc_client_get_leaderboard_bucket_label(bucket_type);
|
||||||
new_label_len = strlen(subset->public_.title) + strlen(label) + 4;
|
new_label_len = strlen(subset->public_.title) + strlen(label) + 4;
|
||||||
new_label = (char*)rc_buf_alloc(&game->buffer, new_label_len);
|
new_label = (char*)rc_buffer_alloc(&game->buffer, new_label_len);
|
||||||
snprintf(new_label, new_label_len, "%s - %s", subset->public_.title, label);
|
snprintf(new_label, new_label_len, "%s - %s", subset->public_.title, label);
|
||||||
|
|
||||||
*ptr = new_label;
|
*ptr = new_label;
|
||||||
|
@ -3379,7 +3532,7 @@ static void rc_client_allocate_leaderboard_tracker(rc_client_game_info_t* game,
|
||||||
if (!available_tracker) {
|
if (!available_tracker) {
|
||||||
rc_client_leaderboard_tracker_info_t** next = &game->leaderboard_trackers;
|
rc_client_leaderboard_tracker_info_t** next = &game->leaderboard_trackers;
|
||||||
|
|
||||||
available_tracker = (rc_client_leaderboard_tracker_info_t*)rc_buf_alloc(&game->buffer, sizeof(*available_tracker));
|
available_tracker = (rc_client_leaderboard_tracker_info_t*)rc_buffer_alloc(&game->buffer, sizeof(*available_tracker));
|
||||||
memset(available_tracker, 0, sizeof(*available_tracker));
|
memset(available_tracker, 0, sizeof(*available_tracker));
|
||||||
available_tracker->public_.id = 1;
|
available_tracker->public_.id = 1;
|
||||||
|
|
||||||
|
@ -3401,7 +3554,7 @@ static void rc_client_allocate_leaderboard_tracker(rc_client_game_info_t* game,
|
||||||
game->pending_events |= RC_CLIENT_GAME_PENDING_EVENT_LEADERBOARD_TRACKER;
|
game->pending_events |= RC_CLIENT_GAME_PENDING_EVENT_LEADERBOARD_TRACKER;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rc_client_release_leaderboard_tracker(rc_client_game_info_t* game, rc_client_leaderboard_info_t* leaderboard)
|
void rc_client_release_leaderboard_tracker(rc_client_game_info_t* game, rc_client_leaderboard_info_t* leaderboard)
|
||||||
{
|
{
|
||||||
rc_client_leaderboard_tracker_info_t* tracker = leaderboard->tracker;
|
rc_client_leaderboard_tracker_info_t* tracker = leaderboard->tracker;
|
||||||
leaderboard->tracker = NULL;
|
leaderboard->tracker = NULL;
|
||||||
|
@ -3476,7 +3629,7 @@ static void rc_client_raise_scoreboard_event(rc_client_submit_leaderboard_entry_
|
||||||
sboard.top_entries = (rc_client_leaderboard_scoreboard_entry_t*)calloc(
|
sboard.top_entries = (rc_client_leaderboard_scoreboard_entry_t*)calloc(
|
||||||
response->num_top_entries, sizeof(rc_client_leaderboard_scoreboard_entry_t));
|
response->num_top_entries, sizeof(rc_client_leaderboard_scoreboard_entry_t));
|
||||||
if (sboard.top_entries != NULL) {
|
if (sboard.top_entries != NULL) {
|
||||||
unsigned i;
|
uint32_t i;
|
||||||
for (i = 0; i < response->num_top_entries; i++) {
|
for (i = 0; i < response->num_top_entries; i++) {
|
||||||
sboard.top_entries[i].username = response->top_entries[i].username;
|
sboard.top_entries[i].username = response->top_entries[i].username;
|
||||||
sboard.top_entries[i].rank = response->top_entries[i].rank;
|
sboard.top_entries[i].rank = response->top_entries[i].rank;
|
||||||
|
@ -3511,7 +3664,7 @@ static void rc_client_submit_leaderboard_entry_callback(const rc_api_server_resp
|
||||||
if (submit_lboard_entry_response.response.error_message && !rc_client_should_retry(server_response)) {
|
if (submit_lboard_entry_response.response.error_message && !rc_client_should_retry(server_response)) {
|
||||||
/* actual error from server */
|
/* actual error from server */
|
||||||
RC_CLIENT_LOG_ERR_FORMATTED(lboard_data->client, "Error submitting leaderboard entry %u: %s", lboard_data->id, error_message);
|
RC_CLIENT_LOG_ERR_FORMATTED(lboard_data->client, "Error submitting leaderboard entry %u: %s", lboard_data->id, error_message);
|
||||||
rc_client_raise_server_error_event(lboard_data->client, "submit_lboard_entry", submit_lboard_entry_response.response.error_message);
|
rc_client_raise_server_error_event(lboard_data->client, "submit_lboard_entry", lboard_data->id, result, submit_lboard_entry_response.response.error_message);
|
||||||
}
|
}
|
||||||
else if (lboard_data->retry_count++ == 0) {
|
else if (lboard_data->retry_count++ == 0) {
|
||||||
/* first retry is immediate */
|
/* first retry is immediate */
|
||||||
|
@ -3529,7 +3682,7 @@ static void rc_client_submit_leaderboard_entry_callback(const rc_api_server_resp
|
||||||
lboard_data->scheduled_callback_data = (rc_client_scheduled_callback_data_t*)calloc(1, sizeof(*lboard_data->scheduled_callback_data));
|
lboard_data->scheduled_callback_data = (rc_client_scheduled_callback_data_t*)calloc(1, sizeof(*lboard_data->scheduled_callback_data));
|
||||||
if (!lboard_data->scheduled_callback_data) {
|
if (!lboard_data->scheduled_callback_data) {
|
||||||
RC_CLIENT_LOG_ERR_FORMATTED(lboard_data->client, "Failed to allocate scheduled callback data for reattempt to submit entry for leaderboard %u", lboard_data->id);
|
RC_CLIENT_LOG_ERR_FORMATTED(lboard_data->client, "Failed to allocate scheduled callback data for reattempt to submit entry for leaderboard %u", lboard_data->id);
|
||||||
rc_client_raise_server_error_event(lboard_data->client, "submit_lboard_entry", rc_error_str(RC_OUT_OF_MEMORY));
|
rc_client_raise_server_error_event(lboard_data->client, "submit_lboard_entry", lboard_data->id, RC_OUT_OF_MEMORY, rc_error_str(RC_OUT_OF_MEMORY));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lboard_data->scheduled_callback_data->callback = rc_client_submit_leaderboard_entry_retry;
|
lboard_data->scheduled_callback_data->callback = rc_client_submit_leaderboard_entry_retry;
|
||||||
|
@ -3611,7 +3764,7 @@ static void rc_client_submit_leaderboard_entry(rc_client_t* client, rc_client_le
|
||||||
callback_data = (rc_client_submit_leaderboard_entry_callback_data_t*)calloc(1, sizeof(*callback_data));
|
callback_data = (rc_client_submit_leaderboard_entry_callback_data_t*)calloc(1, sizeof(*callback_data));
|
||||||
if (!callback_data) {
|
if (!callback_data) {
|
||||||
RC_CLIENT_LOG_ERR_FORMATTED(client, "Failed to allocate callback data for submitting entry for leaderboard %u", leaderboard->public_.id);
|
RC_CLIENT_LOG_ERR_FORMATTED(client, "Failed to allocate callback data for submitting entry for leaderboard %u", leaderboard->public_.id);
|
||||||
rc_client_raise_server_error_event(client, "submit_lboard_entry", rc_error_str(RC_OUT_OF_MEMORY));
|
rc_client_raise_server_error_event(client, "submit_lboard_entry", leaderboard->public_.id, RC_OUT_OF_MEMORY, rc_error_str(RC_OUT_OF_MEMORY));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
callback_data->client = client;
|
callback_data->client = client;
|
||||||
|
@ -3674,8 +3827,11 @@ static void rc_client_fetch_leaderboard_entries_callback(const rc_api_server_res
|
||||||
const char* error_message;
|
const char* error_message;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if (rc_client_async_handle_aborted(client, &lbinfo_callback_data->async_handle)) {
|
result = rc_client_end_async(client, &lbinfo_callback_data->async_handle);
|
||||||
RC_CLIENT_LOG_VERBOSE(client, "Fetch leaderbord entries aborted");
|
if (result) {
|
||||||
|
if (result != RC_CLIENT_ASYNC_DESTROYED) {
|
||||||
|
RC_CLIENT_LOG_VERBOSE(client, "Fetch leaderbord entries aborted");
|
||||||
|
}
|
||||||
free(lbinfo_callback_data);
|
free(lbinfo_callback_data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3690,7 +3846,7 @@ static void rc_client_fetch_leaderboard_entries_callback(const rc_api_server_res
|
||||||
rc_client_leaderboard_entry_list_t* list;
|
rc_client_leaderboard_entry_list_t* list;
|
||||||
const size_t list_size = sizeof(*list) + sizeof(rc_client_leaderboard_entry_t) * lbinfo_response.num_entries;
|
const size_t list_size = sizeof(*list) + sizeof(rc_client_leaderboard_entry_t) * lbinfo_response.num_entries;
|
||||||
size_t needed_size = list_size;
|
size_t needed_size = list_size;
|
||||||
unsigned i;
|
uint32_t i;
|
||||||
|
|
||||||
for (i = 0; i < lbinfo_response.num_entries; i++)
|
for (i = 0; i < lbinfo_response.num_entries; i++)
|
||||||
needed_size += strlen(lbinfo_response.entries[i].username) + 1;
|
needed_size += strlen(lbinfo_response.entries[i].username) + 1;
|
||||||
|
@ -3761,6 +3917,7 @@ static rc_client_async_handle_t* rc_client_begin_fetch_leaderboard_info(rc_clien
|
||||||
callback_data->callback_userdata = callback_userdata;
|
callback_data->callback_userdata = callback_userdata;
|
||||||
callback_data->leaderboard_id = lbinfo_request->leaderboard_id;
|
callback_data->leaderboard_id = lbinfo_request->leaderboard_id;
|
||||||
|
|
||||||
|
rc_client_begin_async(client, &callback_data->async_handle);
|
||||||
client->callbacks.server_call(&request, rc_client_fetch_leaderboard_entries_callback, callback_data, client);
|
client->callbacks.server_call(&request, rc_client_fetch_leaderboard_entries_callback, callback_data, client);
|
||||||
rc_api_destroy_request(&request);
|
rc_api_destroy_request(&request);
|
||||||
|
|
||||||
|
@ -3835,8 +3992,15 @@ static void rc_client_ping(rc_client_scheduled_callback_data_t* callback_data, r
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
rc_runtime_get_richpresence(&client->game->runtime, buffer, sizeof(buffer),
|
if (!client->callbacks.rich_presence_override ||
|
||||||
client->state.legacy_peek, client, NULL);
|
!client->callbacks.rich_presence_override(client, buffer, sizeof(buffer))) {
|
||||||
|
rc_mutex_lock(&client->state.mutex);
|
||||||
|
|
||||||
|
rc_runtime_get_richpresence(&client->game->runtime, buffer, sizeof(buffer),
|
||||||
|
client->state.legacy_peek, client, NULL);
|
||||||
|
|
||||||
|
rc_mutex_unlock(&client->state.mutex);
|
||||||
|
}
|
||||||
|
|
||||||
memset(&api_params, 0, sizeof(api_params));
|
memset(&api_params, 0, sizeof(api_params));
|
||||||
api_params.username = client->user.username;
|
api_params.username = client->user.username;
|
||||||
|
@ -3874,9 +4038,13 @@ size_t rc_client_get_rich_presence_message(rc_client_t* client, char buffer[], s
|
||||||
if (!client || !client->game || !buffer)
|
if (!client || !client->game || !buffer)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
rc_mutex_lock(&client->state.mutex);
|
||||||
|
|
||||||
result = rc_runtime_get_richpresence(&client->game->runtime, buffer, (unsigned)buffer_size,
|
result = rc_runtime_get_richpresence(&client->game->runtime, buffer, (unsigned)buffer_size,
|
||||||
client->state.legacy_peek, client, NULL);
|
client->state.legacy_peek, client, NULL);
|
||||||
|
|
||||||
|
rc_mutex_unlock(&client->state.mutex);
|
||||||
|
|
||||||
if (result == 0)
|
if (result == 0)
|
||||||
result = snprintf(buffer, buffer_size, "Playing %s", client->game->public_.title);
|
result = snprintf(buffer, buffer_size, "Playing %s", client->game->public_.title);
|
||||||
|
|
||||||
|
@ -3922,10 +4090,10 @@ static void rc_client_invalidate_processing_memref(rc_client_t* client)
|
||||||
client->state.processing_memref = NULL;
|
client->state.processing_memref = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned rc_client_peek_le(unsigned address, unsigned num_bytes, void* ud)
|
static uint32_t rc_client_peek_le(uint32_t address, uint32_t num_bytes, void* ud)
|
||||||
{
|
{
|
||||||
rc_client_t* client = (rc_client_t*)ud;
|
rc_client_t* client = (rc_client_t*)ud;
|
||||||
unsigned value = 0;
|
uint32_t value = 0;
|
||||||
uint32_t num_read = 0;
|
uint32_t num_read = 0;
|
||||||
|
|
||||||
/* if we know the address is out of range, and it's part of a pointer chain
|
/* if we know the address is out of range, and it's part of a pointer chain
|
||||||
|
@ -3945,7 +4113,7 @@ static unsigned rc_client_peek_le(unsigned address, unsigned num_bytes, void* ud
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned rc_client_peek(unsigned address, unsigned num_bytes, void* ud)
|
static uint32_t rc_client_peek(uint32_t address, uint32_t num_bytes, void* ud)
|
||||||
{
|
{
|
||||||
rc_client_t* client = (rc_client_t*)ud;
|
rc_client_t* client = (rc_client_t*)ud;
|
||||||
uint8_t buffer[4];
|
uint8_t buffer[4];
|
||||||
|
@ -4017,7 +4185,7 @@ int rc_client_is_processing_required(rc_client_t* client)
|
||||||
static void rc_client_update_memref_values(rc_client_t* client)
|
static void rc_client_update_memref_values(rc_client_t* client)
|
||||||
{
|
{
|
||||||
rc_memref_t* memref = client->game->runtime.memrefs;
|
rc_memref_t* memref = client->game->runtime.memrefs;
|
||||||
unsigned value;
|
uint32_t value;
|
||||||
int invalidated_memref = 0;
|
int invalidated_memref = 0;
|
||||||
|
|
||||||
for (; memref; memref = memref->next) {
|
for (; memref; memref = memref->next) {
|
||||||
|
@ -4051,7 +4219,7 @@ static void rc_client_do_frame_process_achievements(rc_client_t* client, rc_clie
|
||||||
for (; achievement < stop; ++achievement) {
|
for (; achievement < stop; ++achievement) {
|
||||||
rc_trigger_t* trigger = achievement->trigger;
|
rc_trigger_t* trigger = achievement->trigger;
|
||||||
int old_state, new_state;
|
int old_state, new_state;
|
||||||
unsigned old_measured_value;
|
uint32_t old_measured_value;
|
||||||
|
|
||||||
if (!trigger || achievement->public_.state != RC_CLIENT_ACHIEVEMENT_STATE_ACTIVE)
|
if (!trigger || achievement->public_.state != RC_CLIENT_ACHIEVEMENT_STATE_ACTIVE)
|
||||||
continue;
|
continue;
|
||||||
|
@ -4070,8 +4238,8 @@ static void rc_client_do_frame_process_achievements(rc_client_t* client, rc_clie
|
||||||
|
|
||||||
if (trigger->measured_as_percent) {
|
if (trigger->measured_as_percent) {
|
||||||
/* if reporting the measured value as a percentage, only show the popup if the percentage changes */
|
/* if reporting the measured value as a percentage, only show the popup if the percentage changes */
|
||||||
const unsigned old_percent = (unsigned)(((unsigned long long)old_measured_value * 100) / trigger->measured_target);
|
const uint32_t old_percent = (uint32_t)(((unsigned long long)old_measured_value * 100) / trigger->measured_target);
|
||||||
const unsigned new_percent = (unsigned)(((unsigned long long)trigger->measured_value * 100) / trigger->measured_target);
|
const uint32_t new_percent = (uint32_t)(((unsigned long long)trigger->measured_value * 100) / trigger->measured_target);
|
||||||
if (old_percent == new_percent)
|
if (old_percent == new_percent)
|
||||||
progress = -1.0;
|
progress = -1.0;
|
||||||
}
|
}
|
||||||
|
@ -4136,7 +4304,7 @@ static void rc_client_do_frame_update_progress_tracker(rc_client_t* client, rc_c
|
||||||
{
|
{
|
||||||
if (!game->progress_tracker.hide_callback) {
|
if (!game->progress_tracker.hide_callback) {
|
||||||
game->progress_tracker.hide_callback = (rc_client_scheduled_callback_data_t*)
|
game->progress_tracker.hide_callback = (rc_client_scheduled_callback_data_t*)
|
||||||
rc_buf_alloc(&game->buffer, sizeof(rc_client_scheduled_callback_data_t));
|
rc_buffer_alloc(&game->buffer, sizeof(rc_client_scheduled_callback_data_t));
|
||||||
memset(game->progress_tracker.hide_callback, 0, sizeof(rc_client_scheduled_callback_data_t));
|
memset(game->progress_tracker.hide_callback, 0, sizeof(rc_client_scheduled_callback_data_t));
|
||||||
game->progress_tracker.hide_callback->callback = rc_client_progress_tracker_timer_elapsed;
|
game->progress_tracker.hide_callback->callback = rc_client_progress_tracker_timer_elapsed;
|
||||||
}
|
}
|
|
@ -11,11 +11,16 @@ extern "C" {
|
||||||
#include "rc_runtime.h"
|
#include "rc_runtime.h"
|
||||||
#include "rc_runtime_types.h"
|
#include "rc_runtime_types.h"
|
||||||
|
|
||||||
|
/*****************************************************************************\
|
||||||
|
| Callbacks |
|
||||||
|
\*****************************************************************************/
|
||||||
|
|
||||||
struct rc_api_fetch_game_data_response_t;
|
struct rc_api_fetch_game_data_response_t;
|
||||||
typedef void (*rc_client_post_process_game_data_response_t)(const rc_api_server_response_t* server_response,
|
typedef void (*rc_client_post_process_game_data_response_t)(const rc_api_server_response_t* server_response,
|
||||||
struct rc_api_fetch_game_data_response_t* game_data_response, rc_client_t* client, void* userdata);
|
struct rc_api_fetch_game_data_response_t* game_data_response, rc_client_t* client, void* userdata);
|
||||||
typedef int (*rc_client_can_submit_achievement_unlock_t)(uint32_t achievement_id, rc_client_t* client);
|
typedef int (*rc_client_can_submit_achievement_unlock_t)(uint32_t achievement_id, rc_client_t* client);
|
||||||
typedef int (*rc_client_can_submit_leaderboard_entry_t)(uint32_t leaderboard_id, rc_client_t* client);
|
typedef int (*rc_client_can_submit_leaderboard_entry_t)(uint32_t leaderboard_id, rc_client_t* client);
|
||||||
|
typedef int (*rc_client_rich_presence_override_t)(rc_client_t* client, char buffer[], size_t buffersize);
|
||||||
|
|
||||||
typedef struct rc_client_callbacks_t {
|
typedef struct rc_client_callbacks_t {
|
||||||
rc_client_read_memory_func_t read_memory;
|
rc_client_read_memory_func_t read_memory;
|
||||||
|
@ -26,6 +31,7 @@ typedef struct rc_client_callbacks_t {
|
||||||
rc_client_post_process_game_data_response_t post_process_game_data_response;
|
rc_client_post_process_game_data_response_t post_process_game_data_response;
|
||||||
rc_client_can_submit_achievement_unlock_t can_submit_achievement_unlock;
|
rc_client_can_submit_achievement_unlock_t can_submit_achievement_unlock;
|
||||||
rc_client_can_submit_leaderboard_entry_t can_submit_leaderboard_entry;
|
rc_client_can_submit_leaderboard_entry_t can_submit_leaderboard_entry;
|
||||||
|
rc_client_rich_presence_override_t rich_presence_override;
|
||||||
|
|
||||||
void* client_data;
|
void* client_data;
|
||||||
} rc_client_callbacks_t;
|
} rc_client_callbacks_t;
|
||||||
|
@ -36,7 +42,7 @@ typedef void (*rc_client_scheduled_callback_t)(struct rc_client_scheduled_callba
|
||||||
typedef struct rc_client_scheduled_callback_data_t
|
typedef struct rc_client_scheduled_callback_data_t
|
||||||
{
|
{
|
||||||
rc_clock_t when;
|
rc_clock_t when;
|
||||||
unsigned related_id;
|
uint32_t related_id;
|
||||||
rc_client_scheduled_callback_t callback;
|
rc_client_scheduled_callback_t callback;
|
||||||
void* data;
|
void* data;
|
||||||
struct rc_client_scheduled_callback_data_t* next;
|
struct rc_client_scheduled_callback_data_t* next;
|
||||||
|
@ -44,6 +50,10 @@ typedef struct rc_client_scheduled_callback_data_t
|
||||||
|
|
||||||
void rc_client_schedule_callback(rc_client_t* client, rc_client_scheduled_callback_data_t* scheduled_callback);
|
void rc_client_schedule_callback(rc_client_t* client, rc_client_scheduled_callback_data_t* scheduled_callback);
|
||||||
|
|
||||||
|
/*****************************************************************************\
|
||||||
|
| Achievements |
|
||||||
|
\*****************************************************************************/
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
RC_CLIENT_ACHIEVEMENT_PENDING_EVENT_NONE = 0,
|
RC_CLIENT_ACHIEVEMENT_PENDING_EVENT_NONE = 0,
|
||||||
RC_CLIENT_ACHIEVEMENT_PENDING_EVENT_TRIGGERED = (1 << 1),
|
RC_CLIENT_ACHIEVEMENT_PENDING_EVENT_TRIGGERED = (1 << 1),
|
||||||
|
@ -83,6 +93,10 @@ typedef struct rc_client_progress_tracker_t {
|
||||||
uint8_t action;
|
uint8_t action;
|
||||||
} rc_client_progress_tracker_t;
|
} rc_client_progress_tracker_t;
|
||||||
|
|
||||||
|
/*****************************************************************************\
|
||||||
|
| Leaderboard Trackers |
|
||||||
|
\*****************************************************************************/
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
RC_CLIENT_LEADERBOARD_TRACKER_PENDING_EVENT_NONE = 0,
|
RC_CLIENT_LEADERBOARD_TRACKER_PENDING_EVENT_NONE = 0,
|
||||||
RC_CLIENT_LEADERBOARD_TRACKER_PENDING_EVENT_UPDATE = (1 << 1),
|
RC_CLIENT_LEADERBOARD_TRACKER_PENDING_EVENT_UPDATE = (1 << 1),
|
||||||
|
@ -93,7 +107,7 @@ enum {
|
||||||
typedef struct rc_client_leaderboard_tracker_info_t {
|
typedef struct rc_client_leaderboard_tracker_info_t {
|
||||||
rc_client_leaderboard_tracker_t public_;
|
rc_client_leaderboard_tracker_t public_;
|
||||||
struct rc_client_leaderboard_tracker_info_t* next;
|
struct rc_client_leaderboard_tracker_info_t* next;
|
||||||
int raw_value;
|
int32_t raw_value;
|
||||||
|
|
||||||
uint32_t value_djb2;
|
uint32_t value_djb2;
|
||||||
|
|
||||||
|
@ -103,6 +117,10 @@ typedef struct rc_client_leaderboard_tracker_info_t {
|
||||||
uint8_t value_from_hits;
|
uint8_t value_from_hits;
|
||||||
} rc_client_leaderboard_tracker_info_t;
|
} rc_client_leaderboard_tracker_info_t;
|
||||||
|
|
||||||
|
/*****************************************************************************\
|
||||||
|
| Leaderboards |
|
||||||
|
\*****************************************************************************/
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
RC_CLIENT_LEADERBOARD_PENDING_EVENT_NONE = 0,
|
RC_CLIENT_LEADERBOARD_PENDING_EVENT_NONE = 0,
|
||||||
RC_CLIENT_LEADERBOARD_PENDING_EVENT_STARTED = (1 << 1),
|
RC_CLIENT_LEADERBOARD_PENDING_EVENT_STARTED = (1 << 1),
|
||||||
|
@ -119,7 +137,7 @@ typedef struct rc_client_leaderboard_info_t {
|
||||||
rc_client_leaderboard_tracker_info_t* tracker;
|
rc_client_leaderboard_tracker_info_t* tracker;
|
||||||
|
|
||||||
uint32_t value_djb2;
|
uint32_t value_djb2;
|
||||||
int value;
|
int32_t value;
|
||||||
|
|
||||||
uint8_t format;
|
uint8_t format;
|
||||||
uint8_t pending_events;
|
uint8_t pending_events;
|
||||||
|
@ -127,19 +145,18 @@ typedef struct rc_client_leaderboard_info_t {
|
||||||
uint8_t hidden;
|
uint8_t hidden;
|
||||||
} rc_client_leaderboard_info_t;
|
} rc_client_leaderboard_info_t;
|
||||||
|
|
||||||
|
uint8_t rc_client_map_leaderboard_format(int format);
|
||||||
|
|
||||||
|
/*****************************************************************************\
|
||||||
|
| Subsets |
|
||||||
|
\*****************************************************************************/
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
RC_CLIENT_SUBSET_PENDING_EVENT_NONE = 0,
|
RC_CLIENT_SUBSET_PENDING_EVENT_NONE = 0,
|
||||||
RC_CLIENT_SUBSET_PENDING_EVENT_ACHIEVEMENT = (1 << 1),
|
RC_CLIENT_SUBSET_PENDING_EVENT_ACHIEVEMENT = (1 << 1),
|
||||||
RC_CLIENT_SUBSET_PENDING_EVENT_LEADERBOARD = (1 << 2)
|
RC_CLIENT_SUBSET_PENDING_EVENT_LEADERBOARD = (1 << 2)
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
|
||||||
RC_CLIENT_GAME_PENDING_EVENT_NONE = 0,
|
|
||||||
RC_CLIENT_GAME_PENDING_EVENT_LEADERBOARD_TRACKER = (1 << 1),
|
|
||||||
RC_CLIENT_GAME_PENDING_EVENT_UPDATE_ACTIVE_ACHIEVEMENTS = (1 << 2),
|
|
||||||
RC_CLIENT_GAME_PENDING_EVENT_PROGRESS_TRACKER = (1 << 3)
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct rc_client_subset_info_t {
|
typedef struct rc_client_subset_info_t {
|
||||||
rc_client_subset_t public_;
|
rc_client_subset_t public_;
|
||||||
|
|
||||||
|
@ -160,6 +177,12 @@ typedef struct rc_client_subset_info_t {
|
||||||
uint8_t pending_events;
|
uint8_t pending_events;
|
||||||
} rc_client_subset_info_t;
|
} rc_client_subset_info_t;
|
||||||
|
|
||||||
|
void rc_client_begin_load_subset(rc_client_t* client, uint32_t subset_id, rc_client_callback_t callback, void* callback_userdata);
|
||||||
|
|
||||||
|
/*****************************************************************************\
|
||||||
|
| Game |
|
||||||
|
\*****************************************************************************/
|
||||||
|
|
||||||
typedef struct rc_client_game_hash_t {
|
typedef struct rc_client_game_hash_t {
|
||||||
char hash[33];
|
char hash[33];
|
||||||
uint32_t game_id;
|
uint32_t game_id;
|
||||||
|
@ -174,6 +197,13 @@ typedef struct rc_client_media_hash_t {
|
||||||
uint32_t path_djb2;
|
uint32_t path_djb2;
|
||||||
} rc_client_media_hash_t;
|
} rc_client_media_hash_t;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
RC_CLIENT_GAME_PENDING_EVENT_NONE = 0,
|
||||||
|
RC_CLIENT_GAME_PENDING_EVENT_LEADERBOARD_TRACKER = (1 << 1),
|
||||||
|
RC_CLIENT_GAME_PENDING_EVENT_UPDATE_ACTIVE_ACHIEVEMENTS = (1 << 2),
|
||||||
|
RC_CLIENT_GAME_PENDING_EVENT_PROGRESS_TRACKER = (1 << 3)
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct rc_client_game_info_t {
|
typedef struct rc_client_game_info_t {
|
||||||
rc_client_game_t public_;
|
rc_client_game_t public_;
|
||||||
rc_client_leaderboard_tracker_info_t* leaderboard_trackers;
|
rc_client_leaderboard_tracker_info_t* leaderboard_trackers;
|
||||||
|
@ -190,17 +220,24 @@ typedef struct rc_client_game_info_t {
|
||||||
uint8_t waiting_for_reset;
|
uint8_t waiting_for_reset;
|
||||||
uint8_t pending_events;
|
uint8_t pending_events;
|
||||||
|
|
||||||
rc_api_buffer_t buffer;
|
rc_buffer_t buffer;
|
||||||
} rc_client_game_info_t;
|
} rc_client_game_info_t;
|
||||||
|
|
||||||
|
void rc_client_update_active_achievements(rc_client_game_info_t* game);
|
||||||
|
void rc_client_update_active_leaderboards(rc_client_game_info_t* game);
|
||||||
|
|
||||||
|
/*****************************************************************************\
|
||||||
|
| Client |
|
||||||
|
\*****************************************************************************/
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
RC_CLIENT_LOAD_STATE_NONE,
|
RC_CLIENT_LOAD_STATE_NONE,
|
||||||
RC_CLIENT_LOAD_STATE_IDENTIFYING_GAME,
|
RC_CLIENT_LOAD_STATE_IDENTIFYING_GAME,
|
||||||
RC_CLIENT_LOAD_STATE_AWAIT_LOGIN,
|
RC_CLIENT_LOAD_STATE_AWAIT_LOGIN,
|
||||||
RC_CLIENT_LOAD_STATE_FETCHING_GAME_DATA,
|
RC_CLIENT_LOAD_STATE_FETCHING_GAME_DATA,
|
||||||
RC_CLIENT_LOAD_STATE_STARTING_SESSION,
|
RC_CLIENT_LOAD_STATE_STARTING_SESSION,
|
||||||
RC_CLIENT_LOAD_STATE_DONE,
|
RC_CLIENT_LOAD_STATE_DONE,
|
||||||
RC_CLIENT_LOAD_STATE_UNKNOWN_GAME
|
RC_CLIENT_LOAD_STATE_UNKNOWN_GAME
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -232,7 +269,7 @@ struct rc_client_load_state_t;
|
||||||
|
|
||||||
typedef struct rc_client_state_t {
|
typedef struct rc_client_state_t {
|
||||||
rc_mutex_t mutex;
|
rc_mutex_t mutex;
|
||||||
rc_api_buffer_t buffer;
|
rc_buffer_t buffer;
|
||||||
|
|
||||||
rc_client_scheduled_callback_data_t* scheduled_callbacks;
|
rc_client_scheduled_callback_data_t* scheduled_callbacks;
|
||||||
|
|
||||||
|
@ -245,6 +282,7 @@ typedef struct rc_client_state_t {
|
||||||
uint8_t disconnect;
|
uint8_t disconnect;
|
||||||
|
|
||||||
struct rc_client_load_state_t* load;
|
struct rc_client_load_state_t* load;
|
||||||
|
struct rc_client_async_handle_t* async_handles[4];
|
||||||
rc_memref_t* processing_memref;
|
rc_memref_t* processing_memref;
|
||||||
|
|
||||||
rc_peek_t legacy_peek;
|
rc_peek_t legacy_peek;
|
||||||
|
@ -261,6 +299,10 @@ struct rc_client_t {
|
||||||
rc_client_state_t state;
|
rc_client_state_t state;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*****************************************************************************\
|
||||||
|
| Helpers |
|
||||||
|
\*****************************************************************************/
|
||||||
|
|
||||||
#ifdef RC_NO_VARIADIC_MACROS
|
#ifdef RC_NO_VARIADIC_MACROS
|
||||||
void RC_CLIENT_LOG_ERR_FORMATTED(const rc_client_t* client, const char* format, ...);
|
void RC_CLIENT_LOG_ERR_FORMATTED(const rc_client_t* client, const char* format, ...);
|
||||||
void RC_CLIENT_LOG_WARN_FORMATTED(const rc_client_t* client, const char* format, ...);
|
void RC_CLIENT_LOG_WARN_FORMATTED(const rc_client_t* client, const char* format, ...);
|
||||||
|
@ -281,7 +323,7 @@ void rc_client_log_message(const rc_client_t* client, const char* message);
|
||||||
#define RC_CLIENT_LOG_VERBOSE(client, message) { if (client->state.log_level >= RC_CLIENT_LOG_LEVEL_VERBOSE) rc_client_log_message(client, message); }
|
#define RC_CLIENT_LOG_VERBOSE(client, message) { if (client->state.log_level >= RC_CLIENT_LOG_LEVEL_VERBOSE) rc_client_log_message(client, message); }
|
||||||
|
|
||||||
/* internals pulled from runtime.c */
|
/* internals pulled from runtime.c */
|
||||||
void rc_runtime_checksum(const char* memaddr, unsigned char* md5);
|
void rc_runtime_checksum(const char* memaddr, uint8_t* md5);
|
||||||
int rc_trigger_contains_memref(const rc_trigger_t* trigger, const rc_memref_t* memref);
|
int rc_trigger_contains_memref(const rc_trigger_t* trigger, const rc_memref_t* memref);
|
||||||
int rc_value_contains_memref(const rc_value_t* value, const rc_memref_t* memref);
|
int rc_value_contains_memref(const rc_value_t* value, const rc_memref_t* memref);
|
||||||
/* end runtime.c internals */
|
/* end runtime.c internals */
|
||||||
|
@ -299,7 +341,7 @@ enum {
|
||||||
|
|
||||||
void rc_client_set_legacy_peek(rc_client_t* client, int method);
|
void rc_client_set_legacy_peek(rc_client_t* client, int method);
|
||||||
|
|
||||||
void rc_client_begin_load_subset(rc_client_t* client, uint32_t subset_id, rc_client_callback_t callback, void* callback_userdata);
|
void rc_client_release_leaderboard_tracker(rc_client_game_info_t* game, rc_client_leaderboard_info_t* leaderboard);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
|
@ -255,7 +255,7 @@ const rc_disallowed_setting_t* rc_libretro_get_disallowed_settings(const char* l
|
||||||
typedef struct rc_disallowed_core_systems_t
|
typedef struct rc_disallowed_core_systems_t
|
||||||
{
|
{
|
||||||
const char* library_name;
|
const char* library_name;
|
||||||
const int disallowed_consoles[4];
|
const uint32_t disallowed_consoles[4];
|
||||||
} rc_disallowed_core_systems_t;
|
} rc_disallowed_core_systems_t;
|
||||||
|
|
||||||
static const rc_disallowed_core_systems_t rc_disallowed_core_systems[] = {
|
static const rc_disallowed_core_systems_t rc_disallowed_core_systems[] = {
|
||||||
|
@ -264,7 +264,7 @@ static const rc_disallowed_core_systems_t rc_disallowed_core_systems[] = {
|
||||||
{ NULL, { 0 } }
|
{ NULL, { 0 } }
|
||||||
};
|
};
|
||||||
|
|
||||||
int rc_libretro_is_system_allowed(const char* library_name, int console_id) {
|
int rc_libretro_is_system_allowed(const char* library_name, uint32_t console_id) {
|
||||||
const rc_disallowed_core_systems_t* core_filter = rc_disallowed_core_systems;
|
const rc_disallowed_core_systems_t* core_filter = rc_disallowed_core_systems;
|
||||||
size_t library_name_length;
|
size_t library_name_length;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
@ -288,8 +288,8 @@ int rc_libretro_is_system_allowed(const char* library_name, int console_id) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char* rc_libretro_memory_find_avail(const rc_libretro_memory_regions_t* regions, unsigned address, unsigned* avail) {
|
uint8_t* rc_libretro_memory_find_avail(const rc_libretro_memory_regions_t* regions, uint32_t address, uint32_t* avail) {
|
||||||
unsigned i;
|
uint32_t i;
|
||||||
|
|
||||||
for (i = 0; i < regions->count; ++i) {
|
for (i = 0; i < regions->count; ++i) {
|
||||||
const size_t size = regions->size[i];
|
const size_t size = regions->size[i];
|
||||||
|
@ -298,12 +298,12 @@ unsigned char* rc_libretro_memory_find_avail(const rc_libretro_memory_regions_t*
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (avail)
|
if (avail)
|
||||||
*avail = (unsigned)(size - address);
|
*avail = (uint32_t)(size - address);
|
||||||
|
|
||||||
return ®ions->data[i][address];
|
return ®ions->data[i][address];
|
||||||
}
|
}
|
||||||
|
|
||||||
address -= (unsigned)size;
|
address -= (uint32_t)size;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (avail)
|
if (avail)
|
||||||
|
@ -312,13 +312,13 @@ unsigned char* rc_libretro_memory_find_avail(const rc_libretro_memory_regions_t*
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char* rc_libretro_memory_find(const rc_libretro_memory_regions_t* regions, unsigned address) {
|
uint8_t* rc_libretro_memory_find(const rc_libretro_memory_regions_t* regions, uint32_t address) {
|
||||||
return rc_libretro_memory_find_avail(regions, address, NULL);
|
return rc_libretro_memory_find_avail(regions, address, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t rc_libretro_memory_read(const rc_libretro_memory_regions_t* regions, unsigned address,
|
uint32_t rc_libretro_memory_read(const rc_libretro_memory_regions_t* regions, uint32_t address,
|
||||||
uint8_t* buffer, uint32_t num_bytes) {
|
uint8_t* buffer, uint32_t num_bytes) {
|
||||||
unsigned i;
|
uint32_t i;
|
||||||
uint32_t avail;
|
uint32_t avail;
|
||||||
|
|
||||||
for (i = 0; i < regions->count; ++i) {
|
for (i = 0; i < regions->count; ++i) {
|
||||||
|
@ -367,7 +367,7 @@ static const char* rc_memory_type_str(int type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rc_libretro_memory_register_region(rc_libretro_memory_regions_t* regions, int type,
|
static void rc_libretro_memory_register_region(rc_libretro_memory_regions_t* regions, int type,
|
||||||
unsigned char* data, size_t size, const char* description) {
|
uint8_t* data, size_t size, const char* description) {
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -419,7 +419,7 @@ static void rc_libretro_memory_init_without_regions(rc_libretro_memory_regions_t
|
||||||
rc_libretro_memory_register_region(regions, RC_MEMORY_TYPE_SAVE_RAM, info.data, info.size, description);
|
rc_libretro_memory_register_region(regions, RC_MEMORY_TYPE_SAVE_RAM, info.data, info.size, description);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct retro_memory_descriptor* rc_libretro_memory_get_descriptor(const struct retro_memory_map* mmap, unsigned real_address, size_t* offset)
|
static const struct retro_memory_descriptor* rc_libretro_memory_get_descriptor(const struct retro_memory_map* mmap, uint32_t real_address, size_t* offset)
|
||||||
{
|
{
|
||||||
const struct retro_memory_descriptor* desc = mmap->descriptors;
|
const struct retro_memory_descriptor* desc = mmap->descriptors;
|
||||||
const struct retro_memory_descriptor* end = desc + mmap->num_descriptors;
|
const struct retro_memory_descriptor* end = desc + mmap->num_descriptors;
|
||||||
|
@ -437,14 +437,14 @@ static const struct retro_memory_descriptor* rc_libretro_memory_get_descriptor(c
|
||||||
/* address is in the block if (addr & select) == (start & select) */
|
/* address is in the block if (addr & select) == (start & select) */
|
||||||
if (((desc->start ^ real_address) & desc->select) == 0) {
|
if (((desc->start ^ real_address) & desc->select) == 0) {
|
||||||
/* get the relative offset of the address from the start of the memory block */
|
/* get the relative offset of the address from the start of the memory block */
|
||||||
unsigned reduced_address = real_address - (unsigned)desc->start;
|
uint32_t reduced_address = real_address - (unsigned)desc->start;
|
||||||
|
|
||||||
/* remove any bits from the reduced_address that correspond to the bits in the disconnect
|
/* remove any bits from the reduced_address that correspond to the bits in the disconnect
|
||||||
* mask and collapse the remaining bits. this code was copied from the mmap_reduce function
|
* mask and collapse the remaining bits. this code was copied from the mmap_reduce function
|
||||||
* in RetroArch. i'm not exactly sure how it works, but it does. */
|
* in RetroArch. i'm not exactly sure how it works, but it does. */
|
||||||
unsigned disconnect_mask = (unsigned)desc->disconnect;
|
uint32_t disconnect_mask = (unsigned)desc->disconnect;
|
||||||
while (disconnect_mask) {
|
while (disconnect_mask) {
|
||||||
const unsigned tmp = (disconnect_mask - 1) & ~disconnect_mask;
|
const uint32_t tmp = (disconnect_mask - 1) & ~disconnect_mask;
|
||||||
reduced_address = (reduced_address & tmp) | ((reduced_address >> 1) & ~tmp);
|
reduced_address = (reduced_address & tmp) | ((reduced_address >> 1) & ~tmp);
|
||||||
disconnect_mask = (disconnect_mask & (disconnect_mask - 1)) >> 1;
|
disconnect_mask = (disconnect_mask & (disconnect_mask - 1)) >> 1;
|
||||||
}
|
}
|
||||||
|
@ -466,24 +466,24 @@ static const struct retro_memory_descriptor* rc_libretro_memory_get_descriptor(c
|
||||||
static void rc_libretro_memory_init_from_memory_map(rc_libretro_memory_regions_t* regions, const struct retro_memory_map* mmap,
|
static void rc_libretro_memory_init_from_memory_map(rc_libretro_memory_regions_t* regions, const struct retro_memory_map* mmap,
|
||||||
const rc_memory_regions_t* console_regions) {
|
const rc_memory_regions_t* console_regions) {
|
||||||
char description[64];
|
char description[64];
|
||||||
unsigned i;
|
uint32_t i;
|
||||||
unsigned char* region_start;
|
uint8_t* region_start;
|
||||||
unsigned char* desc_start;
|
uint8_t* desc_start;
|
||||||
size_t desc_size;
|
size_t desc_size;
|
||||||
size_t offset;
|
size_t offset;
|
||||||
|
|
||||||
for (i = 0; i < console_regions->num_regions; ++i) {
|
for (i = 0; i < console_regions->num_regions; ++i) {
|
||||||
const rc_memory_region_t* console_region = &console_regions->region[i];
|
const rc_memory_region_t* console_region = &console_regions->region[i];
|
||||||
size_t console_region_size = console_region->end_address - console_region->start_address + 1;
|
size_t console_region_size = console_region->end_address - console_region->start_address + 1;
|
||||||
unsigned real_address = console_region->real_address;
|
uint32_t real_address = console_region->real_address;
|
||||||
unsigned disconnect_size = 0;
|
uint32_t disconnect_size = 0;
|
||||||
|
|
||||||
while (console_region_size > 0) {
|
while (console_region_size > 0) {
|
||||||
const struct retro_memory_descriptor* desc = rc_libretro_memory_get_descriptor(mmap, real_address, &offset);
|
const struct retro_memory_descriptor* desc = rc_libretro_memory_get_descriptor(mmap, real_address, &offset);
|
||||||
if (!desc) {
|
if (!desc) {
|
||||||
if (rc_libretro_verbose_message_callback && console_region->type != RC_MEMORY_TYPE_UNUSED) {
|
if (rc_libretro_verbose_message_callback && console_region->type != RC_MEMORY_TYPE_UNUSED) {
|
||||||
snprintf(description, sizeof(description), "Could not map region starting at $%06X",
|
snprintf(description, sizeof(description), "Could not map region starting at $%06X",
|
||||||
real_address - console_region->real_address + console_region->start_address);
|
(unsigned)(real_address - console_region->real_address + console_region->start_address));
|
||||||
rc_libretro_verbose(description);
|
rc_libretro_verbose(description);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -523,7 +523,7 @@ static void rc_libretro_memory_init_from_memory_map(rc_libretro_memory_regions_t
|
||||||
if (desc_size == 0) {
|
if (desc_size == 0) {
|
||||||
if (rc_libretro_verbose_message_callback && console_region->type != RC_MEMORY_TYPE_UNUSED) {
|
if (rc_libretro_verbose_message_callback && console_region->type != RC_MEMORY_TYPE_UNUSED) {
|
||||||
snprintf(description, sizeof(description), "Could not map region starting at $%06X",
|
snprintf(description, sizeof(description), "Could not map region starting at $%06X",
|
||||||
real_address - console_region->real_address + console_region->start_address);
|
(unsigned)(real_address - console_region->real_address + console_region->start_address));
|
||||||
rc_libretro_verbose(description);
|
rc_libretro_verbose(description);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -544,7 +544,7 @@ static void rc_libretro_memory_init_from_memory_map(rc_libretro_memory_regions_t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned rc_libretro_memory_console_region_to_ram_type(int region_type) {
|
static uint32_t rc_libretro_memory_console_region_to_ram_type(uint8_t region_type) {
|
||||||
switch (region_type)
|
switch (region_type)
|
||||||
{
|
{
|
||||||
case RC_MEMORY_TYPE_SAVE_RAM:
|
case RC_MEMORY_TYPE_SAVE_RAM:
|
||||||
|
@ -561,15 +561,15 @@ static unsigned rc_libretro_memory_console_region_to_ram_type(int region_type) {
|
||||||
static void rc_libretro_memory_init_from_unmapped_memory(rc_libretro_memory_regions_t* regions,
|
static void rc_libretro_memory_init_from_unmapped_memory(rc_libretro_memory_regions_t* regions,
|
||||||
rc_libretro_get_core_memory_info_func get_core_memory_info, const rc_memory_regions_t* console_regions) {
|
rc_libretro_get_core_memory_info_func get_core_memory_info, const rc_memory_regions_t* console_regions) {
|
||||||
char description[64];
|
char description[64];
|
||||||
unsigned i, j;
|
uint32_t i, j;
|
||||||
rc_libretro_core_memory_info_t info;
|
rc_libretro_core_memory_info_t info;
|
||||||
size_t offset;
|
size_t offset;
|
||||||
|
|
||||||
for (i = 0; i < console_regions->num_regions; ++i) {
|
for (i = 0; i < console_regions->num_regions; ++i) {
|
||||||
const rc_memory_region_t* console_region = &console_regions->region[i];
|
const rc_memory_region_t* console_region = &console_regions->region[i];
|
||||||
const size_t console_region_size = console_region->end_address - console_region->start_address + 1;
|
const size_t console_region_size = console_region->end_address - console_region->start_address + 1;
|
||||||
const unsigned type = rc_libretro_memory_console_region_to_ram_type(console_region->type);
|
const uint32_t type = rc_libretro_memory_console_region_to_ram_type(console_region->type);
|
||||||
unsigned base_address = 0;
|
uint32_t base_address = 0;
|
||||||
|
|
||||||
for (j = 0; j <= i; ++j) {
|
for (j = 0; j <= i; ++j) {
|
||||||
const rc_memory_region_t* console_region2 = &console_regions->region[j];
|
const rc_memory_region_t* console_region2 = &console_regions->region[j];
|
||||||
|
@ -595,7 +595,7 @@ static void rc_libretro_memory_init_from_unmapped_memory(rc_libretro_memory_regi
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (rc_libretro_verbose_message_callback && console_region->type != RC_MEMORY_TYPE_UNUSED) {
|
if (rc_libretro_verbose_message_callback && console_region->type != RC_MEMORY_TYPE_UNUSED) {
|
||||||
snprintf(description, sizeof(description), "Could not map region starting at $%06X", console_region->start_address);
|
snprintf(description, sizeof(description), "Could not map region starting at $%06X", (unsigned)console_region->start_address);
|
||||||
rc_libretro_verbose(description);
|
rc_libretro_verbose(description);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -620,7 +620,7 @@ int rc_libretro_memory_init(rc_libretro_memory_regions_t* regions, const struct
|
||||||
const rc_memory_regions_t* console_regions = rc_console_memory_regions(console_id);
|
const rc_memory_regions_t* console_regions = rc_console_memory_regions(console_id);
|
||||||
rc_libretro_memory_regions_t new_regions;
|
rc_libretro_memory_regions_t new_regions;
|
||||||
int has_valid_region = 0;
|
int has_valid_region = 0;
|
||||||
unsigned i;
|
uint32_t i;
|
||||||
|
|
||||||
if (!regions)
|
if (!regions)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -676,46 +676,49 @@ void rc_libretro_hash_set_init(struct rc_libretro_hash_set_t* hash_set,
|
||||||
rc_file_seek(file_handle, 0, SEEK_SET);
|
rc_file_seek(file_handle, 0, SEEK_SET);
|
||||||
|
|
||||||
m3u_contents = (char*)malloc((size_t)file_len + 1);
|
m3u_contents = (char*)malloc((size_t)file_len + 1);
|
||||||
rc_file_read(file_handle, m3u_contents, (int)file_len);
|
if (m3u_contents)
|
||||||
m3u_contents[file_len] = '\0';
|
|
||||||
|
|
||||||
rc_file_close(file_handle);
|
|
||||||
|
|
||||||
ptr = m3u_contents;
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
/* ignore whitespace */
|
rc_file_read(file_handle, m3u_contents, (int)file_len);
|
||||||
while (isspace((int)*ptr))
|
m3u_contents[file_len] = '\0';
|
||||||
++ptr;
|
|
||||||
|
|
||||||
if (*ptr == '#')
|
rc_file_close(file_handle);
|
||||||
|
|
||||||
|
ptr = m3u_contents;
|
||||||
|
do
|
||||||
{
|
{
|
||||||
/* ignore comment unless it's the special SAVEDISK extension */
|
/* ignore whitespace */
|
||||||
if (memcmp(ptr, "#SAVEDISK:", 10) == 0)
|
while (isspace((int)*ptr))
|
||||||
|
++ptr;
|
||||||
|
|
||||||
|
if (*ptr == '#')
|
||||||
{
|
{
|
||||||
/* get the path to the save disk from the frontend, assign it a bogus hash so
|
/* ignore comment unless it's the special SAVEDISK extension */
|
||||||
* it doesn't get hashed later */
|
if (memcmp(ptr, "#SAVEDISK:", 10) == 0)
|
||||||
if (get_image_path(index, image_path, sizeof(image_path)))
|
|
||||||
{
|
{
|
||||||
const char save_disk_hash[33] = "[SAVE DISK]";
|
/* get the path to the save disk from the frontend, assign it a bogus hash so
|
||||||
rc_libretro_hash_set_add(hash_set, image_path, -1, save_disk_hash);
|
* it doesn't get hashed later */
|
||||||
++index;
|
if (get_image_path(index, image_path, sizeof(image_path)))
|
||||||
|
{
|
||||||
|
const char save_disk_hash[33] = "[SAVE DISK]";
|
||||||
|
rc_libretro_hash_set_add(hash_set, image_path, -1, save_disk_hash);
|
||||||
|
++index;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
else
|
{
|
||||||
{
|
/* non-empty line, tally a file */
|
||||||
/* non-empty line, tally a file */
|
++index;
|
||||||
++index;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* find the end of the line */
|
/* find the end of the line */
|
||||||
while (*ptr && *ptr != '\n')
|
while (*ptr && *ptr != '\n')
|
||||||
++ptr;
|
++ptr;
|
||||||
|
|
||||||
} while (*ptr);
|
} while (*ptr);
|
||||||
|
|
||||||
free(m3u_contents);
|
free(m3u_contents);
|
||||||
|
}
|
||||||
|
|
||||||
if (hash_set->entries_count > 0)
|
if (hash_set->entries_count > 0)
|
||||||
{
|
{
|
||||||
|
@ -732,9 +735,9 @@ void rc_libretro_hash_set_destroy(struct rc_libretro_hash_set_t* hash_set) {
|
||||||
memset(hash_set, 0, sizeof(*hash_set));
|
memset(hash_set, 0, sizeof(*hash_set));
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned rc_libretro_djb2(const char* input)
|
static uint32_t rc_libretro_djb2(const char* input)
|
||||||
{
|
{
|
||||||
unsigned result = 5381;
|
uint32_t result = 5381;
|
||||||
char c;
|
char c;
|
||||||
|
|
||||||
while ((c = *input++) != '\0')
|
while ((c = *input++) != '\0')
|
||||||
|
@ -744,8 +747,8 @@ static unsigned rc_libretro_djb2(const char* input)
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_libretro_hash_set_add(struct rc_libretro_hash_set_t* hash_set,
|
void rc_libretro_hash_set_add(struct rc_libretro_hash_set_t* hash_set,
|
||||||
const char* path, int game_id, const char hash[33]) {
|
const char* path, uint32_t game_id, const char hash[33]) {
|
||||||
const unsigned path_djb2 = (path != NULL) ? rc_libretro_djb2(path) : 0;
|
const uint32_t path_djb2 = (path != NULL) ? rc_libretro_djb2(path) : 0;
|
||||||
struct rc_libretro_hash_entry_t* entry = NULL;
|
struct rc_libretro_hash_entry_t* entry = NULL;
|
||||||
struct rc_libretro_hash_entry_t* scan;
|
struct rc_libretro_hash_entry_t* scan;
|
||||||
struct rc_libretro_hash_entry_t* stop = hash_set->entries + hash_set->entries_count;;
|
struct rc_libretro_hash_entry_t* stop = hash_set->entries + hash_set->entries_count;;
|
||||||
|
@ -790,7 +793,7 @@ void rc_libretro_hash_set_add(struct rc_libretro_hash_set_t* hash_set,
|
||||||
|
|
||||||
const char* rc_libretro_hash_set_get_hash(const struct rc_libretro_hash_set_t* hash_set, const char* path)
|
const char* rc_libretro_hash_set_get_hash(const struct rc_libretro_hash_set_t* hash_set, const char* path)
|
||||||
{
|
{
|
||||||
const unsigned path_djb2 = rc_libretro_djb2(path);
|
const uint32_t path_djb2 = rc_libretro_djb2(path);
|
||||||
struct rc_libretro_hash_entry_t* scan = hash_set->entries;
|
struct rc_libretro_hash_entry_t* scan = hash_set->entries;
|
||||||
struct rc_libretro_hash_entry_t* stop = scan + hash_set->entries_count;
|
struct rc_libretro_hash_entry_t* stop = scan + hash_set->entries_count;
|
||||||
for (; scan < stop; ++scan)
|
for (; scan < stop; ++scan)
|
|
@ -1,13 +1,16 @@
|
||||||
#ifndef RC_LIBRETRO_H
|
#ifndef RC_LIBRETRO_H
|
||||||
#define RC_LIBRETRO_H
|
#define RC_LIBRETRO_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/* this file comes from the libretro repository, which is not an explicit submodule.
|
/* this file comes from the libretro repository, which is not an explicit submodule.
|
||||||
* the integration must set up paths appropriately to find it. */
|
* the integration must set up paths appropriately to find it. */
|
||||||
#include <libretro.h>
|
#include <libretro.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#include <stddef.h>
|
||||||
extern "C" {
|
#include <stdint.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
/*****************************************************************************\
|
/*****************************************************************************\
|
||||||
| Disallowed Settings |
|
| Disallowed Settings |
|
||||||
|
@ -21,7 +24,7 @@ typedef struct rc_disallowed_setting_t
|
||||||
|
|
||||||
const rc_disallowed_setting_t* rc_libretro_get_disallowed_settings(const char* library_name);
|
const rc_disallowed_setting_t* rc_libretro_get_disallowed_settings(const char* library_name);
|
||||||
int rc_libretro_is_setting_allowed(const rc_disallowed_setting_t* disallowed_settings, const char* setting, const char* value);
|
int rc_libretro_is_setting_allowed(const rc_disallowed_setting_t* disallowed_settings, const char* setting, const char* value);
|
||||||
int rc_libretro_is_system_allowed(const char* library_name, int console_id);
|
int rc_libretro_is_system_allowed(const char* library_name, uint32_t console_id);
|
||||||
|
|
||||||
/*****************************************************************************\
|
/*****************************************************************************\
|
||||||
| Memory Mapping |
|
| Memory Mapping |
|
||||||
|
@ -34,27 +37,27 @@ void rc_libretro_init_verbose_message_callback(rc_libretro_message_callback call
|
||||||
#define RC_LIBRETRO_MAX_MEMORY_REGIONS 32
|
#define RC_LIBRETRO_MAX_MEMORY_REGIONS 32
|
||||||
typedef struct rc_libretro_memory_regions_t
|
typedef struct rc_libretro_memory_regions_t
|
||||||
{
|
{
|
||||||
unsigned char* data[RC_LIBRETRO_MAX_MEMORY_REGIONS];
|
uint8_t* data[RC_LIBRETRO_MAX_MEMORY_REGIONS];
|
||||||
size_t size[RC_LIBRETRO_MAX_MEMORY_REGIONS];
|
size_t size[RC_LIBRETRO_MAX_MEMORY_REGIONS];
|
||||||
size_t total_size;
|
size_t total_size;
|
||||||
unsigned count;
|
uint32_t count;
|
||||||
} rc_libretro_memory_regions_t;
|
} rc_libretro_memory_regions_t;
|
||||||
|
|
||||||
typedef struct rc_libretro_core_memory_info_t
|
typedef struct rc_libretro_core_memory_info_t
|
||||||
{
|
{
|
||||||
unsigned char* data;
|
uint8_t* data;
|
||||||
size_t size;
|
size_t size;
|
||||||
} rc_libretro_core_memory_info_t;
|
} rc_libretro_core_memory_info_t;
|
||||||
|
|
||||||
typedef void (*rc_libretro_get_core_memory_info_func)(unsigned id, rc_libretro_core_memory_info_t* info);
|
typedef void (*rc_libretro_get_core_memory_info_func)(uint32_t id, rc_libretro_core_memory_info_t* info);
|
||||||
|
|
||||||
int rc_libretro_memory_init(rc_libretro_memory_regions_t* regions, const struct retro_memory_map* mmap,
|
int rc_libretro_memory_init(rc_libretro_memory_regions_t* regions, const struct retro_memory_map* mmap,
|
||||||
rc_libretro_get_core_memory_info_func get_core_memory_info, int console_id);
|
rc_libretro_get_core_memory_info_func get_core_memory_info, int console_id);
|
||||||
void rc_libretro_memory_destroy(rc_libretro_memory_regions_t* regions);
|
void rc_libretro_memory_destroy(rc_libretro_memory_regions_t* regions);
|
||||||
|
|
||||||
unsigned char* rc_libretro_memory_find(const rc_libretro_memory_regions_t* regions, unsigned address);
|
uint8_t* rc_libretro_memory_find(const rc_libretro_memory_regions_t* regions, uint32_t address);
|
||||||
unsigned char* rc_libretro_memory_find_avail(const rc_libretro_memory_regions_t* regions, unsigned address, unsigned* avail);
|
uint8_t* rc_libretro_memory_find_avail(const rc_libretro_memory_regions_t* regions, uint32_t address, uint32_t* avail);
|
||||||
uint32_t rc_libretro_memory_read(const rc_libretro_memory_regions_t* regions, unsigned address, uint8_t* buffer, uint32_t num_bytes);
|
uint32_t rc_libretro_memory_read(const rc_libretro_memory_regions_t* regions, uint32_t address, uint8_t* buffer, uint32_t num_bytes);
|
||||||
|
|
||||||
/*****************************************************************************\
|
/*****************************************************************************\
|
||||||
| Disk Identification |
|
| Disk Identification |
|
||||||
|
@ -63,7 +66,7 @@ uint32_t rc_libretro_memory_read(const rc_libretro_memory_regions_t* regions, un
|
||||||
typedef struct rc_libretro_hash_entry_t
|
typedef struct rc_libretro_hash_entry_t
|
||||||
{
|
{
|
||||||
uint32_t path_djb2;
|
uint32_t path_djb2;
|
||||||
int game_id;
|
uint32_t game_id;
|
||||||
char hash[33];
|
char hash[33];
|
||||||
} rc_libretro_hash_entry_t;
|
} rc_libretro_hash_entry_t;
|
||||||
|
|
||||||
|
@ -74,14 +77,14 @@ typedef struct rc_libretro_hash_set_t
|
||||||
uint16_t entries_size;
|
uint16_t entries_size;
|
||||||
} rc_libretro_hash_set_t;
|
} rc_libretro_hash_set_t;
|
||||||
|
|
||||||
typedef int (*rc_libretro_get_image_path_func)(unsigned index, char* buffer, size_t buffer_size);
|
typedef int (*rc_libretro_get_image_path_func)(uint32_t index, char* buffer, size_t buffer_size);
|
||||||
|
|
||||||
void rc_libretro_hash_set_init(struct rc_libretro_hash_set_t* hash_set,
|
void rc_libretro_hash_set_init(struct rc_libretro_hash_set_t* hash_set,
|
||||||
const char* m3u_path, rc_libretro_get_image_path_func get_image_path);
|
const char* m3u_path, rc_libretro_get_image_path_func get_image_path);
|
||||||
void rc_libretro_hash_set_destroy(struct rc_libretro_hash_set_t* hash_set);
|
void rc_libretro_hash_set_destroy(struct rc_libretro_hash_set_t* hash_set);
|
||||||
|
|
||||||
void rc_libretro_hash_set_add(struct rc_libretro_hash_set_t* hash_set,
|
void rc_libretro_hash_set_add(struct rc_libretro_hash_set_t* hash_set,
|
||||||
const char* path, int game_id, const char hash[33]);
|
const char* path, uint32_t game_id, const char hash[33]);
|
||||||
const char* rc_libretro_hash_set_get_hash(const struct rc_libretro_hash_set_t* hash_set, const char* path);
|
const char* rc_libretro_hash_set_get_hash(const struct rc_libretro_hash_set_t* hash_set, const char* path);
|
||||||
int rc_libretro_hash_set_get_game_id(const struct rc_libretro_hash_set_t* hash_set, const char* hash);
|
int rc_libretro_hash_set_get_game_id(const struct rc_libretro_hash_set_t* hash_set, const char* hash);
|
||||||
|
|
188
dep/rcheevos/src/rc_util.c
Normal file
188
dep/rcheevos/src/rc_util.c
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
#include "rc_util.h"
|
||||||
|
|
||||||
|
#include "rc_compat.h"
|
||||||
|
#include "rc_error.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#undef DEBUG_BUFFERS
|
||||||
|
|
||||||
|
/* --- rc_buffer --- */
|
||||||
|
|
||||||
|
void rc_buffer_init(rc_buffer_t* buffer)
|
||||||
|
{
|
||||||
|
buffer->chunk.write = buffer->chunk.start = &buffer->data[0];
|
||||||
|
buffer->chunk.end = &buffer->data[sizeof(buffer->data)];
|
||||||
|
buffer->chunk.next = NULL;
|
||||||
|
/* leave buffer->data uninitialized */
|
||||||
|
}
|
||||||
|
|
||||||
|
void rc_buffer_destroy(rc_buffer_t* buffer)
|
||||||
|
{
|
||||||
|
rc_buffer_chunk_t* chunk;
|
||||||
|
#ifdef DEBUG_BUFFERS
|
||||||
|
int count = 0;
|
||||||
|
int wasted = 0;
|
||||||
|
int total = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* first chunk is not allocated. skip it. */
|
||||||
|
chunk = buffer->chunk.next;
|
||||||
|
|
||||||
|
/* deallocate any additional buffers */
|
||||||
|
while (chunk)
|
||||||
|
{
|
||||||
|
rc_buffer_chunk_t* next = chunk->next;
|
||||||
|
#ifdef DEBUG_BUFFERS
|
||||||
|
total += (int)(chunk->end - chunk->start);
|
||||||
|
wasted += (int)(chunk->end - chunk->write);
|
||||||
|
++count;
|
||||||
|
#endif
|
||||||
|
free(chunk);
|
||||||
|
chunk = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_BUFFERS
|
||||||
|
printf("-- %d allocated buffers (%d/%d used, %d wasted, %0.2f%% efficiency)\n", count,
|
||||||
|
total - wasted, total, wasted, (float)(100.0 - (wasted * 100.0) / total));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* rc_buffer_reserve(rc_buffer_t* buffer, size_t amount)
|
||||||
|
{
|
||||||
|
rc_buffer_chunk_t* chunk = &buffer->chunk;
|
||||||
|
size_t remaining;
|
||||||
|
while (chunk)
|
||||||
|
{
|
||||||
|
remaining = chunk->end - chunk->write;
|
||||||
|
if (remaining >= amount)
|
||||||
|
return chunk->write;
|
||||||
|
|
||||||
|
if (!chunk->next)
|
||||||
|
{
|
||||||
|
/* allocate a chunk of memory that is a multiple of 256-bytes. the first 32 bytes will be associated
|
||||||
|
* to the chunk header, and the remaining will be used for data.
|
||||||
|
*/
|
||||||
|
const size_t chunk_header_size = sizeof(rc_buffer_chunk_t);
|
||||||
|
const size_t alloc_size = (chunk_header_size + amount + 0xFF) & ~0xFF;
|
||||||
|
chunk->next = (rc_buffer_chunk_t*)malloc(alloc_size);
|
||||||
|
if (!chunk->next)
|
||||||
|
break;
|
||||||
|
|
||||||
|
chunk->next->start = (uint8_t*)chunk->next + chunk_header_size;
|
||||||
|
chunk->next->write = chunk->next->start;
|
||||||
|
chunk->next->end = (uint8_t*)chunk->next + alloc_size;
|
||||||
|
chunk->next->next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk = chunk->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rc_buffer_consume(rc_buffer_t* buffer, const uint8_t* start, uint8_t* end)
|
||||||
|
{
|
||||||
|
rc_buffer_chunk_t* chunk = &buffer->chunk;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (chunk->write == start)
|
||||||
|
{
|
||||||
|
size_t offset = (end - chunk->start);
|
||||||
|
offset = (offset + 7) & ~7;
|
||||||
|
chunk->write = &chunk->start[offset];
|
||||||
|
|
||||||
|
if (chunk->write > chunk->end)
|
||||||
|
chunk->write = chunk->end;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk = chunk->next;
|
||||||
|
} while (chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* rc_buffer_alloc(rc_buffer_t* buffer, size_t amount)
|
||||||
|
{
|
||||||
|
uint8_t* ptr = rc_buffer_reserve(buffer, amount);
|
||||||
|
rc_buffer_consume(buffer, ptr, ptr + amount);
|
||||||
|
return (void*)ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* rc_buffer_strncpy(rc_buffer_t* buffer, const char* src, size_t len)
|
||||||
|
{
|
||||||
|
uint8_t* dst = rc_buffer_reserve(buffer, len + 1);
|
||||||
|
memcpy(dst, src, len);
|
||||||
|
dst[len] = '\0';
|
||||||
|
rc_buffer_consume(buffer, dst, dst + len + 2);
|
||||||
|
return (char*)dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* rc_buffer_strcpy(rc_buffer_t* buffer, const char* src)
|
||||||
|
{
|
||||||
|
return rc_buffer_strncpy(buffer, src, strlen(src));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- other --- */
|
||||||
|
|
||||||
|
void rc_format_md5(char checksum[33], const uint8_t digest[16])
|
||||||
|
{
|
||||||
|
snprintf(checksum, 33, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||||
|
digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7],
|
||||||
|
digest[8], digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], digest[15]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t rc_djb2(const char* input)
|
||||||
|
{
|
||||||
|
uint32_t result = 5381;
|
||||||
|
char c;
|
||||||
|
|
||||||
|
while ((c = *input++) != '\0')
|
||||||
|
result = ((result << 5) + result) + c; /* result = result * 33 + c */
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* rc_error_str(int ret)
|
||||||
|
{
|
||||||
|
switch (ret) {
|
||||||
|
case RC_OK: return "OK";
|
||||||
|
case RC_INVALID_LUA_OPERAND: return "Invalid Lua operand";
|
||||||
|
case RC_INVALID_MEMORY_OPERAND: return "Invalid memory operand";
|
||||||
|
case RC_INVALID_CONST_OPERAND: return "Invalid constant operand";
|
||||||
|
case RC_INVALID_FP_OPERAND: return "Invalid floating-point operand";
|
||||||
|
case RC_INVALID_CONDITION_TYPE: return "Invalid condition type";
|
||||||
|
case RC_INVALID_OPERATOR: return "Invalid operator";
|
||||||
|
case RC_INVALID_REQUIRED_HITS: return "Invalid required hits";
|
||||||
|
case RC_DUPLICATED_START: return "Duplicated start condition";
|
||||||
|
case RC_DUPLICATED_CANCEL: return "Duplicated cancel condition";
|
||||||
|
case RC_DUPLICATED_SUBMIT: return "Duplicated submit condition";
|
||||||
|
case RC_DUPLICATED_VALUE: return "Duplicated value expression";
|
||||||
|
case RC_DUPLICATED_PROGRESS: return "Duplicated progress expression";
|
||||||
|
case RC_MISSING_START: return "Missing start condition";
|
||||||
|
case RC_MISSING_CANCEL: return "Missing cancel condition";
|
||||||
|
case RC_MISSING_SUBMIT: return "Missing submit condition";
|
||||||
|
case RC_MISSING_VALUE: return "Missing value expression";
|
||||||
|
case RC_INVALID_LBOARD_FIELD: return "Invalid field in leaderboard";
|
||||||
|
case RC_MISSING_DISPLAY_STRING: return "Missing display string";
|
||||||
|
case RC_OUT_OF_MEMORY: return "Out of memory";
|
||||||
|
case RC_INVALID_VALUE_FLAG: return "Invalid flag in value expression";
|
||||||
|
case RC_MISSING_VALUE_MEASURED: return "Missing measured flag in value expression";
|
||||||
|
case RC_MULTIPLE_MEASURED: return "Multiple measured targets";
|
||||||
|
case RC_INVALID_MEASURED_TARGET: return "Invalid measured target";
|
||||||
|
case RC_INVALID_COMPARISON: return "Invalid comparison";
|
||||||
|
case RC_INVALID_STATE: return "Invalid state";
|
||||||
|
case RC_INVALID_JSON: return "Invalid JSON";
|
||||||
|
case RC_API_FAILURE: return "API call failed";
|
||||||
|
case RC_LOGIN_REQUIRED: return "Login required";
|
||||||
|
case RC_NO_GAME_LOADED: return "No game loaded";
|
||||||
|
case RC_HARDCORE_DISABLED: return "Hardcore disabled";
|
||||||
|
case RC_ABORTED: return "Aborted";
|
||||||
|
case RC_NO_RESPONSE: return "No response";
|
||||||
|
case RC_ACCESS_DENIED: return "Access denied";
|
||||||
|
case RC_INVALID_CREDENTIALS: return "Invalid credentials";
|
||||||
|
case RC_EXPIRED_TOKEN: return "Expired token";
|
||||||
|
default: return "Unknown error";
|
||||||
|
}
|
||||||
|
}
|
53
dep/rcheevos/src/rc_util.h
Normal file
53
dep/rcheevos/src/rc_util.h
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
#ifndef RC_UTIL_H
|
||||||
|
#define RC_UTIL_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A block of memory for variable length data (like strings and arrays).
|
||||||
|
*/
|
||||||
|
typedef struct rc_buffer_chunk_t {
|
||||||
|
/* The current location where data is being written */
|
||||||
|
uint8_t* write;
|
||||||
|
/* The first byte past the end of data where writing cannot occur */
|
||||||
|
uint8_t* end;
|
||||||
|
/* The first byte of the data */
|
||||||
|
uint8_t* start;
|
||||||
|
/* The next block in the allocated memory chain */
|
||||||
|
struct rc_buffer_chunk_t* next;
|
||||||
|
}
|
||||||
|
rc_buffer_chunk_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A preallocated block of memory for variable length data (like strings and arrays).
|
||||||
|
*/
|
||||||
|
typedef struct rc_buffer_t {
|
||||||
|
/* The chunk data (will point at the local data member) */
|
||||||
|
struct rc_buffer_chunk_t chunk;
|
||||||
|
/* Small chunk of memory pre-allocated for the chunk */
|
||||||
|
uint8_t data[256];
|
||||||
|
}
|
||||||
|
rc_buffer_t;
|
||||||
|
|
||||||
|
void rc_buffer_init(rc_buffer_t* buffer);
|
||||||
|
void rc_buffer_destroy(rc_buffer_t* buffer);
|
||||||
|
uint8_t* rc_buffer_reserve(rc_buffer_t* buffer, size_t amount);
|
||||||
|
void rc_buffer_consume(rc_buffer_t* buffer, const uint8_t* start, uint8_t* end);
|
||||||
|
void* rc_buffer_alloc(rc_buffer_t* buffer, size_t amount);
|
||||||
|
char* rc_buffer_strcpy(rc_buffer_t* buffer, const char* src);
|
||||||
|
char* rc_buffer_strncpy(rc_buffer_t* buffer, const char* src, size_t len);
|
||||||
|
|
||||||
|
uint32_t rc_djb2(const char* input);
|
||||||
|
|
||||||
|
void rc_format_md5(char checksum[33], const uint8_t digest[16]);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* RC_UTIL_H */
|
|
@ -5,8 +5,8 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define RCHEEVOS_VERSION_MAJOR 10
|
#define RCHEEVOS_VERSION_MAJOR 11
|
||||||
#define RCHEEVOS_VERSION_MINOR 7
|
#define RCHEEVOS_VERSION_MINOR 0
|
||||||
#define RCHEEVOS_VERSION_PATCH 0
|
#define RCHEEVOS_VERSION_PATCH 0
|
||||||
|
|
||||||
#define RCHEEVOS_MAKE_VERSION(major, minor, patch) (major * 1000000 + minor * 1000 + patch)
|
#define RCHEEVOS_MAKE_VERSION(major, minor, patch) (major * 1000000 + minor * 1000 + patch)
|
|
@ -3,7 +3,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
void* rc_alloc_scratch(void* pointer, int* offset, int size, int alignment, rc_scratch_t* scratch, int scratch_object_pointer_offset)
|
void* rc_alloc_scratch(void* pointer, int32_t* offset, uint32_t size, uint32_t alignment, rc_scratch_t* scratch, uint32_t scratch_object_pointer_offset)
|
||||||
{
|
{
|
||||||
rc_scratch_buffer_t* buffer;
|
rc_scratch_buffer_t* buffer;
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ void* rc_alloc_scratch(void* pointer, int* offset, int size, int alignment, rc_s
|
||||||
|
|
||||||
/* update how much space will be required in the real buffer */
|
/* update how much space will be required in the real buffer */
|
||||||
{
|
{
|
||||||
const int aligned_offset = (*offset + alignment - 1) & ~(alignment - 1);
|
const int32_t aligned_offset = (*offset + alignment - 1) & ~(alignment - 1);
|
||||||
*offset += (aligned_offset - *offset);
|
*offset += (aligned_offset - *offset);
|
||||||
*offset += size;
|
*offset += size;
|
||||||
}
|
}
|
||||||
|
@ -21,12 +21,14 @@ void* rc_alloc_scratch(void* pointer, int* offset, int size, int alignment, rc_s
|
||||||
/* find a scratch buffer to hold the temporary data */
|
/* find a scratch buffer to hold the temporary data */
|
||||||
buffer = &scratch->buffer;
|
buffer = &scratch->buffer;
|
||||||
do {
|
do {
|
||||||
const int aligned_buffer_offset = (buffer->offset + alignment - 1) & ~(alignment - 1);
|
const uint32_t aligned_buffer_offset = (buffer->offset + alignment - 1) & ~(alignment - 1);
|
||||||
const int remaining = sizeof(buffer->buffer) - aligned_buffer_offset;
|
if (aligned_buffer_offset < sizeof(buffer->buffer)) {
|
||||||
|
const uint32_t remaining = sizeof(buffer->buffer) - aligned_buffer_offset;
|
||||||
|
|
||||||
if (remaining >= size) {
|
if (remaining >= size) {
|
||||||
/* claim the required space from an existing buffer */
|
/* claim the required space from an existing buffer */
|
||||||
return rc_alloc(buffer->buffer, &buffer->offset, size, alignment, NULL, -1);
|
return rc_alloc(buffer->buffer, &buffer->offset, size, alignment, NULL, -1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!buffer->next)
|
if (!buffer->next)
|
||||||
|
@ -36,13 +38,13 @@ void* rc_alloc_scratch(void* pointer, int* offset, int size, int alignment, rc_s
|
||||||
} while (1);
|
} while (1);
|
||||||
|
|
||||||
/* not enough space in any existing buffer, allocate more */
|
/* not enough space in any existing buffer, allocate more */
|
||||||
if (size > (int)sizeof(buffer->buffer)) {
|
if (size > (uint32_t)sizeof(buffer->buffer)) {
|
||||||
/* caller is asking for more than we can fit in a standard rc_scratch_buffer_t.
|
/* caller is asking for more than we can fit in a standard rc_scratch_buffer_t.
|
||||||
* leverage the fact that the buffer is the last field and extend its size.
|
* leverage the fact that the buffer is the last field and extend its size.
|
||||||
* this chunk will be exactly large enough to hold the needed data, and since offset
|
* this chunk will be exactly large enough to hold the needed data, and since offset
|
||||||
* will exceed sizeof(buffer->buffer), it will never be eligible to hold anything else.
|
* will exceed sizeof(buffer->buffer), it will never be eligible to hold anything else.
|
||||||
*/
|
*/
|
||||||
const int needed = sizeof(rc_scratch_buffer_t) - sizeof(buffer->buffer) + size;
|
const size_t needed = sizeof(rc_scratch_buffer_t) - sizeof(buffer->buffer) + size;
|
||||||
buffer->next = (rc_scratch_buffer_t*)malloc(needed);
|
buffer->next = (rc_scratch_buffer_t*)malloc(needed);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -62,7 +64,7 @@ void* rc_alloc_scratch(void* pointer, int* offset, int size, int alignment, rc_s
|
||||||
return rc_alloc(buffer->buffer, &buffer->offset, size, alignment, NULL, -1);
|
return rc_alloc(buffer->buffer, &buffer->offset, size, alignment, NULL, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* rc_alloc(void* pointer, int* offset, int size, int alignment, rc_scratch_t* scratch, int scratch_object_pointer_offset) {
|
void* rc_alloc(void* pointer, int32_t* offset, uint32_t size, uint32_t alignment, rc_scratch_t* scratch, uint32_t scratch_object_pointer_offset) {
|
||||||
void* ptr;
|
void* ptr;
|
||||||
|
|
||||||
*offset = (*offset + alignment - 1) & ~(alignment - 1);
|
*offset = (*offset + alignment - 1) & ~(alignment - 1);
|
||||||
|
@ -76,7 +78,7 @@ void* rc_alloc(void* pointer, int* offset, int size, int alignment, rc_scratch_t
|
||||||
void** scratch_object_pointer = (void**)((char*)&scratch->objs + scratch_object_pointer_offset);
|
void** scratch_object_pointer = (void**)((char*)&scratch->objs + scratch_object_pointer_offset);
|
||||||
ptr = *scratch_object_pointer;
|
ptr = *scratch_object_pointer;
|
||||||
if (!ptr) {
|
if (!ptr) {
|
||||||
int used;
|
int32_t used;
|
||||||
ptr = *scratch_object_pointer = rc_alloc_scratch(NULL, &used, size, alignment, scratch, -1);
|
ptr = *scratch_object_pointer = rc_alloc_scratch(NULL, &used, size, alignment, scratch, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,8 +91,8 @@ void* rc_alloc(void* pointer, int* offset, int size, int alignment, rc_scratch_t
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* rc_alloc_str(rc_parse_state_t* parse, const char* text, int length) {
|
char* rc_alloc_str(rc_parse_state_t* parse, const char* text, size_t length) {
|
||||||
int used = 0;
|
int32_t used = 0;
|
||||||
char* ptr;
|
char* ptr;
|
||||||
|
|
||||||
rc_scratch_string_t** next = &parse->scratch.strings;
|
rc_scratch_string_t** next = &parse->scratch.strings;
|
||||||
|
@ -109,7 +111,7 @@ char* rc_alloc_str(rc_parse_state_t* parse, const char* text, int length) {
|
||||||
}
|
}
|
||||||
|
|
||||||
*next = (rc_scratch_string_t*)rc_alloc_scratch(NULL, &used, sizeof(rc_scratch_string_t), RC_ALIGNOF(rc_scratch_string_t), &parse->scratch, RC_OFFSETOF(parse->scratch.objs, __rc_scratch_string_t));
|
*next = (rc_scratch_string_t*)rc_alloc_scratch(NULL, &used, sizeof(rc_scratch_string_t), RC_ALIGNOF(rc_scratch_string_t), &parse->scratch, RC_OFFSETOF(parse->scratch.objs, __rc_scratch_string_t));
|
||||||
ptr = (char*)rc_alloc_scratch(parse->buffer, &parse->offset, length + 1, RC_ALIGNOF(char), &parse->scratch, -1);
|
ptr = (char*)rc_alloc_scratch(parse->buffer, &parse->offset, (uint32_t)length + 1, RC_ALIGNOF(char), &parse->scratch, -1);
|
||||||
|
|
||||||
if (!ptr || !*next) {
|
if (!ptr || !*next) {
|
||||||
if (parse->offset >= 0)
|
if (parse->offset >= 0)
|
||||||
|
@ -158,54 +160,3 @@ void rc_destroy_parse_state(rc_parse_state_t* parse)
|
||||||
buffer = next;
|
buffer = next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned rc_djb2(const char* input)
|
|
||||||
{
|
|
||||||
unsigned result = 5381;
|
|
||||||
char c;
|
|
||||||
|
|
||||||
while ((c = *input++) != '\0')
|
|
||||||
result = ((result << 5) + result) + c; /* result = result * 33 + c */
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* rc_error_str(int ret)
|
|
||||||
{
|
|
||||||
switch (ret) {
|
|
||||||
case RC_OK: return "OK";
|
|
||||||
case RC_INVALID_LUA_OPERAND: return "Invalid Lua operand";
|
|
||||||
case RC_INVALID_MEMORY_OPERAND: return "Invalid memory operand";
|
|
||||||
case RC_INVALID_CONST_OPERAND: return "Invalid constant operand";
|
|
||||||
case RC_INVALID_FP_OPERAND: return "Invalid floating-point operand";
|
|
||||||
case RC_INVALID_CONDITION_TYPE: return "Invalid condition type";
|
|
||||||
case RC_INVALID_OPERATOR: return "Invalid operator";
|
|
||||||
case RC_INVALID_REQUIRED_HITS: return "Invalid required hits";
|
|
||||||
case RC_DUPLICATED_START: return "Duplicated start condition";
|
|
||||||
case RC_DUPLICATED_CANCEL: return "Duplicated cancel condition";
|
|
||||||
case RC_DUPLICATED_SUBMIT: return "Duplicated submit condition";
|
|
||||||
case RC_DUPLICATED_VALUE: return "Duplicated value expression";
|
|
||||||
case RC_DUPLICATED_PROGRESS: return "Duplicated progress expression";
|
|
||||||
case RC_MISSING_START: return "Missing start condition";
|
|
||||||
case RC_MISSING_CANCEL: return "Missing cancel condition";
|
|
||||||
case RC_MISSING_SUBMIT: return "Missing submit condition";
|
|
||||||
case RC_MISSING_VALUE: return "Missing value expression";
|
|
||||||
case RC_INVALID_LBOARD_FIELD: return "Invalid field in leaderboard";
|
|
||||||
case RC_MISSING_DISPLAY_STRING: return "Missing display string";
|
|
||||||
case RC_OUT_OF_MEMORY: return "Out of memory";
|
|
||||||
case RC_INVALID_VALUE_FLAG: return "Invalid flag in value expression";
|
|
||||||
case RC_MISSING_VALUE_MEASURED: return "Missing measured flag in value expression";
|
|
||||||
case RC_MULTIPLE_MEASURED: return "Multiple measured targets";
|
|
||||||
case RC_INVALID_MEASURED_TARGET: return "Invalid measured target";
|
|
||||||
case RC_INVALID_COMPARISON: return "Invalid comparison";
|
|
||||||
case RC_INVALID_STATE: return "Invalid state";
|
|
||||||
case RC_INVALID_JSON: return "Invalid JSON";
|
|
||||||
case RC_API_FAILURE: return "API call failed";
|
|
||||||
case RC_LOGIN_REQUIRED: return "Login required";
|
|
||||||
case RC_NO_GAME_LOADED: return "No game loaded";
|
|
||||||
case RC_HARDCORE_DISABLED: return "Hardcore disabled";
|
|
||||||
case RC_ABORTED: return "Aborted";
|
|
||||||
case RC_NO_RESPONSE: return "No response";
|
|
||||||
default: return "Unknown error";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
static int rc_test_condition_compare(unsigned value1, unsigned value2, char oper) {
|
static int rc_test_condition_compare(uint32_t value1, uint32_t value2, uint8_t oper) {
|
||||||
switch (oper) {
|
switch (oper) {
|
||||||
case RC_OPERATOR_EQ: return value1 == value2;
|
case RC_OPERATOR_EQ: return value1 == value2;
|
||||||
case RC_OPERATOR_NE: return value1 != value2;
|
case RC_OPERATOR_NE: return value1 != value2;
|
||||||
|
@ -149,7 +149,7 @@ static int rc_parse_operator(const char** memaddr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse, int is_indirect) {
|
rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse, uint8_t is_indirect) {
|
||||||
rc_condition_t* self;
|
rc_condition_t* self;
|
||||||
const char* aux;
|
const char* aux;
|
||||||
int result;
|
int result;
|
||||||
|
@ -323,23 +323,23 @@ int rc_condition_is_combining(const rc_condition_t* self) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rc_test_condition_compare_memref_to_const(rc_condition_t* self) {
|
static int rc_test_condition_compare_memref_to_const(rc_condition_t* self) {
|
||||||
const unsigned value1 = self->operand1.value.memref->value.value;
|
const uint32_t value1 = self->operand1.value.memref->value.value;
|
||||||
const unsigned value2 = self->operand2.value.num;
|
const uint32_t value2 = self->operand2.value.num;
|
||||||
assert(self->operand1.size == self->operand1.value.memref->value.size);
|
assert(self->operand1.size == self->operand1.value.memref->value.size);
|
||||||
return rc_test_condition_compare(value1, value2, self->oper);
|
return rc_test_condition_compare(value1, value2, self->oper);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rc_test_condition_compare_delta_to_const(rc_condition_t* self) {
|
static int rc_test_condition_compare_delta_to_const(rc_condition_t* self) {
|
||||||
const rc_memref_value_t* memref1 = &self->operand1.value.memref->value;
|
const rc_memref_value_t* memref1 = &self->operand1.value.memref->value;
|
||||||
const unsigned value1 = (memref1->changed) ? memref1->prior : memref1->value;
|
const uint32_t value1 = (memref1->changed) ? memref1->prior : memref1->value;
|
||||||
const unsigned value2 = self->operand2.value.num;
|
const uint32_t value2 = self->operand2.value.num;
|
||||||
assert(self->operand1.size == self->operand1.value.memref->value.size);
|
assert(self->operand1.size == self->operand1.value.memref->value.size);
|
||||||
return rc_test_condition_compare(value1, value2, self->oper);
|
return rc_test_condition_compare(value1, value2, self->oper);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rc_test_condition_compare_memref_to_memref(rc_condition_t* self) {
|
static int rc_test_condition_compare_memref_to_memref(rc_condition_t* self) {
|
||||||
const unsigned value1 = self->operand1.value.memref->value.value;
|
const uint32_t value1 = self->operand1.value.memref->value.value;
|
||||||
const unsigned value2 = self->operand2.value.memref->value.value;
|
const uint32_t value2 = self->operand2.value.memref->value.value;
|
||||||
assert(self->operand1.size == self->operand1.value.memref->value.size);
|
assert(self->operand1.size == self->operand1.value.memref->value.size);
|
||||||
assert(self->operand2.size == self->operand2.value.memref->value.size);
|
assert(self->operand2.size == self->operand2.value.memref->value.size);
|
||||||
return rc_test_condition_compare(value1, value2, self->oper);
|
return rc_test_condition_compare(value1, value2, self->oper);
|
||||||
|
@ -387,7 +387,7 @@ static int rc_test_condition_compare_delta_to_memref(rc_condition_t* self) {
|
||||||
|
|
||||||
static int rc_test_condition_compare_memref_to_const_transformed(rc_condition_t* self) {
|
static int rc_test_condition_compare_memref_to_const_transformed(rc_condition_t* self) {
|
||||||
rc_typed_value_t value1;
|
rc_typed_value_t value1;
|
||||||
const unsigned value2 = self->operand2.value.num;
|
const uint32_t value2 = self->operand2.value.num;
|
||||||
|
|
||||||
value1.type = RC_VALUE_TYPE_UNSIGNED;
|
value1.type = RC_VALUE_TYPE_UNSIGNED;
|
||||||
value1.value.u32 = self->operand1.value.memref->value.value;
|
value1.value.u32 = self->operand1.value.memref->value.value;
|
||||||
|
@ -399,7 +399,7 @@ static int rc_test_condition_compare_memref_to_const_transformed(rc_condition_t*
|
||||||
static int rc_test_condition_compare_delta_to_const_transformed(rc_condition_t* self) {
|
static int rc_test_condition_compare_delta_to_const_transformed(rc_condition_t* self) {
|
||||||
rc_typed_value_t value1;
|
rc_typed_value_t value1;
|
||||||
const rc_memref_value_t* memref1 = &self->operand1.value.memref->value;
|
const rc_memref_value_t* memref1 = &self->operand1.value.memref->value;
|
||||||
const unsigned value2 = self->operand2.value.num;
|
const uint32_t value2 = self->operand2.value.num;
|
||||||
|
|
||||||
value1.type = RC_VALUE_TYPE_UNSIGNED;
|
value1.type = RC_VALUE_TYPE_UNSIGNED;
|
||||||
value1.value.u32 = (memref1->changed) ? memref1->prior : memref1->value;
|
value1.value.u32 = (memref1->changed) ? memref1->prior : memref1->value;
|
||||||
|
|
|
@ -28,7 +28,7 @@ rc_condset_t* rc_parse_condset(const char** memaddr, rc_parse_state_t* parse, in
|
||||||
rc_condset_t* self;
|
rc_condset_t* self;
|
||||||
rc_condition_t** next;
|
rc_condition_t** next;
|
||||||
int in_add_address;
|
int in_add_address;
|
||||||
unsigned measured_target = 0;
|
uint32_t measured_target = 0;
|
||||||
|
|
||||||
self = RC_ALLOC(rc_condset_t, parse);
|
self = RC_ALLOC(rc_condset_t, parse);
|
||||||
self->has_pause = self->is_paused = self->has_indirect_memrefs = 0;
|
self->has_pause = self->is_paused = self->has_indirect_memrefs = 0;
|
||||||
|
@ -181,7 +181,7 @@ static int rc_test_condset_internal(rc_condset_t* self, int processing_pause, rc
|
||||||
rc_typed_value_t value;
|
rc_typed_value_t value;
|
||||||
int set_valid, cond_valid, and_next, or_next, reset_next, measured_from_hits, can_measure;
|
int set_valid, cond_valid, and_next, or_next, reset_next, measured_from_hits, can_measure;
|
||||||
rc_typed_value_t measured_value;
|
rc_typed_value_t measured_value;
|
||||||
unsigned total_hits;
|
uint32_t total_hits;
|
||||||
|
|
||||||
measured_value.type = RC_VALUE_TYPE_NONE;
|
measured_value.type = RC_VALUE_TYPE_NONE;
|
||||||
measured_from_hits = 0;
|
measured_from_hits = 0;
|
||||||
|
|
|
@ -761,16 +761,19 @@ static const rc_memory_region_t _rc_memory_regions_sg1000[] = {
|
||||||
static const rc_memory_regions_t rc_memory_regions_sg1000 = { _rc_memory_regions_sg1000, 4 };
|
static const rc_memory_regions_t rc_memory_regions_sg1000 = { _rc_memory_regions_sg1000, 4 };
|
||||||
|
|
||||||
/* ===== Super Cassette Vision ===== */
|
/* ===== Super Cassette Vision ===== */
|
||||||
|
/* https://github.com/mamedev/mame/blob/f32bb79e8541ba96d3a8144b220c48fb7536ba4b/src/mame/epoch/scv.cpp#L78-L86 */
|
||||||
|
/* SCV only has 128 bytes of system RAM, any additional memory is provided on the individual carts and is
|
||||||
|
* not backed up by battery. */
|
||||||
|
/* http://www.videogameconsolelibrary.com/pg80-super_cass_vis.htm#page=specs */
|
||||||
static const rc_memory_region_t _rc_memory_regions_scv[] = {
|
static const rc_memory_region_t _rc_memory_regions_scv[] = {
|
||||||
{ 0x000000U, 0x000FFFU, 0x000000U, RC_MEMORY_TYPE_READONLY, "System ROM" },
|
{ 0x000000U, 0x000FFFU, 0x000000U, RC_MEMORY_TYPE_READONLY, "System ROM" }, /* BIOS */
|
||||||
{ 0x001000U, 0x001FFFU, 0x001000U, RC_MEMORY_TYPE_UNUSED, "" },
|
{ 0x001000U, 0x001FFFU, 0x001000U, RC_MEMORY_TYPE_UNUSED, "" },
|
||||||
{ 0x002000U, 0x003FFFU, 0x002000U, RC_MEMORY_TYPE_VIDEO_RAM, "Video RAM" },
|
{ 0x002000U, 0x003FFFU, 0x002000U, RC_MEMORY_TYPE_VIDEO_RAM, "Video RAM" }, /* only really goes to $33FF? */
|
||||||
{ 0x004000U, 0x007FFFU, 0x004000U, RC_MEMORY_TYPE_UNUSED, "" },
|
{ 0x004000U, 0x007FFFU, 0x004000U, RC_MEMORY_TYPE_UNUSED, "" },
|
||||||
{ 0x008000U, 0x00DFFFU, 0x008000U, RC_MEMORY_TYPE_READONLY, "Cartridge ROM" },
|
{ 0x008000U, 0x00FF7FU, 0x008000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Cartridge RAM" },
|
||||||
{ 0x00E000U, 0x00FF7FU, 0x00E000U, RC_MEMORY_TYPE_SAVE_RAM, "Cartridge RAM" },
|
|
||||||
{ 0x00FF80U, 0x00FFFFU, 0x00FF80U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
|
{ 0x00FF80U, 0x00FFFFU, 0x00FF80U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
|
||||||
};
|
};
|
||||||
static const rc_memory_regions_t rc_memory_regions_scv = { _rc_memory_regions_scv, 7 };
|
static const rc_memory_regions_t rc_memory_regions_scv = { _rc_memory_regions_scv, 6 };
|
||||||
|
|
||||||
/* ===== Super Nintendo ===== */
|
/* ===== Super Nintendo ===== */
|
||||||
/* https://en.wikibooks.org/wiki/Super_NES_Programming/SNES_memory_map#LoROM */
|
/* https://en.wikibooks.org/wiki/Super_NES_Programming/SNES_memory_map#LoROM */
|
||||||
|
@ -879,7 +882,7 @@ static const rc_memory_regions_t rc_memory_regions_wonderswan = { _rc_memory_reg
|
||||||
/* ===== default ===== */
|
/* ===== default ===== */
|
||||||
static const rc_memory_regions_t rc_memory_regions_none = { 0, 0 };
|
static const rc_memory_regions_t rc_memory_regions_none = { 0, 0 };
|
||||||
|
|
||||||
const rc_memory_regions_t* rc_console_memory_regions(int console_id)
|
const rc_memory_regions_t* rc_console_memory_regions(uint32_t console_id)
|
||||||
{
|
{
|
||||||
switch (console_id)
|
switch (console_id)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "rc_internal.h"
|
#include "rc_internal.h"
|
||||||
|
|
||||||
#include "rc_compat.h"
|
#include "../rc_compat.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -75,16 +75,16 @@ int rc_parse_format(const char* format_str) {
|
||||||
return RC_FORMAT_VALUE;
|
return RC_FORMAT_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rc_format_value_minutes(char* buffer, int size, unsigned minutes) {
|
static int rc_format_value_minutes(char* buffer, size_t size, uint32_t minutes) {
|
||||||
unsigned hours;
|
uint32_t hours;
|
||||||
|
|
||||||
hours = minutes / 60;
|
hours = minutes / 60;
|
||||||
minutes -= hours * 60;
|
minutes -= hours * 60;
|
||||||
return snprintf(buffer, size, "%uh%02u", hours, minutes);
|
return snprintf(buffer, size, "%uh%02u", hours, minutes);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rc_format_value_seconds(char* buffer, int size, unsigned seconds) {
|
static int rc_format_value_seconds(char* buffer, size_t size, uint32_t seconds) {
|
||||||
unsigned hours, minutes;
|
uint32_t hours, minutes;
|
||||||
|
|
||||||
/* apply modulus math to split the seconds into hours/minutes/seconds */
|
/* apply modulus math to split the seconds into hours/minutes/seconds */
|
||||||
minutes = seconds / 60;
|
minutes = seconds / 60;
|
||||||
|
@ -98,8 +98,8 @@ static int rc_format_value_seconds(char* buffer, int size, unsigned seconds) {
|
||||||
return snprintf(buffer, size, "%uh%02u:%02u", hours, minutes, seconds);
|
return snprintf(buffer, size, "%uh%02u:%02u", hours, minutes, seconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rc_format_value_centiseconds(char* buffer, int size, unsigned centiseconds) {
|
static int rc_format_value_centiseconds(char* buffer, size_t size, uint32_t centiseconds) {
|
||||||
unsigned seconds;
|
uint32_t seconds;
|
||||||
int chars, chars2;
|
int chars, chars2;
|
||||||
|
|
||||||
/* modulus off the centiseconds */
|
/* modulus off the centiseconds */
|
||||||
|
@ -119,7 +119,7 @@ static int rc_format_value_centiseconds(char* buffer, int size, unsigned centise
|
||||||
return chars;
|
return chars;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_format_typed_value(char* buffer, int size, const rc_typed_value_t* value, int format) {
|
int rc_format_typed_value(char* buffer, size_t size, const rc_typed_value_t* value, int format) {
|
||||||
int chars;
|
int chars;
|
||||||
rc_typed_value_t converted_value;
|
rc_typed_value_t converted_value;
|
||||||
|
|
||||||
|
@ -197,7 +197,7 @@ int rc_format_typed_value(char* buffer, int size, const rc_typed_value_t* value,
|
||||||
return chars;
|
return chars;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_format_value(char* buffer, int size, int value, int format) {
|
int rc_format_value(char* buffer, int size, int32_t value, int format) {
|
||||||
rc_typed_value_t typed_value;
|
rc_typed_value_t typed_value;
|
||||||
|
|
||||||
typed_value.value.i32 = value;
|
typed_value.value.i32 = value;
|
||||||
|
|
|
@ -164,7 +164,7 @@ rc_lboard_t* rc_parse_lboard(void* buffer, const char* memaddr, lua_State* L, in
|
||||||
return (parse.offset >= 0) ? self : 0;
|
return (parse.offset >= 0) ? self : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_evaluate_lboard(rc_lboard_t* self, int* value, rc_peek_t peek, void* peek_ud, lua_State* L) {
|
int rc_evaluate_lboard(rc_lboard_t* self, int32_t* value, rc_peek_t peek, void* peek_ud, lua_State* L) {
|
||||||
int start_ok, cancel_ok, submit_ok;
|
int start_ok, cancel_ok, submit_ok;
|
||||||
|
|
||||||
rc_update_memref_values(self->memrefs, peek, peek_ud);
|
rc_update_memref_values(self->memrefs, peek, peek_ud);
|
||||||
|
@ -262,6 +262,9 @@ int rc_lboard_state_active(int state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_reset_lboard(rc_lboard_t* self) {
|
void rc_reset_lboard(rc_lboard_t* self) {
|
||||||
|
if (!self)
|
||||||
|
return;
|
||||||
|
|
||||||
self->state = RC_LBOARD_STATE_WAITING;
|
self->state = RC_LBOARD_STATE_WAITING;
|
||||||
|
|
||||||
rc_reset_trigger(&self->start);
|
rc_reset_trigger(&self->start);
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
#define MEMREF_PLACEHOLDER_ADDRESS 0xFFFFFFFF
|
#define MEMREF_PLACEHOLDER_ADDRESS 0xFFFFFFFF
|
||||||
|
|
||||||
rc_memref_t* rc_alloc_memref(rc_parse_state_t* parse, unsigned address, char size, char is_indirect) {
|
rc_memref_t* rc_alloc_memref(rc_parse_state_t* parse, uint32_t address, uint8_t size, uint8_t is_indirect) {
|
||||||
rc_memref_t** next_memref;
|
rc_memref_t** next_memref;
|
||||||
rc_memref_t* memref;
|
rc_memref_t* memref;
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ rc_memref_t* rc_alloc_memref(rc_parse_state_t* parse, unsigned address, char siz
|
||||||
return memref;
|
return memref;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_parse_memref(const char** memaddr, char* size, unsigned* address) {
|
int rc_parse_memref(const char** memaddr, uint8_t* size, uint32_t* address) {
|
||||||
const char* aux = *memaddr;
|
const char* aux = *memaddr;
|
||||||
char* end;
|
char* end;
|
||||||
unsigned long value;
|
unsigned long value;
|
||||||
|
@ -114,15 +114,15 @@ int rc_parse_memref(const char** memaddr, char* size, unsigned* address) {
|
||||||
if (value > 0xffffffffU)
|
if (value > 0xffffffffU)
|
||||||
value = 0xffffffffU;
|
value = 0xffffffffU;
|
||||||
|
|
||||||
*address = (unsigned)value;
|
*address = (uint32_t)value;
|
||||||
*memaddr = end;
|
*memaddr = end;
|
||||||
return RC_OK;
|
return RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static float rc_build_float(unsigned mantissa_bits, int exponent, int sign) {
|
static float rc_build_float(uint32_t mantissa_bits, int32_t exponent, int sign) {
|
||||||
/* 32-bit float has a 23-bit mantissa and 8-bit exponent */
|
/* 32-bit float has a 23-bit mantissa and 8-bit exponent */
|
||||||
const unsigned implied_bit = 1 << 23;
|
const uint32_t implied_bit = 1 << 23;
|
||||||
const unsigned mantissa = mantissa_bits | implied_bit;
|
const uint32_t mantissa = mantissa_bits | implied_bit;
|
||||||
double dbl = ((double)mantissa) / ((double)implied_bit);
|
double dbl = ((double)mantissa) / ((double)implied_bit);
|
||||||
|
|
||||||
if (exponent > 127) {
|
if (exponent > 127) {
|
||||||
|
@ -179,8 +179,8 @@ static float rc_build_float(unsigned mantissa_bits, int exponent, int sign) {
|
||||||
|
|
||||||
static void rc_transform_memref_float(rc_typed_value_t* value) {
|
static void rc_transform_memref_float(rc_typed_value_t* value) {
|
||||||
/* decodes an IEEE 754 float */
|
/* decodes an IEEE 754 float */
|
||||||
const unsigned mantissa = (value->value.u32 & 0x7FFFFF);
|
const uint32_t mantissa = (value->value.u32 & 0x7FFFFF);
|
||||||
const int exponent = (int)((value->value.u32 >> 23) & 0xFF) - 127;
|
const int32_t exponent = (int32_t)((value->value.u32 >> 23) & 0xFF) - 127;
|
||||||
const int sign = (value->value.u32 & 0x80000000);
|
const int sign = (value->value.u32 & 0x80000000);
|
||||||
value->value.f32 = rc_build_float(mantissa, exponent, sign);
|
value->value.f32 = rc_build_float(mantissa, exponent, sign);
|
||||||
value->type = RC_VALUE_TYPE_FLOAT;
|
value->type = RC_VALUE_TYPE_FLOAT;
|
||||||
|
@ -188,11 +188,11 @@ static void rc_transform_memref_float(rc_typed_value_t* value) {
|
||||||
|
|
||||||
static void rc_transform_memref_float_be(rc_typed_value_t* value) {
|
static void rc_transform_memref_float_be(rc_typed_value_t* value) {
|
||||||
/* decodes an IEEE 754 float in big endian format */
|
/* decodes an IEEE 754 float in big endian format */
|
||||||
const unsigned mantissa = ((value->value.u32 & 0xFF000000) >> 24) |
|
const uint32_t mantissa = ((value->value.u32 & 0xFF000000) >> 24) |
|
||||||
((value->value.u32 & 0x00FF0000) >> 8) |
|
((value->value.u32 & 0x00FF0000) >> 8) |
|
||||||
((value->value.u32 & 0x00007F00) << 8);
|
((value->value.u32 & 0x00007F00) << 8);
|
||||||
const int exponent = (int)(((value->value.u32 & 0x0000007F) << 1) |
|
const int32_t exponent = (int32_t)(((value->value.u32 & 0x0000007F) << 1) |
|
||||||
((value->value.u32 & 0x00008000) >> 15)) - 127;
|
((value->value.u32 & 0x00008000) >> 15)) - 127;
|
||||||
const int sign = (value->value.u32 & 0x00000080);
|
const int sign = (value->value.u32 & 0x00000080);
|
||||||
value->value.f32 = rc_build_float(mantissa, exponent, sign);
|
value->value.f32 = rc_build_float(mantissa, exponent, sign);
|
||||||
value->type = RC_VALUE_TYPE_FLOAT;
|
value->type = RC_VALUE_TYPE_FLOAT;
|
||||||
|
@ -201,10 +201,10 @@ static void rc_transform_memref_float_be(rc_typed_value_t* value) {
|
||||||
static void rc_transform_memref_mbf32(rc_typed_value_t* value) {
|
static void rc_transform_memref_mbf32(rc_typed_value_t* value) {
|
||||||
/* decodes a Microsoft Binary Format float */
|
/* decodes a Microsoft Binary Format float */
|
||||||
/* NOTE: 32-bit MBF is stored in memory as big endian (at least for Apple II) */
|
/* NOTE: 32-bit MBF is stored in memory as big endian (at least for Apple II) */
|
||||||
const unsigned mantissa = ((value->value.u32 & 0xFF000000) >> 24) |
|
const uint32_t mantissa = ((value->value.u32 & 0xFF000000) >> 24) |
|
||||||
((value->value.u32 & 0x00FF0000) >> 8) |
|
((value->value.u32 & 0x00FF0000) >> 8) |
|
||||||
((value->value.u32 & 0x00007F00) << 8);
|
((value->value.u32 & 0x00007F00) << 8);
|
||||||
const int exponent = (int)(value->value.u32 & 0xFF) - 129;
|
const int32_t exponent = (int32_t)(value->value.u32 & 0xFF) - 129;
|
||||||
const int sign = (value->value.u32 & 0x00008000);
|
const int sign = (value->value.u32 & 0x00008000);
|
||||||
|
|
||||||
if (mantissa == 0 && exponent == -129)
|
if (mantissa == 0 && exponent == -129)
|
||||||
|
@ -218,8 +218,8 @@ static void rc_transform_memref_mbf32(rc_typed_value_t* value) {
|
||||||
static void rc_transform_memref_mbf32_le(rc_typed_value_t* value) {
|
static void rc_transform_memref_mbf32_le(rc_typed_value_t* value) {
|
||||||
/* decodes a Microsoft Binary Format float */
|
/* decodes a Microsoft Binary Format float */
|
||||||
/* Locomotive BASIC (CPC) uses MBF40, but in little endian format */
|
/* Locomotive BASIC (CPC) uses MBF40, but in little endian format */
|
||||||
const unsigned mantissa = value->value.u32 & 0x007FFFFF;
|
const uint32_t mantissa = value->value.u32 & 0x007FFFFF;
|
||||||
const int exponent = (int)(value->value.u32 >> 24) - 129;
|
const int32_t exponent = (int32_t)(value->value.u32 >> 24) - 129;
|
||||||
const int sign = (value->value.u32 & 0x00800000);
|
const int sign = (value->value.u32 & 0x00800000);
|
||||||
|
|
||||||
if (mantissa == 0 && exponent == -129)
|
if (mantissa == 0 && exponent == -129)
|
||||||
|
@ -230,9 +230,9 @@ static void rc_transform_memref_mbf32_le(rc_typed_value_t* value) {
|
||||||
value->type = RC_VALUE_TYPE_FLOAT;
|
value->type = RC_VALUE_TYPE_FLOAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const unsigned char rc_bits_set[16] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 };
|
static const uint8_t rc_bits_set[16] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 };
|
||||||
|
|
||||||
void rc_transform_memref_value(rc_typed_value_t* value, char size) {
|
void rc_transform_memref_value(rc_typed_value_t* value, uint8_t size) {
|
||||||
/* ASSERT: value->type == RC_VALUE_TYPE_UNSIGNED */
|
/* ASSERT: value->type == RC_VALUE_TYPE_UNSIGNED */
|
||||||
switch (size)
|
switch (size)
|
||||||
{
|
{
|
||||||
|
@ -335,7 +335,7 @@ void rc_transform_memref_value(rc_typed_value_t* value, char size) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const unsigned rc_memref_masks[] = {
|
static const uint32_t rc_memref_masks[] = {
|
||||||
0x000000ff, /* RC_MEMSIZE_8_BITS */
|
0x000000ff, /* RC_MEMSIZE_8_BITS */
|
||||||
0x0000ffff, /* RC_MEMSIZE_16_BITS */
|
0x0000ffff, /* RC_MEMSIZE_16_BITS */
|
||||||
0x00ffffff, /* RC_MEMSIZE_24_BITS */
|
0x00ffffff, /* RC_MEMSIZE_24_BITS */
|
||||||
|
@ -361,7 +361,7 @@ static const unsigned rc_memref_masks[] = {
|
||||||
0xffffffff /* RC_MEMSIZE_VARIABLE */
|
0xffffffff /* RC_MEMSIZE_VARIABLE */
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned rc_memref_mask(char size) {
|
uint32_t rc_memref_mask(uint8_t size) {
|
||||||
const size_t index = (size_t)size;
|
const size_t index = (size_t)size;
|
||||||
if (index >= sizeof(rc_memref_masks) / sizeof(rc_memref_masks[0]))
|
if (index >= sizeof(rc_memref_masks) / sizeof(rc_memref_masks[0]))
|
||||||
return 0xffffffff;
|
return 0xffffffff;
|
||||||
|
@ -372,7 +372,7 @@ unsigned rc_memref_mask(char size) {
|
||||||
/* all sizes less than 8-bits (1 byte) are mapped to 8-bits. 24-bit is mapped to 32-bit
|
/* all sizes less than 8-bits (1 byte) are mapped to 8-bits. 24-bit is mapped to 32-bit
|
||||||
* as we don't expect the client to understand a request for 3 bytes. all other reads are
|
* as we don't expect the client to understand a request for 3 bytes. all other reads are
|
||||||
* mapped to the little-endian read of the same size. */
|
* mapped to the little-endian read of the same size. */
|
||||||
static const char rc_memref_shared_sizes[] = {
|
static const uint8_t rc_memref_shared_sizes[] = {
|
||||||
RC_MEMSIZE_8_BITS, /* RC_MEMSIZE_8_BITS */
|
RC_MEMSIZE_8_BITS, /* RC_MEMSIZE_8_BITS */
|
||||||
RC_MEMSIZE_16_BITS, /* RC_MEMSIZE_16_BITS */
|
RC_MEMSIZE_16_BITS, /* RC_MEMSIZE_16_BITS */
|
||||||
RC_MEMSIZE_32_BITS, /* RC_MEMSIZE_24_BITS */
|
RC_MEMSIZE_32_BITS, /* RC_MEMSIZE_24_BITS */
|
||||||
|
@ -398,7 +398,7 @@ static const char rc_memref_shared_sizes[] = {
|
||||||
RC_MEMSIZE_32_BITS /* RC_MEMSIZE_VARIABLE */
|
RC_MEMSIZE_32_BITS /* RC_MEMSIZE_VARIABLE */
|
||||||
};
|
};
|
||||||
|
|
||||||
char rc_memref_shared_size(char size) {
|
uint8_t rc_memref_shared_size(uint8_t size) {
|
||||||
const size_t index = (size_t)size;
|
const size_t index = (size_t)size;
|
||||||
if (index >= sizeof(rc_memref_shared_sizes) / sizeof(rc_memref_shared_sizes[0]))
|
if (index >= sizeof(rc_memref_shared_sizes) / sizeof(rc_memref_shared_sizes[0]))
|
||||||
return size;
|
return size;
|
||||||
|
@ -406,7 +406,7 @@ char rc_memref_shared_size(char size) {
|
||||||
return rc_memref_shared_sizes[index];
|
return rc_memref_shared_sizes[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned rc_peek_value(unsigned address, char size, rc_peek_t peek, void* ud) {
|
uint32_t rc_peek_value(uint32_t address, uint8_t size, rc_peek_t peek, void* ud) {
|
||||||
if (!peek)
|
if (!peek)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -423,7 +423,7 @@ unsigned rc_peek_value(unsigned address, char size, rc_peek_t peek, void* ud) {
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
unsigned value;
|
uint32_t value;
|
||||||
const size_t index = (size_t)size;
|
const size_t index = (size_t)size;
|
||||||
if (index >= sizeof(rc_memref_shared_sizes) / sizeof(rc_memref_shared_sizes[0]))
|
if (index >= sizeof(rc_memref_shared_sizes) / sizeof(rc_memref_shared_sizes[0]))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -437,7 +437,7 @@ unsigned rc_peek_value(unsigned address, char size, rc_peek_t peek, void* ud) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_update_memref_value(rc_memref_value_t* memref, unsigned new_value) {
|
void rc_update_memref_value(rc_memref_value_t* memref, uint32_t new_value) {
|
||||||
if (memref->value == new_value) {
|
if (memref->value == new_value) {
|
||||||
memref->changed = 0;
|
memref->changed = 0;
|
||||||
}
|
}
|
||||||
|
@ -463,7 +463,7 @@ void rc_init_parse_state_memrefs(rc_parse_state_t* parse, rc_memref_t** memrefs)
|
||||||
*memrefs = 0;
|
*memrefs = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned rc_get_memref_value_value(const rc_memref_value_t* memref, int operand_type) {
|
static uint32_t rc_get_memref_value_value(const rc_memref_value_t* memref, int operand_type) {
|
||||||
switch (operand_type)
|
switch (operand_type)
|
||||||
{
|
{
|
||||||
/* most common case explicitly first, even though it could be handled by default case.
|
/* most common case explicitly first, even though it could be handled by default case.
|
||||||
|
@ -483,10 +483,10 @@ static unsigned rc_get_memref_value_value(const rc_memref_value_t* memref, int o
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned rc_get_memref_value(rc_memref_t* memref, int operand_type, rc_eval_state_t* eval_state) {
|
uint32_t rc_get_memref_value(rc_memref_t* memref, int operand_type, rc_eval_state_t* eval_state) {
|
||||||
/* if this is an indirect reference, handle the indirection. */
|
/* if this is an indirect reference, handle the indirection. */
|
||||||
if (memref->value.is_indirect) {
|
if (memref->value.is_indirect) {
|
||||||
const unsigned new_address = memref->address + eval_state->add_address;
|
const uint32_t new_address = memref->address + eval_state->add_address;
|
||||||
rc_update_memref_value(&memref->value, rc_peek_value(new_address, memref->value.size, eval_state->peek, eval_state->peek_userdata));
|
rc_update_memref_value(&memref->value, rc_peek_value(new_address, memref->value.size, eval_state->peek, eval_state->peek_userdata));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,10 +68,10 @@ static int rc_parse_operand_lua(rc_operand_t* self, const char** memaddr, rc_par
|
||||||
return RC_OK;
|
return RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rc_parse_operand_memory(rc_operand_t* self, const char** memaddr, rc_parse_state_t* parse, int is_indirect) {
|
static int rc_parse_operand_memory(rc_operand_t* self, const char** memaddr, rc_parse_state_t* parse, uint8_t is_indirect) {
|
||||||
const char* aux = *memaddr;
|
const char* aux = *memaddr;
|
||||||
unsigned address;
|
uint32_t address;
|
||||||
char size;
|
uint8_t size;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
switch (*aux) {
|
switch (*aux) {
|
||||||
|
@ -115,7 +115,7 @@ static int rc_parse_operand_memory(rc_operand_t* self, const char** memaddr, rc_
|
||||||
size = self->size;
|
size = self->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
self->value.memref = rc_alloc_memref(parse, address, size, (char)is_indirect);
|
self->value.memref = rc_alloc_memref(parse, address, size, is_indirect);
|
||||||
if (parse->offset < 0)
|
if (parse->offset < 0)
|
||||||
return parse->offset;
|
return parse->offset;
|
||||||
|
|
||||||
|
@ -123,7 +123,7 @@ static int rc_parse_operand_memory(rc_operand_t* self, const char** memaddr, rc_
|
||||||
return RC_OK;
|
return RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_parse_operand(rc_operand_t* self, const char** memaddr, int is_indirect, rc_parse_state_t* parse) {
|
int rc_parse_operand(rc_operand_t* self, const char** memaddr, uint8_t is_indirect, rc_parse_state_t* parse) {
|
||||||
const char* aux = *memaddr;
|
const char* aux = *memaddr;
|
||||||
char* end;
|
char* end;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -286,11 +286,11 @@ typedef struct {
|
||||||
rc_luapeek_t;
|
rc_luapeek_t;
|
||||||
|
|
||||||
static int rc_luapeek(lua_State* L) {
|
static int rc_luapeek(lua_State* L) {
|
||||||
unsigned address = (unsigned)luaL_checkinteger(L, 1);
|
uint32_t address = (uint32_t)luaL_checkinteger(L, 1);
|
||||||
unsigned num_bytes = (unsigned)luaL_checkinteger(L, 2);
|
uint32_t num_bytes = (uint32_t)luaL_checkinteger(L, 2);
|
||||||
rc_luapeek_t* luapeek = (rc_luapeek_t*)lua_touserdata(L, 3);
|
rc_luapeek_t* luapeek = (rc_luapeek_t*)lua_touserdata(L, 3);
|
||||||
|
|
||||||
unsigned value = luapeek->peek(address, num_bytes, luapeek->ud);
|
uint32_t value = luapeek->peek(address, num_bytes, luapeek->ud);
|
||||||
|
|
||||||
lua_pushinteger(L, value);
|
lua_pushinteger(L, value);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -330,7 +330,7 @@ int rc_operand_is_float(const rc_operand_t* self) {
|
||||||
return rc_operand_is_float_memref(self);
|
return rc_operand_is_float_memref(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned rc_transform_operand_value(unsigned value, const rc_operand_t* self) {
|
uint32_t rc_transform_operand_value(uint32_t value, const rc_operand_t* self) {
|
||||||
switch (self->type)
|
switch (self->type)
|
||||||
{
|
{
|
||||||
case RC_OPERAND_BCD:
|
case RC_OPERAND_BCD:
|
||||||
|
@ -451,10 +451,10 @@ void rc_evaluate_operand(rc_typed_value_t* result, rc_operand_t* self, rc_eval_s
|
||||||
|
|
||||||
if (lua_pcall(eval_state->L, 2, 1, 0) == LUA_OK) {
|
if (lua_pcall(eval_state->L, 2, 1, 0) == LUA_OK) {
|
||||||
if (lua_isboolean(eval_state->L, -1)) {
|
if (lua_isboolean(eval_state->L, -1)) {
|
||||||
result->value.u32 = (unsigned)lua_toboolean(eval_state->L, -1);
|
result->value.u32 = (uint32_t)lua_toboolean(eval_state->L, -1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result->value.u32 = (unsigned)lua_tonumber(eval_state->L, -1);
|
result->value.u32 = (uint32_t)lua_tonumber(eval_state->L, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef INTERNAL_H
|
#ifndef RC_INTERNAL_H
|
||||||
#define INTERNAL_H
|
#define RC_INTERNAL_H
|
||||||
|
|
||||||
#include "rc_runtime_types.h"
|
#include "rc_runtime_types.h"
|
||||||
|
|
||||||
|
@ -41,8 +41,8 @@ RC_ALLOW_ALIGN(char)
|
||||||
|
|
||||||
typedef struct rc_scratch_buffer {
|
typedef struct rc_scratch_buffer {
|
||||||
struct rc_scratch_buffer* next;
|
struct rc_scratch_buffer* next;
|
||||||
int offset;
|
int32_t offset;
|
||||||
unsigned char buffer[512 - 16];
|
uint8_t buffer[512 - 16];
|
||||||
}
|
}
|
||||||
rc_scratch_buffer_t;
|
rc_scratch_buffer_t;
|
||||||
|
|
||||||
|
@ -77,8 +77,8 @@ enum {
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
union {
|
union {
|
||||||
unsigned u32;
|
uint32_t u32;
|
||||||
int i32;
|
int32_t i32;
|
||||||
float f32;
|
float f32;
|
||||||
} value;
|
} value;
|
||||||
|
|
||||||
|
@ -90,24 +90,24 @@ rc_typed_value_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
rc_typed_value_t add_value;/* AddSource/SubSource */
|
rc_typed_value_t add_value;/* AddSource/SubSource */
|
||||||
int add_hits; /* AddHits */
|
int32_t add_hits; /* AddHits */
|
||||||
unsigned add_address; /* AddAddress */
|
uint32_t add_address; /* AddAddress */
|
||||||
|
|
||||||
rc_peek_t peek;
|
rc_peek_t peek;
|
||||||
void* peek_userdata;
|
void* peek_userdata;
|
||||||
lua_State* L;
|
lua_State* L;
|
||||||
|
|
||||||
rc_typed_value_t measured_value; /* Measured */
|
rc_typed_value_t measured_value; /* Measured */
|
||||||
char was_reset; /* ResetIf triggered */
|
uint8_t was_reset; /* ResetIf triggered */
|
||||||
char has_hits; /* one of more hit counts is non-zero */
|
uint8_t has_hits; /* one of more hit counts is non-zero */
|
||||||
char primed; /* true if all non-Trigger conditions are true */
|
uint8_t primed; /* true if all non-Trigger conditions are true */
|
||||||
char measured_from_hits; /* true if the measured_value came from a condition's hit count */
|
uint8_t measured_from_hits; /* true if the measured_value came from a condition's hit count */
|
||||||
char was_cond_reset; /* ResetNextIf triggered */
|
uint8_t was_cond_reset; /* ResetNextIf triggered */
|
||||||
}
|
}
|
||||||
rc_eval_state_t;
|
rc_eval_state_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int offset;
|
int32_t offset;
|
||||||
|
|
||||||
lua_State* L;
|
lua_State* L;
|
||||||
int funcs_ndx;
|
int funcs_ndx;
|
||||||
|
@ -118,11 +118,11 @@ typedef struct {
|
||||||
rc_memref_t** first_memref;
|
rc_memref_t** first_memref;
|
||||||
rc_value_t** variables;
|
rc_value_t** variables;
|
||||||
|
|
||||||
unsigned measured_target;
|
uint32_t measured_target;
|
||||||
int lines_read;
|
int lines_read;
|
||||||
|
|
||||||
char has_required_hits;
|
uint8_t has_required_hits;
|
||||||
char measured_as_percent;
|
uint8_t measured_as_percent;
|
||||||
}
|
}
|
||||||
rc_parse_state_t;
|
rc_parse_state_t;
|
||||||
|
|
||||||
|
@ -131,21 +131,19 @@ void rc_init_parse_state_memrefs(rc_parse_state_t* parse, rc_memref_t** memrefs)
|
||||||
void rc_init_parse_state_variables(rc_parse_state_t* parse, rc_value_t** variables);
|
void rc_init_parse_state_variables(rc_parse_state_t* parse, rc_value_t** variables);
|
||||||
void rc_destroy_parse_state(rc_parse_state_t* parse);
|
void rc_destroy_parse_state(rc_parse_state_t* parse);
|
||||||
|
|
||||||
void* rc_alloc(void* pointer, int* offset, int size, int alignment, rc_scratch_t* scratch, int scratch_object_pointer_offset);
|
void* rc_alloc(void* pointer, int32_t* offset, uint32_t size, uint32_t alignment, rc_scratch_t* scratch, uint32_t scratch_object_pointer_offset);
|
||||||
void* rc_alloc_scratch(void* pointer, int* offset, int size, int alignment, rc_scratch_t* scratch, int scratch_object_pointer_offset);
|
void* rc_alloc_scratch(void* pointer, int32_t* offset, uint32_t size, uint32_t alignment, rc_scratch_t* scratch, uint32_t scratch_object_pointer_offset);
|
||||||
char* rc_alloc_str(rc_parse_state_t* parse, const char* text, int length);
|
char* rc_alloc_str(rc_parse_state_t* parse, const char* text, size_t length);
|
||||||
|
|
||||||
unsigned rc_djb2(const char* input);
|
rc_memref_t* rc_alloc_memref(rc_parse_state_t* parse, uint32_t address, uint8_t size, uint8_t is_indirect);
|
||||||
|
int rc_parse_memref(const char** memaddr, uint8_t* size, uint32_t* address);
|
||||||
rc_memref_t* rc_alloc_memref(rc_parse_state_t* parse, unsigned address, char size, char is_indirect);
|
|
||||||
int rc_parse_memref(const char** memaddr, char* size, unsigned* address);
|
|
||||||
void rc_update_memref_values(rc_memref_t* memref, rc_peek_t peek, void* ud);
|
void rc_update_memref_values(rc_memref_t* memref, rc_peek_t peek, void* ud);
|
||||||
void rc_update_memref_value(rc_memref_value_t* memref, unsigned value);
|
void rc_update_memref_value(rc_memref_value_t* memref, uint32_t value);
|
||||||
unsigned rc_get_memref_value(rc_memref_t* memref, int operand_type, rc_eval_state_t* eval_state);
|
uint32_t rc_get_memref_value(rc_memref_t* memref, int operand_type, rc_eval_state_t* eval_state);
|
||||||
char rc_memref_shared_size(char size);
|
uint8_t rc_memref_shared_size(uint8_t size);
|
||||||
unsigned rc_memref_mask(char size);
|
uint32_t rc_memref_mask(uint8_t size);
|
||||||
void rc_transform_memref_value(rc_typed_value_t* value, char size);
|
void rc_transform_memref_value(rc_typed_value_t* value, uint8_t size);
|
||||||
unsigned rc_peek_value(unsigned address, char size, rc_peek_t peek, void* ud);
|
uint32_t rc_peek_value(uint32_t address, uint8_t size, rc_peek_t peek, void* ud);
|
||||||
|
|
||||||
void rc_parse_trigger_internal(rc_trigger_t* self, const char** memaddr, rc_parse_state_t* parse);
|
void rc_parse_trigger_internal(rc_trigger_t* self, const char** memaddr, rc_parse_state_t* parse);
|
||||||
int rc_trigger_state_active(int state);
|
int rc_trigger_state_active(int state);
|
||||||
|
@ -170,12 +168,12 @@ enum {
|
||||||
RC_PROCESSING_COMPARE_ALWAYS_FALSE
|
RC_PROCESSING_COMPARE_ALWAYS_FALSE
|
||||||
};
|
};
|
||||||
|
|
||||||
rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse, int is_indirect);
|
rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse, uint8_t is_indirect);
|
||||||
int rc_test_condition(rc_condition_t* self, rc_eval_state_t* eval_state);
|
int rc_test_condition(rc_condition_t* self, rc_eval_state_t* eval_state);
|
||||||
void rc_evaluate_condition_value(rc_typed_value_t* value, rc_condition_t* self, rc_eval_state_t* eval_state);
|
void rc_evaluate_condition_value(rc_typed_value_t* value, rc_condition_t* self, rc_eval_state_t* eval_state);
|
||||||
int rc_condition_is_combining(const rc_condition_t* self);
|
int rc_condition_is_combining(const rc_condition_t* self);
|
||||||
|
|
||||||
int rc_parse_operand(rc_operand_t* self, const char** memaddr, int is_indirect, rc_parse_state_t* parse);
|
int rc_parse_operand(rc_operand_t* self, const char** memaddr, uint8_t is_indirect, rc_parse_state_t* parse);
|
||||||
void rc_evaluate_operand(rc_typed_value_t* value, rc_operand_t* self, rc_eval_state_t* eval_state);
|
void rc_evaluate_operand(rc_typed_value_t* value, rc_operand_t* self, rc_eval_state_t* eval_state);
|
||||||
int rc_operand_is_float_memref(const rc_operand_t* self);
|
int rc_operand_is_float_memref(const rc_operand_t* self);
|
||||||
int rc_operand_is_float(const rc_operand_t* self);
|
int rc_operand_is_float(const rc_operand_t* self);
|
||||||
|
@ -184,7 +182,7 @@ void rc_parse_value_internal(rc_value_t* self, const char** memaddr, rc_parse_st
|
||||||
int rc_evaluate_value_typed(rc_value_t* self, rc_typed_value_t* value, rc_peek_t peek, void* ud, lua_State* L);
|
int rc_evaluate_value_typed(rc_value_t* self, rc_typed_value_t* value, rc_peek_t peek, void* ud, lua_State* L);
|
||||||
void rc_reset_value(rc_value_t* self);
|
void rc_reset_value(rc_value_t* self);
|
||||||
int rc_value_from_hits(rc_value_t* self);
|
int rc_value_from_hits(rc_value_t* self);
|
||||||
rc_value_t* rc_alloc_helper_variable(const char* memaddr, int memaddr_len, rc_parse_state_t* parse);
|
rc_value_t* rc_alloc_helper_variable(const char* memaddr, size_t memaddr_len, rc_parse_state_t* parse);
|
||||||
void rc_update_variables(rc_value_t* variable, rc_peek_t peek, void* ud, lua_State* L);
|
void rc_update_variables(rc_value_t* variable, rc_peek_t peek, void* ud, lua_State* L);
|
||||||
|
|
||||||
void rc_typed_value_convert(rc_typed_value_t* value, char new_type);
|
void rc_typed_value_convert(rc_typed_value_t* value, char new_type);
|
||||||
|
@ -195,7 +193,7 @@ void rc_typed_value_negate(rc_typed_value_t* value);
|
||||||
int rc_typed_value_compare(const rc_typed_value_t* value1, const rc_typed_value_t* value2, char oper);
|
int rc_typed_value_compare(const rc_typed_value_t* value1, const rc_typed_value_t* value2, char oper);
|
||||||
void rc_typed_value_from_memref_value(rc_typed_value_t* value, const rc_memref_value_t* memref);
|
void rc_typed_value_from_memref_value(rc_typed_value_t* value, const rc_memref_value_t* memref);
|
||||||
|
|
||||||
int rc_format_typed_value(char* buffer, int size, const rc_typed_value_t* value, int format);
|
int rc_format_typed_value(char* buffer, size_t size, const rc_typed_value_t* value, int format);
|
||||||
|
|
||||||
void rc_parse_lboard_internal(rc_lboard_t* self, const char* memaddr, rc_parse_state_t* parse);
|
void rc_parse_lboard_internal(rc_lboard_t* self, const char* memaddr, rc_parse_state_t* parse);
|
||||||
int rc_lboard_state_active(int state);
|
int rc_lboard_state_active(int state);
|
||||||
|
@ -206,4 +204,4 @@ void rc_parse_richpresence_internal(rc_richpresence_t* self, const char* script,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* INTERNAL_H */
|
#endif /* RC_INTERNAL_H */
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
#include "rc_validate.h"
|
#include "rc_validate.h"
|
||||||
|
|
||||||
#include "rc_compat.h"
|
|
||||||
#include "rc_consoles.h"
|
#include "rc_consoles.h"
|
||||||
#include "rc_internal.h"
|
#include "rc_internal.h"
|
||||||
|
|
||||||
|
#include "../rc_compat.h"
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
static int rc_validate_memref(const rc_memref_t* memref, char result[], const size_t result_size, int console_id, unsigned max_address)
|
static int rc_validate_memref(const rc_memref_t* memref, char result[], const size_t result_size, uint32_t console_id, uint32_t max_address)
|
||||||
{
|
{
|
||||||
if (memref->address > max_address) {
|
if (memref->address > max_address) {
|
||||||
snprintf(result, result_size, "Address %04X out of range (max %04X)", memref->address, max_address);
|
snprintf(result, result_size, "Address %04X out of range (max %04X)", memref->address, max_address);
|
||||||
|
@ -41,7 +42,7 @@ static int rc_validate_memref(const rc_memref_t* memref, char result[], const si
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_validate_memrefs(const rc_memref_t* memref, char result[], const size_t result_size, unsigned max_address)
|
int rc_validate_memrefs(const rc_memref_t* memref, char result[], const size_t result_size, uint32_t max_address)
|
||||||
{
|
{
|
||||||
while (memref) {
|
while (memref) {
|
||||||
if (!rc_validate_memref(memref, result, result_size, 0, max_address))
|
if (!rc_validate_memref(memref, result, result_size, 0, max_address))
|
||||||
|
@ -53,7 +54,7 @@ int rc_validate_memrefs(const rc_memref_t* memref, char result[], const size_t r
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned rc_console_max_address(int console_id)
|
static uint32_t rc_console_max_address(uint32_t console_id)
|
||||||
{
|
{
|
||||||
const rc_memory_regions_t* memory_regions;
|
const rc_memory_regions_t* memory_regions;
|
||||||
memory_regions = rc_console_memory_regions(console_id);
|
memory_regions = rc_console_memory_regions(console_id);
|
||||||
|
@ -63,9 +64,9 @@ static unsigned rc_console_max_address(int console_id)
|
||||||
return 0xFFFFFFFF;
|
return 0xFFFFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_validate_memrefs_for_console(const rc_memref_t* memref, char result[], const size_t result_size, int console_id)
|
int rc_validate_memrefs_for_console(const rc_memref_t* memref, char result[], const size_t result_size, uint32_t console_id)
|
||||||
{
|
{
|
||||||
const unsigned max_address = rc_console_max_address(console_id);
|
const uint32_t max_address = rc_console_max_address(console_id);
|
||||||
while (memref) {
|
while (memref) {
|
||||||
if (!rc_validate_memref(memref, result, result_size, console_id, max_address))
|
if (!rc_validate_memref(memref, result, result_size, console_id, max_address))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -76,7 +77,7 @@ int rc_validate_memrefs_for_console(const rc_memref_t* memref, char result[], co
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned rc_max_value(const rc_operand_t* operand)
|
static uint32_t rc_max_value(const rc_operand_t* operand)
|
||||||
{
|
{
|
||||||
if (operand->type == RC_OPERAND_CONST)
|
if (operand->type == RC_OPERAND_CONST)
|
||||||
return operand->value.num;
|
return operand->value.num;
|
||||||
|
@ -118,7 +119,7 @@ static unsigned rc_max_value(const rc_operand_t* operand)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned rc_scale_value(unsigned value, char oper, const rc_operand_t* operand)
|
static uint32_t rc_scale_value(uint32_t value, uint8_t oper, const rc_operand_t* operand)
|
||||||
{
|
{
|
||||||
switch (oper) {
|
switch (oper) {
|
||||||
case RC_OPERATOR_MULT:
|
case RC_OPERATOR_MULT:
|
||||||
|
@ -127,12 +128,12 @@ static unsigned rc_scale_value(unsigned value, char oper, const rc_operand_t* op
|
||||||
if (scaled > 0xFFFFFFFF)
|
if (scaled > 0xFFFFFFFF)
|
||||||
return 0xFFFFFFFF;
|
return 0xFFFFFFFF;
|
||||||
|
|
||||||
return (unsigned)scaled;
|
return (uint32_t)scaled;
|
||||||
}
|
}
|
||||||
|
|
||||||
case RC_OPERATOR_DIV:
|
case RC_OPERATOR_DIV:
|
||||||
{
|
{
|
||||||
const unsigned min_val = (operand->type == RC_OPERAND_CONST) ? operand->value.num : 1;
|
const uint32_t min_val = (operand->type == RC_OPERAND_CONST) ? operand->value.num : 1;
|
||||||
return value / min_val;
|
return value / min_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +163,7 @@ static int rc_validate_get_condition_index(const rc_condset_t* condset, const rc
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rc_validate_range(unsigned min_val, unsigned max_val, char oper, unsigned max, char result[], const size_t result_size)
|
static int rc_validate_range(uint32_t min_val, uint32_t max_val, char oper, uint32_t max, char result[], const size_t result_size)
|
||||||
{
|
{
|
||||||
switch (oper) {
|
switch (oper) {
|
||||||
case RC_OPERATOR_AND:
|
case RC_OPERATOR_AND:
|
||||||
|
@ -230,11 +231,11 @@ static int rc_validate_range(unsigned min_val, unsigned max_val, char oper, unsi
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_validate_condset_internal(const rc_condset_t* condset, char result[], const size_t result_size, int console_id, unsigned max_address)
|
int rc_validate_condset_internal(const rc_condset_t* condset, char result[], const size_t result_size, uint32_t console_id, uint32_t max_address)
|
||||||
{
|
{
|
||||||
const rc_condition_t* cond;
|
const rc_condition_t* cond;
|
||||||
char buffer[128];
|
char buffer[128];
|
||||||
unsigned max_val;
|
uint32_t max_val;
|
||||||
int index = 1;
|
int index = 1;
|
||||||
unsigned long long add_source_max = 0;
|
unsigned long long add_source_max = 0;
|
||||||
int in_add_hits = 0;
|
int in_add_hits = 0;
|
||||||
|
@ -247,7 +248,7 @@ int rc_validate_condset_internal(const rc_condset_t* condset, char result[], con
|
||||||
}
|
}
|
||||||
|
|
||||||
for (cond = condset->conditions; cond; cond = cond->next, ++index) {
|
for (cond = condset->conditions; cond; cond = cond->next, ++index) {
|
||||||
unsigned max = rc_max_value(&cond->operand1);
|
uint32_t max = rc_max_value(&cond->operand1);
|
||||||
const int is_memref1 = rc_operand_is_memref(&cond->operand1);
|
const int is_memref1 = rc_operand_is_memref(&cond->operand1);
|
||||||
const int is_memref2 = rc_operand_is_memref(&cond->operand2);
|
const int is_memref2 = rc_operand_is_memref(&cond->operand2);
|
||||||
|
|
||||||
|
@ -300,6 +301,13 @@ int rc_validate_condset_internal(const rc_condset_t* condset, char result[], con
|
||||||
is_combining = 1;
|
is_combining = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case RC_CONDITION_RESET_IF:
|
||||||
|
if (cond->required_hits == 1) {
|
||||||
|
snprintf(result, result_size, "Condition %d: Hit target of 1 is redundant on ResetIf", index);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* fallthrough to default */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (in_add_hits) {
|
if (in_add_hits) {
|
||||||
if (cond->required_hits == 0) {
|
if (cond->required_hits == 0) {
|
||||||
|
@ -334,7 +342,7 @@ int rc_validate_condset_internal(const rc_condset_t* condset, char result[], con
|
||||||
if (is_memref1 || is_memref2 || add_source_max) {
|
if (is_memref1 || is_memref2 || add_source_max) {
|
||||||
const size_t prefix_length = snprintf(result, result_size, "Condition %d: ", index);
|
const size_t prefix_length = snprintf(result, result_size, "Condition %d: ", index);
|
||||||
|
|
||||||
unsigned min_val;
|
uint32_t min_val;
|
||||||
switch (cond->operand2.type) {
|
switch (cond->operand2.type) {
|
||||||
case RC_OPERAND_CONST:
|
case RC_OPERAND_CONST:
|
||||||
min_val = cond->operand2.value.num;
|
min_val = cond->operand2.value.num;
|
||||||
|
@ -386,14 +394,14 @@ int rc_validate_condset_internal(const rc_condset_t* condset, char result[], con
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_validate_condset(const rc_condset_t* condset, char result[], const size_t result_size, unsigned max_address)
|
int rc_validate_condset(const rc_condset_t* condset, char result[], const size_t result_size, uint32_t max_address)
|
||||||
{
|
{
|
||||||
return rc_validate_condset_internal(condset, result, result_size, 0, max_address);
|
return rc_validate_condset_internal(condset, result, result_size, 0, max_address);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_validate_condset_for_console(const rc_condset_t* condset, char result[], const size_t result_size, int console_id)
|
int rc_validate_condset_for_console(const rc_condset_t* condset, char result[], const size_t result_size, uint32_t console_id)
|
||||||
{
|
{
|
||||||
const unsigned max_address = rc_console_max_address(console_id);
|
const uint32_t max_address = rc_console_max_address(console_id);
|
||||||
return rc_validate_condset_internal(condset, result, result_size, console_id, max_address);
|
return rc_validate_condset_internal(condset, result, result_size, console_id, max_address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -476,7 +484,7 @@ enum {
|
||||||
RC_OVERLAP_DEFER
|
RC_OVERLAP_DEFER
|
||||||
};
|
};
|
||||||
|
|
||||||
static int rc_validate_comparison_overlap(int comparison1, unsigned value1, int comparison2, unsigned value2)
|
static int rc_validate_comparison_overlap(int comparison1, uint32_t value1, int comparison2, uint32_t value2)
|
||||||
{
|
{
|
||||||
/* NOTE: this only cares if comp2 conflicts with comp1.
|
/* NOTE: this only cares if comp2 conflicts with comp1.
|
||||||
* If comp1 conflicts with comp2, we'll catch that later (return RC_OVERLAP_NONE for now) */
|
* If comp1 conflicts with comp2, we'll catch that later (return RC_OVERLAP_NONE for now) */
|
||||||
|
@ -634,7 +642,7 @@ static int rc_validate_conflicting_conditions(const rc_condset_t* conditions, co
|
||||||
const char* prefix, const char* compare_prefix, char result[], const size_t result_size)
|
const char* prefix, const char* compare_prefix, char result[], const size_t result_size)
|
||||||
{
|
{
|
||||||
int comparison1, comparison2;
|
int comparison1, comparison2;
|
||||||
unsigned value1, value2;
|
uint32_t value1, value2;
|
||||||
const rc_operand_t* operand1;
|
const rc_operand_t* operand1;
|
||||||
const rc_operand_t* operand2;
|
const rc_operand_t* operand2;
|
||||||
const rc_condition_t* compare_condition;
|
const rc_condition_t* compare_condition;
|
||||||
|
@ -789,7 +797,7 @@ static int rc_validate_conflicting_conditions(const rc_condset_t* conditions, co
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rc_validate_trigger_internal(const rc_trigger_t* trigger, char result[], const size_t result_size, int console_id, unsigned max_address)
|
static int rc_validate_trigger_internal(const rc_trigger_t* trigger, char result[], const size_t result_size, uint32_t console_id, uint32_t max_address)
|
||||||
{
|
{
|
||||||
const rc_condset_t* alt;
|
const rc_condset_t* alt;
|
||||||
int index;
|
int index;
|
||||||
|
@ -835,13 +843,13 @@ static int rc_validate_trigger_internal(const rc_trigger_t* trigger, char result
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_validate_trigger(const rc_trigger_t* trigger, char result[], const size_t result_size, unsigned max_address)
|
int rc_validate_trigger(const rc_trigger_t* trigger, char result[], const size_t result_size, uint32_t max_address)
|
||||||
{
|
{
|
||||||
return rc_validate_trigger_internal(trigger, result, result_size, 0, max_address);
|
return rc_validate_trigger_internal(trigger, result, result_size, 0, max_address);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_validate_trigger_for_console(const rc_trigger_t* trigger, char result[], const size_t result_size, int console_id)
|
int rc_validate_trigger_for_console(const rc_trigger_t* trigger, char result[], const size_t result_size, uint32_t console_id)
|
||||||
{
|
{
|
||||||
const unsigned max_address = rc_console_max_address(console_id);
|
const uint32_t max_address = rc_console_max_address(console_id);
|
||||||
return rc_validate_trigger_internal(trigger, result, result_size, console_id, max_address);
|
return rc_validate_trigger_internal(trigger, result, result_size, console_id, max_address);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,15 +9,15 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int rc_validate_memrefs(const rc_memref_t* memref, char result[], const size_t result_size, unsigned max_address);
|
int rc_validate_memrefs(const rc_memref_t* memref, char result[], const size_t result_size, uint32_t max_address);
|
||||||
|
|
||||||
int rc_validate_condset(const rc_condset_t* condset, char result[], const size_t result_size, unsigned max_address);
|
int rc_validate_condset(const rc_condset_t* condset, char result[], const size_t result_size, uint32_t max_address);
|
||||||
int rc_validate_trigger(const rc_trigger_t* trigger, char result[], const size_t result_size, unsigned max_address);
|
int rc_validate_trigger(const rc_trigger_t* trigger, char result[], const size_t result_size, uint32_t max_address);
|
||||||
|
|
||||||
int rc_validate_memrefs_for_console(const rc_memref_t* memref, char result[], const size_t result_size, int console_id);
|
int rc_validate_memrefs_for_console(const rc_memref_t* memref, char result[], const size_t result_size, uint32_t console_id);
|
||||||
|
|
||||||
int rc_validate_condset_for_console(const rc_condset_t* condset, char result[], const size_t result_size, int console_id);
|
int rc_validate_condset_for_console(const rc_condset_t* condset, char result[], const size_t result_size, uint32_t console_id);
|
||||||
int rc_validate_trigger_for_console(const rc_trigger_t* trigger, char result[], const size_t result_size, int console_id);
|
int rc_validate_trigger_for_console(const rc_trigger_t* trigger, char result[], const size_t result_size, uint32_t console_id);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "rc_internal.h"
|
#include "rc_internal.h"
|
||||||
|
|
||||||
#include "rc_compat.h"
|
#include "../rc_compat.h"
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
@ -16,8 +16,8 @@ enum {
|
||||||
static rc_memref_value_t* rc_alloc_helper_variable_memref_value(const char* memaddr, int memaddr_len, rc_parse_state_t* parse) {
|
static rc_memref_value_t* rc_alloc_helper_variable_memref_value(const char* memaddr, int memaddr_len, rc_parse_state_t* parse) {
|
||||||
const char* end;
|
const char* end;
|
||||||
rc_value_t* variable;
|
rc_value_t* variable;
|
||||||
unsigned address;
|
uint32_t address;
|
||||||
char size;
|
uint8_t size;
|
||||||
|
|
||||||
/* single memory reference lookups without a modifier flag can be handled without a variable */
|
/* single memory reference lookups without a modifier flag can be handled without a variable */
|
||||||
end = memaddr;
|
end = memaddr;
|
||||||
|
@ -78,7 +78,7 @@ static const char* rc_parse_line(const char* line, const char** end, rc_parse_st
|
||||||
typedef struct rc_richpresence_builtin_macro_t {
|
typedef struct rc_richpresence_builtin_macro_t {
|
||||||
const char* name;
|
const char* name;
|
||||||
size_t name_len;
|
size_t name_len;
|
||||||
unsigned short display_type;
|
uint8_t display_type;
|
||||||
} rc_richpresence_builtin_macro_t;
|
} rc_richpresence_builtin_macro_t;
|
||||||
|
|
||||||
static rc_richpresence_display_t* rc_parse_richpresence_display_internal(const char* line, const char* endline, rc_parse_state_t* parse, rc_richpresence_lookup_t* first_lookup) {
|
static rc_richpresence_display_t* rc_parse_richpresence_display_internal(const char* line, const char* endline, rc_parse_state_t* parse, rc_richpresence_lookup_t* first_lookup) {
|
||||||
|
@ -324,7 +324,7 @@ static void rc_rebalance_richpresence_lookup(rc_richpresence_lookup_item_t** roo
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rc_insert_richpresence_lookup_item(rc_richpresence_lookup_t* lookup,
|
static void rc_insert_richpresence_lookup_item(rc_richpresence_lookup_t* lookup,
|
||||||
unsigned first, unsigned last, const char* label, int label_len, rc_parse_state_t* parse)
|
uint32_t first, uint32_t last, const char* label, size_t label_len, rc_parse_state_t* parse)
|
||||||
{
|
{
|
||||||
rc_richpresence_lookup_item_t** next;
|
rc_richpresence_lookup_item_t** next;
|
||||||
rc_richpresence_lookup_item_t* item;
|
rc_richpresence_lookup_item_t* item;
|
||||||
|
@ -370,7 +370,7 @@ static const char* rc_parse_richpresence_lookup(rc_richpresence_lookup_t* lookup
|
||||||
const char* endline;
|
const char* endline;
|
||||||
const char* label;
|
const char* label;
|
||||||
char* endptr = 0;
|
char* endptr = 0;
|
||||||
unsigned first, last;
|
uint32_t first, last;
|
||||||
int base;
|
int base;
|
||||||
|
|
||||||
do
|
do
|
||||||
|
@ -525,7 +525,7 @@ void rc_parse_richpresence_internal(rc_richpresence_t* self, const char* script,
|
||||||
memcpy(format, line, chars);
|
memcpy(format, line, chars);
|
||||||
format[chars] = '\0';
|
format[chars] = '\0';
|
||||||
|
|
||||||
lookup->format = (unsigned short)rc_parse_format(format);
|
lookup->format = (uint8_t)rc_parse_format(format);
|
||||||
} else {
|
} else {
|
||||||
lookup->format = RC_FORMAT_VALUE;
|
lookup->format = RC_FORMAT_VALUE;
|
||||||
}
|
}
|
||||||
|
@ -663,7 +663,7 @@ void rc_update_richpresence(rc_richpresence_t* richpresence, rc_peek_t peek, voi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rc_evaluate_richpresence_display(rc_richpresence_display_part_t* part, char* buffer, unsigned buffersize)
|
static int rc_evaluate_richpresence_display(rc_richpresence_display_part_t* part, char* buffer, size_t buffersize)
|
||||||
{
|
{
|
||||||
rc_richpresence_lookup_item_t* item;
|
rc_richpresence_lookup_item_t* item;
|
||||||
rc_typed_value_t value;
|
rc_typed_value_t value;
|
||||||
|
@ -807,7 +807,7 @@ static int rc_evaluate_richpresence_display(rc_richpresence_display_part_t* part
|
||||||
return (int)(ptr - buffer);
|
return (int)(ptr - buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_get_richpresence_display_string(rc_richpresence_t* richpresence, char* buffer, unsigned buffersize, rc_peek_t peek, void* peek_ud, lua_State* L) {
|
int rc_get_richpresence_display_string(rc_richpresence_t* richpresence, char* buffer, size_t buffersize, rc_peek_t peek, void* peek_ud, lua_State* L) {
|
||||||
rc_richpresence_display_t* display;
|
rc_richpresence_display_t* display;
|
||||||
|
|
||||||
for (display = richpresence->first_display; display; display = display->next) {
|
for (display = richpresence->first_display; display; display = display->next) {
|
||||||
|
@ -828,7 +828,7 @@ int rc_get_richpresence_display_string(rc_richpresence_t* richpresence, char* bu
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_evaluate_richpresence(rc_richpresence_t* richpresence, char* buffer, unsigned buffersize, rc_peek_t peek, void* peek_ud, lua_State* L) {
|
int rc_evaluate_richpresence(rc_richpresence_t* richpresence, char* buffer, size_t buffersize, rc_peek_t peek, void* peek_ud, lua_State* L) {
|
||||||
rc_update_richpresence(richpresence, peek, peek_ud, L);
|
rc_update_richpresence(richpresence, peek, peek_ud, L);
|
||||||
return rc_get_richpresence_display_string(richpresence, buffer, buffersize, peek, peek_ud, L);
|
return rc_get_richpresence_display_string(richpresence, buffer, buffersize, peek, peek_ud, L);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "rc_runtime.h"
|
#include "rc_runtime.h"
|
||||||
#include "rc_internal.h"
|
#include "rc_internal.h"
|
||||||
#include "rc_compat.h"
|
|
||||||
|
|
||||||
|
#include "../rc_compat.h"
|
||||||
#include "../rhash/md5.h"
|
#include "../rhash/md5.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -27,7 +27,7 @@ void rc_runtime_init(rc_runtime_t* self) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_runtime_destroy(rc_runtime_t* self) {
|
void rc_runtime_destroy(rc_runtime_t* self) {
|
||||||
unsigned i;
|
uint32_t i;
|
||||||
|
|
||||||
if (self->triggers) {
|
if (self->triggers) {
|
||||||
for (i = 0; i < self->trigger_count; ++i)
|
for (i = 0; i < self->trigger_count; ++i)
|
||||||
|
@ -65,7 +65,7 @@ void rc_runtime_destroy(rc_runtime_t* self) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_runtime_checksum(const char* memaddr, unsigned char* md5) {
|
void rc_runtime_checksum(const char* memaddr, uint8_t* md5) {
|
||||||
md5_state_t state;
|
md5_state_t state;
|
||||||
md5_init(&state);
|
md5_init(&state);
|
||||||
md5_append(&state, (unsigned char*)memaddr, (int)strlen(memaddr));
|
md5_append(&state, (unsigned char*)memaddr, (int)strlen(memaddr));
|
||||||
|
@ -96,7 +96,7 @@ static char rc_runtime_allocated_memrefs(rc_runtime_t* self) {
|
||||||
return owns_memref;
|
return owns_memref;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rc_runtime_deactivate_trigger_by_index(rc_runtime_t* self, unsigned index) {
|
static void rc_runtime_deactivate_trigger_by_index(rc_runtime_t* self, uint32_t index) {
|
||||||
if (self->triggers[index].owns_memrefs) {
|
if (self->triggers[index].owns_memrefs) {
|
||||||
/* if the trigger has one or more memrefs in its buffer, we can't free the buffer.
|
/* if the trigger has one or more memrefs in its buffer, we can't free the buffer.
|
||||||
* just null out the trigger so the runtime processor will skip it
|
* just null out the trigger so the runtime processor will skip it
|
||||||
|
@ -113,8 +113,8 @@ static void rc_runtime_deactivate_trigger_by_index(rc_runtime_t* self, unsigned
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_runtime_deactivate_achievement(rc_runtime_t* self, unsigned id) {
|
void rc_runtime_deactivate_achievement(rc_runtime_t* self, uint32_t id) {
|
||||||
unsigned i;
|
uint32_t i;
|
||||||
|
|
||||||
for (i = 0; i < self->trigger_count; ++i) {
|
for (i = 0; i < self->trigger_count; ++i) {
|
||||||
if (self->triggers[i].id == id && self->triggers[i].trigger != NULL)
|
if (self->triggers[i].id == id && self->triggers[i].trigger != NULL)
|
||||||
|
@ -122,14 +122,14 @@ void rc_runtime_deactivate_achievement(rc_runtime_t* self, unsigned id) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_runtime_activate_achievement(rc_runtime_t* self, unsigned id, const char* memaddr, lua_State* L, int funcs_idx) {
|
int rc_runtime_activate_achievement(rc_runtime_t* self, uint32_t id, const char* memaddr, lua_State* L, int funcs_idx) {
|
||||||
void* trigger_buffer;
|
void* trigger_buffer;
|
||||||
rc_trigger_t* trigger;
|
rc_trigger_t* trigger;
|
||||||
rc_runtime_trigger_t* runtime_trigger;
|
rc_runtime_trigger_t* runtime_trigger;
|
||||||
rc_parse_state_t parse;
|
rc_parse_state_t parse;
|
||||||
unsigned char md5[16];
|
uint8_t md5[16];
|
||||||
int size;
|
int32_t size;
|
||||||
unsigned i;
|
uint32_t i;
|
||||||
|
|
||||||
if (memaddr == NULL)
|
if (memaddr == NULL)
|
||||||
return RC_INVALID_MEMORY_OPERAND;
|
return RC_INVALID_MEMORY_OPERAND;
|
||||||
|
@ -222,9 +222,9 @@ int rc_runtime_activate_achievement(rc_runtime_t* self, unsigned id, const char*
|
||||||
return RC_OK;
|
return RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc_trigger_t* rc_runtime_get_achievement(const rc_runtime_t* self, unsigned id)
|
rc_trigger_t* rc_runtime_get_achievement(const rc_runtime_t* self, uint32_t id)
|
||||||
{
|
{
|
||||||
unsigned i;
|
uint32_t i;
|
||||||
|
|
||||||
for (i = 0; i < self->trigger_count; ++i) {
|
for (i = 0; i < self->trigger_count; ++i) {
|
||||||
if (self->triggers[i].id == id && self->triggers[i].trigger != NULL)
|
if (self->triggers[i].id == id && self->triggers[i].trigger != NULL)
|
||||||
|
@ -234,7 +234,7 @@ rc_trigger_t* rc_runtime_get_achievement(const rc_runtime_t* self, unsigned id)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_runtime_get_achievement_measured(const rc_runtime_t* runtime, unsigned id, unsigned* measured_value, unsigned* measured_target)
|
int rc_runtime_get_achievement_measured(const rc_runtime_t* runtime, uint32_t id, unsigned* measured_value, unsigned* measured_target)
|
||||||
{
|
{
|
||||||
const rc_trigger_t* trigger = rc_runtime_get_achievement(runtime, id);
|
const rc_trigger_t* trigger = rc_runtime_get_achievement(runtime, id);
|
||||||
if (!measured_value || !measured_target)
|
if (!measured_value || !measured_target)
|
||||||
|
@ -257,10 +257,10 @@ int rc_runtime_get_achievement_measured(const rc_runtime_t* runtime, unsigned id
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_runtime_format_achievement_measured(const rc_runtime_t* runtime, unsigned id, char* buffer, size_t buffer_size)
|
int rc_runtime_format_achievement_measured(const rc_runtime_t* runtime, uint32_t id, char* buffer, size_t buffer_size)
|
||||||
{
|
{
|
||||||
const rc_trigger_t* trigger = rc_runtime_get_achievement(runtime, id);
|
const rc_trigger_t* trigger = rc_runtime_get_achievement(runtime, id);
|
||||||
unsigned value;
|
uint32_t value;
|
||||||
if (!buffer || !buffer_size)
|
if (!buffer || !buffer_size)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -277,14 +277,14 @@ int rc_runtime_format_achievement_measured(const rc_runtime_t* runtime, unsigned
|
||||||
value = trigger->measured_target;
|
value = trigger->measured_target;
|
||||||
|
|
||||||
if (trigger->measured_as_percent) {
|
if (trigger->measured_as_percent) {
|
||||||
unsigned percent = (unsigned)(((unsigned long long)value * 100) / trigger->measured_target);
|
const uint32_t percent = (uint32_t)(((unsigned long long)value * 100) / trigger->measured_target);
|
||||||
return snprintf(buffer, buffer_size, "%u%%", percent);
|
return snprintf(buffer, buffer_size, "%u%%", percent);
|
||||||
}
|
}
|
||||||
|
|
||||||
return snprintf(buffer, buffer_size, "%u/%u", value, trigger->measured_target);
|
return snprintf(buffer, buffer_size, "%u/%u", value, trigger->measured_target);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rc_runtime_deactivate_lboard_by_index(rc_runtime_t* self, unsigned index) {
|
static void rc_runtime_deactivate_lboard_by_index(rc_runtime_t* self, uint32_t index) {
|
||||||
if (self->lboards[index].owns_memrefs) {
|
if (self->lboards[index].owns_memrefs) {
|
||||||
/* if the lboard has one or more memrefs in its buffer, we can't free the buffer.
|
/* if the lboard has one or more memrefs in its buffer, we can't free the buffer.
|
||||||
* just null out the lboard so the runtime processor will skip it
|
* just null out the lboard so the runtime processor will skip it
|
||||||
|
@ -301,8 +301,8 @@ static void rc_runtime_deactivate_lboard_by_index(rc_runtime_t* self, unsigned i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_runtime_deactivate_lboard(rc_runtime_t* self, unsigned id) {
|
void rc_runtime_deactivate_lboard(rc_runtime_t* self, uint32_t id) {
|
||||||
unsigned i;
|
uint32_t i;
|
||||||
|
|
||||||
for (i = 0; i < self->lboard_count; ++i) {
|
for (i = 0; i < self->lboard_count; ++i) {
|
||||||
if (self->lboards[i].id == id && self->lboards[i].lboard != NULL)
|
if (self->lboards[i].id == id && self->lboards[i].lboard != NULL)
|
||||||
|
@ -310,14 +310,14 @@ void rc_runtime_deactivate_lboard(rc_runtime_t* self, unsigned id) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_runtime_activate_lboard(rc_runtime_t* self, unsigned id, const char* memaddr, lua_State* L, int funcs_idx) {
|
int rc_runtime_activate_lboard(rc_runtime_t* self, uint32_t id, const char* memaddr, lua_State* L, int funcs_idx) {
|
||||||
void* lboard_buffer;
|
void* lboard_buffer;
|
||||||
unsigned char md5[16];
|
uint8_t md5[16];
|
||||||
rc_lboard_t* lboard;
|
rc_lboard_t* lboard;
|
||||||
rc_parse_state_t parse;
|
rc_parse_state_t parse;
|
||||||
rc_runtime_lboard_t* runtime_lboard;
|
rc_runtime_lboard_t* runtime_lboard;
|
||||||
int size;
|
int size;
|
||||||
unsigned i;
|
uint32_t i;
|
||||||
|
|
||||||
if (memaddr == 0)
|
if (memaddr == 0)
|
||||||
return RC_INVALID_MEMORY_OPERAND;
|
return RC_INVALID_MEMORY_OPERAND;
|
||||||
|
@ -410,9 +410,9 @@ int rc_runtime_activate_lboard(rc_runtime_t* self, unsigned id, const char* mema
|
||||||
return RC_OK;
|
return RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc_lboard_t* rc_runtime_get_lboard(const rc_runtime_t* self, unsigned id)
|
rc_lboard_t* rc_runtime_get_lboard(const rc_runtime_t* self, uint32_t id)
|
||||||
{
|
{
|
||||||
unsigned i;
|
uint32_t i;
|
||||||
|
|
||||||
for (i = 0; i < self->lboard_count; ++i) {
|
for (i = 0; i < self->lboard_count; ++i) {
|
||||||
if (self->lboards[i].id == id && self->lboards[i].lboard != NULL)
|
if (self->lboards[i].id == id && self->lboards[i].lboard != NULL)
|
||||||
|
@ -422,7 +422,7 @@ rc_lboard_t* rc_runtime_get_lboard(const rc_runtime_t* self, unsigned id)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_runtime_format_lboard_value(char* buffer, int size, int value, int format)
|
int rc_runtime_format_lboard_value(char* buffer, int size, int32_t value, int format)
|
||||||
{
|
{
|
||||||
return rc_format_value(buffer, size, value, format);
|
return rc_format_value(buffer, size, value, format);
|
||||||
}
|
}
|
||||||
|
@ -432,7 +432,7 @@ int rc_runtime_activate_richpresence(rc_runtime_t* self, const char* script, lua
|
||||||
rc_runtime_richpresence_t* previous;
|
rc_runtime_richpresence_t* previous;
|
||||||
rc_runtime_richpresence_t** previous_ptr;
|
rc_runtime_richpresence_t** previous_ptr;
|
||||||
rc_parse_state_t parse;
|
rc_parse_state_t parse;
|
||||||
unsigned char md5[16];
|
uint8_t md5[16];
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
if (script == NULL)
|
if (script == NULL)
|
||||||
|
@ -529,7 +529,7 @@ int rc_runtime_activate_richpresence(rc_runtime_t* self, const char* script, lua
|
||||||
return RC_OK;
|
return RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_runtime_get_richpresence(const rc_runtime_t* self, char* buffer, unsigned buffersize, rc_runtime_peek_t peek, void* peek_ud, lua_State* L) {
|
int rc_runtime_get_richpresence(const rc_runtime_t* self, char* buffer, size_t buffersize, rc_runtime_peek_t peek, void* peek_ud, lua_State* L) {
|
||||||
if (self->richpresence && self->richpresence->richpresence)
|
if (self->richpresence && self->richpresence->richpresence)
|
||||||
return rc_get_richpresence_display_string(self->richpresence->richpresence, buffer, buffersize, peek, peek_ud, L);
|
return rc_get_richpresence_display_string(self->richpresence->richpresence, buffer, buffersize, peek, peek_ud, L);
|
||||||
|
|
||||||
|
@ -549,7 +549,7 @@ void rc_runtime_do_frame(rc_runtime_t* self, rc_runtime_event_handler_t event_ha
|
||||||
for (i = self->trigger_count - 1; i >= 0; --i) {
|
for (i = self->trigger_count - 1; i >= 0; --i) {
|
||||||
rc_trigger_t* trigger = self->triggers[i].trigger;
|
rc_trigger_t* trigger = self->triggers[i].trigger;
|
||||||
int old_state, new_state;
|
int old_state, new_state;
|
||||||
unsigned old_measured_value;
|
uint32_t old_measured_value;
|
||||||
|
|
||||||
if (!trigger)
|
if (!trigger)
|
||||||
continue;
|
continue;
|
||||||
|
@ -593,8 +593,8 @@ void rc_runtime_do_frame(rc_runtime_t* self, rc_runtime_event_handler_t event_ha
|
||||||
|
|
||||||
if (trigger->measured_as_percent) {
|
if (trigger->measured_as_percent) {
|
||||||
/* if reporting measured value as a percentage, only send the notification if the percentage changes */
|
/* if reporting measured value as a percentage, only send the notification if the percentage changes */
|
||||||
unsigned old_percent = (unsigned)(((unsigned long long)old_measured_value * 100) / trigger->measured_target);
|
const int32_t old_percent = (int32_t)(((unsigned long long)old_measured_value * 100) / trigger->measured_target);
|
||||||
unsigned new_percent = (unsigned)(((unsigned long long)trigger->measured_value * 100) / trigger->measured_target);
|
const int32_t new_percent = (int32_t)(((unsigned long long)trigger->measured_value * 100) / trigger->measured_target);
|
||||||
if (old_percent != new_percent) {
|
if (old_percent != new_percent) {
|
||||||
runtime_event.value = new_percent;
|
runtime_event.value = new_percent;
|
||||||
event_handler(&runtime_event);
|
event_handler(&runtime_event);
|
||||||
|
@ -715,7 +715,7 @@ void rc_runtime_do_frame(rc_runtime_t* self, rc_runtime_event_handler_t event_ha
|
||||||
|
|
||||||
void rc_runtime_reset(rc_runtime_t* self) {
|
void rc_runtime_reset(rc_runtime_t* self) {
|
||||||
rc_value_t* variable;
|
rc_value_t* variable;
|
||||||
unsigned i;
|
uint32_t i;
|
||||||
|
|
||||||
for (i = 0; i < self->trigger_count; ++i) {
|
for (i = 0; i < self->trigger_count; ++i) {
|
||||||
if (self->triggers[i].trigger)
|
if (self->triggers[i].trigger)
|
||||||
|
@ -779,7 +779,7 @@ int rc_trigger_contains_memref(const rc_trigger_t* trigger, const rc_memref_t* m
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rc_runtime_invalidate_memref(rc_runtime_t* self, rc_memref_t* memref) {
|
static void rc_runtime_invalidate_memref(rc_runtime_t* self, rc_memref_t* memref) {
|
||||||
unsigned i;
|
uint32_t i;
|
||||||
|
|
||||||
/* disable any achievements dependent on the address */
|
/* disable any achievements dependent on the address */
|
||||||
for (i = 0; i < self->trigger_count; ++i) {
|
for (i = 0; i < self->trigger_count; ++i) {
|
||||||
|
@ -814,7 +814,7 @@ static void rc_runtime_invalidate_memref(rc_runtime_t* self, rc_memref_t* memref
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_runtime_invalidate_address(rc_runtime_t* self, unsigned address) {
|
void rc_runtime_invalidate_address(rc_runtime_t* self, uint32_t address) {
|
||||||
rc_memref_t** last_memref = &self->memrefs;
|
rc_memref_t** last_memref = &self->memrefs;
|
||||||
rc_memref_t* memref = self->memrefs;
|
rc_memref_t* memref = self->memrefs;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "rc_runtime.h"
|
#include "rc_runtime.h"
|
||||||
#include "rc_internal.h"
|
#include "rc_internal.h"
|
||||||
|
|
||||||
|
#include "../rc_util.h"
|
||||||
#include "../rhash/md5.h"
|
#include "../rhash/md5.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -19,10 +20,10 @@
|
||||||
typedef struct rc_runtime_progress_t {
|
typedef struct rc_runtime_progress_t {
|
||||||
const rc_runtime_t* runtime;
|
const rc_runtime_t* runtime;
|
||||||
|
|
||||||
int offset;
|
uint32_t offset;
|
||||||
unsigned char* buffer;
|
uint8_t* buffer;
|
||||||
|
|
||||||
int chunk_size_offset;
|
uint32_t chunk_size_offset;
|
||||||
|
|
||||||
lua_State* L;
|
lua_State* L;
|
||||||
} rc_runtime_progress_t;
|
} rc_runtime_progress_t;
|
||||||
|
@ -39,7 +40,7 @@ typedef struct rc_runtime_progress_t {
|
||||||
#define RC_COND_FLAG_OPERAND2_IS_INDIRECT_MEMREF 0x00100000
|
#define RC_COND_FLAG_OPERAND2_IS_INDIRECT_MEMREF 0x00100000
|
||||||
#define RC_COND_FLAG_OPERAND2_MEMREF_CHANGED_THIS_FRAME 0x00200000
|
#define RC_COND_FLAG_OPERAND2_MEMREF_CHANGED_THIS_FRAME 0x00200000
|
||||||
|
|
||||||
static void rc_runtime_progress_write_uint(rc_runtime_progress_t* progress, unsigned value)
|
static void rc_runtime_progress_write_uint(rc_runtime_progress_t* progress, uint32_t value)
|
||||||
{
|
{
|
||||||
if (progress->buffer) {
|
if (progress->buffer) {
|
||||||
progress->buffer[progress->offset + 0] = value & 0xFF; value >>= 8;
|
progress->buffer[progress->offset + 0] = value & 0xFF; value >>= 8;
|
||||||
|
@ -51,9 +52,9 @@ static void rc_runtime_progress_write_uint(rc_runtime_progress_t* progress, unsi
|
||||||
progress->offset += 4;
|
progress->offset += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned rc_runtime_progress_read_uint(rc_runtime_progress_t* progress)
|
static uint32_t rc_runtime_progress_read_uint(rc_runtime_progress_t* progress)
|
||||||
{
|
{
|
||||||
unsigned value = progress->buffer[progress->offset + 0] |
|
uint32_t value = progress->buffer[progress->offset + 0] |
|
||||||
(progress->buffer[progress->offset + 1] << 8) |
|
(progress->buffer[progress->offset + 1] << 8) |
|
||||||
(progress->buffer[progress->offset + 2] << 16) |
|
(progress->buffer[progress->offset + 2] << 16) |
|
||||||
(progress->buffer[progress->offset + 3] << 24);
|
(progress->buffer[progress->offset + 3] << 24);
|
||||||
|
@ -62,7 +63,7 @@ static unsigned rc_runtime_progress_read_uint(rc_runtime_progress_t* progress)
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rc_runtime_progress_write_md5(rc_runtime_progress_t* progress, unsigned char* md5)
|
static void rc_runtime_progress_write_md5(rc_runtime_progress_t* progress, uint8_t* md5)
|
||||||
{
|
{
|
||||||
if (progress->buffer)
|
if (progress->buffer)
|
||||||
memcpy(&progress->buffer[progress->offset], md5, 16);
|
memcpy(&progress->buffer[progress->offset], md5, 16);
|
||||||
|
@ -70,7 +71,7 @@ static void rc_runtime_progress_write_md5(rc_runtime_progress_t* progress, unsig
|
||||||
progress->offset += 16;
|
progress->offset += 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rc_runtime_progress_match_md5(rc_runtime_progress_t* progress, unsigned char* md5)
|
static int rc_runtime_progress_match_md5(rc_runtime_progress_t* progress, uint8_t* md5)
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
if (progress->buffer)
|
if (progress->buffer)
|
||||||
|
@ -81,7 +82,7 @@ static int rc_runtime_progress_match_md5(rc_runtime_progress_t* progress, unsign
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rc_runtime_progress_start_chunk(rc_runtime_progress_t* progress, unsigned chunk_id)
|
static void rc_runtime_progress_start_chunk(rc_runtime_progress_t* progress, uint32_t chunk_id)
|
||||||
{
|
{
|
||||||
rc_runtime_progress_write_uint(progress, chunk_id);
|
rc_runtime_progress_write_uint(progress, chunk_id);
|
||||||
|
|
||||||
|
@ -92,14 +93,14 @@ static void rc_runtime_progress_start_chunk(rc_runtime_progress_t* progress, uns
|
||||||
|
|
||||||
static void rc_runtime_progress_end_chunk(rc_runtime_progress_t* progress)
|
static void rc_runtime_progress_end_chunk(rc_runtime_progress_t* progress)
|
||||||
{
|
{
|
||||||
unsigned length;
|
uint32_t length;
|
||||||
int offset;
|
uint32_t offset;
|
||||||
|
|
||||||
progress->offset = (progress->offset + 3) & ~0x03; /* align to 4 byte boundary */
|
progress->offset = (progress->offset + 3) & ~0x03; /* align to 4 byte boundary */
|
||||||
|
|
||||||
if (progress->buffer) {
|
if (progress->buffer) {
|
||||||
/* ignore chunk size field when calculating chunk size */
|
/* ignore chunk size field when calculating chunk size */
|
||||||
length = (unsigned)(progress->offset - progress->chunk_size_offset - 4);
|
length = (uint32_t)(progress->offset - progress->chunk_size_offset - 4);
|
||||||
|
|
||||||
/* temporarily update the write pointer to write the chunk size field */
|
/* temporarily update the write pointer to write the chunk size field */
|
||||||
offset = progress->offset;
|
offset = progress->offset;
|
||||||
|
@ -119,7 +120,7 @@ static void rc_runtime_progress_init(rc_runtime_progress_t* progress, const rc_r
|
||||||
static int rc_runtime_progress_write_memrefs(rc_runtime_progress_t* progress)
|
static int rc_runtime_progress_write_memrefs(rc_runtime_progress_t* progress)
|
||||||
{
|
{
|
||||||
rc_memref_t* memref = progress->runtime->memrefs;
|
rc_memref_t* memref = progress->runtime->memrefs;
|
||||||
unsigned int flags = 0;
|
uint32_t flags = 0;
|
||||||
|
|
||||||
rc_runtime_progress_start_chunk(progress, RC_RUNTIME_CHUNK_MEMREFS);
|
rc_runtime_progress_start_chunk(progress, RC_RUNTIME_CHUNK_MEMREFS);
|
||||||
|
|
||||||
|
@ -150,9 +151,9 @@ static int rc_runtime_progress_write_memrefs(rc_runtime_progress_t* progress)
|
||||||
|
|
||||||
static int rc_runtime_progress_read_memrefs(rc_runtime_progress_t* progress)
|
static int rc_runtime_progress_read_memrefs(rc_runtime_progress_t* progress)
|
||||||
{
|
{
|
||||||
unsigned entries;
|
uint32_t entries;
|
||||||
unsigned address, flags, value, prior;
|
uint32_t address, flags, value, prior;
|
||||||
char size;
|
uint8_t size;
|
||||||
rc_memref_t* memref;
|
rc_memref_t* memref;
|
||||||
rc_memref_t* first_unmatched_memref = progress->runtime->memrefs;
|
rc_memref_t* first_unmatched_memref = progress->runtime->memrefs;
|
||||||
|
|
||||||
|
@ -207,7 +208,7 @@ static int rc_runtime_progress_is_indirect_memref(rc_operand_t* oper)
|
||||||
static int rc_runtime_progress_write_condset(rc_runtime_progress_t* progress, rc_condset_t* condset)
|
static int rc_runtime_progress_write_condset(rc_runtime_progress_t* progress, rc_condset_t* condset)
|
||||||
{
|
{
|
||||||
rc_condition_t* cond;
|
rc_condition_t* cond;
|
||||||
unsigned flags;
|
uint32_t flags;
|
||||||
|
|
||||||
rc_runtime_progress_write_uint(progress, condset->is_paused);
|
rc_runtime_progress_write_uint(progress, condset->is_paused);
|
||||||
|
|
||||||
|
@ -251,7 +252,7 @@ static int rc_runtime_progress_write_condset(rc_runtime_progress_t* progress, rc
|
||||||
static int rc_runtime_progress_read_condset(rc_runtime_progress_t* progress, rc_condset_t* condset)
|
static int rc_runtime_progress_read_condset(rc_runtime_progress_t* progress, rc_condset_t* condset)
|
||||||
{
|
{
|
||||||
rc_condition_t* cond;
|
rc_condition_t* cond;
|
||||||
unsigned flags;
|
uint32_t flags;
|
||||||
|
|
||||||
condset->is_paused = (char)rc_runtime_progress_read_uint(progress);
|
condset->is_paused = (char)rc_runtime_progress_read_uint(progress);
|
||||||
|
|
||||||
|
@ -286,7 +287,7 @@ static int rc_runtime_progress_read_condset(rc_runtime_progress_t* progress, rc_
|
||||||
return RC_OK;
|
return RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned rc_runtime_progress_should_serialize_variable_condset(const rc_condset_t* conditions)
|
static uint32_t rc_runtime_progress_should_serialize_variable_condset(const rc_condset_t* conditions)
|
||||||
{
|
{
|
||||||
const rc_condition_t* condition;
|
const rc_condition_t* condition;
|
||||||
|
|
||||||
|
@ -307,7 +308,7 @@ static unsigned rc_runtime_progress_should_serialize_variable_condset(const rc_c
|
||||||
|
|
||||||
static int rc_runtime_progress_write_variable(rc_runtime_progress_t* progress, const rc_value_t* variable)
|
static int rc_runtime_progress_write_variable(rc_runtime_progress_t* progress, const rc_value_t* variable)
|
||||||
{
|
{
|
||||||
unsigned flags;
|
uint32_t flags;
|
||||||
|
|
||||||
flags = rc_runtime_progress_should_serialize_variable_condset(variable->conditions);
|
flags = rc_runtime_progress_should_serialize_variable_condset(variable->conditions);
|
||||||
if (variable->value.changed)
|
if (variable->value.changed)
|
||||||
|
@ -328,7 +329,7 @@ static int rc_runtime_progress_write_variable(rc_runtime_progress_t* progress, c
|
||||||
|
|
||||||
static int rc_runtime_progress_write_variables(rc_runtime_progress_t* progress)
|
static int rc_runtime_progress_write_variables(rc_runtime_progress_t* progress)
|
||||||
{
|
{
|
||||||
unsigned count = 0;
|
uint32_t count = 0;
|
||||||
const rc_value_t* variable;
|
const rc_value_t* variable;
|
||||||
|
|
||||||
for (variable = progress->runtime->variables; variable; variable = variable->next)
|
for (variable = progress->runtime->variables; variable; variable = variable->next)
|
||||||
|
@ -341,7 +342,7 @@ static int rc_runtime_progress_write_variables(rc_runtime_progress_t* progress)
|
||||||
|
|
||||||
for (variable = progress->runtime->variables; variable; variable = variable->next)
|
for (variable = progress->runtime->variables; variable; variable = variable->next)
|
||||||
{
|
{
|
||||||
unsigned djb2 = rc_djb2(variable->name);
|
uint32_t djb2 = rc_djb2(variable->name);
|
||||||
rc_runtime_progress_write_uint(progress, djb2);
|
rc_runtime_progress_write_uint(progress, djb2);
|
||||||
|
|
||||||
rc_runtime_progress_write_variable(progress, variable);
|
rc_runtime_progress_write_variable(progress, variable);
|
||||||
|
@ -353,7 +354,7 @@ static int rc_runtime_progress_write_variables(rc_runtime_progress_t* progress)
|
||||||
|
|
||||||
static int rc_runtime_progress_read_variable(rc_runtime_progress_t* progress, rc_value_t* variable)
|
static int rc_runtime_progress_read_variable(rc_runtime_progress_t* progress, rc_value_t* variable)
|
||||||
{
|
{
|
||||||
unsigned flags = rc_runtime_progress_read_uint(progress);
|
uint32_t flags = rc_runtime_progress_read_uint(progress);
|
||||||
variable->value.changed = (flags & RC_MEMREF_FLAG_CHANGED_THIS_FRAME) ? 1 : 0;
|
variable->value.changed = (flags & RC_MEMREF_FLAG_CHANGED_THIS_FRAME) ? 1 : 0;
|
||||||
variable->value.value = rc_runtime_progress_read_uint(progress);
|
variable->value.value = rc_runtime_progress_read_uint(progress);
|
||||||
variable->value.prior = rc_runtime_progress_read_uint(progress);
|
variable->value.prior = rc_runtime_progress_read_uint(progress);
|
||||||
|
@ -375,14 +376,14 @@ static int rc_runtime_progress_read_variables(rc_runtime_progress_t* progress)
|
||||||
struct rc_pending_value_t
|
struct rc_pending_value_t
|
||||||
{
|
{
|
||||||
rc_value_t* variable;
|
rc_value_t* variable;
|
||||||
unsigned djb2;
|
uint32_t djb2;
|
||||||
};
|
};
|
||||||
struct rc_pending_value_t local_pending_variables[32];
|
struct rc_pending_value_t local_pending_variables[32];
|
||||||
struct rc_pending_value_t* pending_variables;
|
struct rc_pending_value_t* pending_variables;
|
||||||
rc_value_t* variable;
|
rc_value_t* variable;
|
||||||
unsigned count, serialized_count;
|
uint32_t count, serialized_count;
|
||||||
int result;
|
int result;
|
||||||
unsigned i;
|
uint32_t i;
|
||||||
|
|
||||||
serialized_count = rc_runtime_progress_read_uint(progress);
|
serialized_count = rc_runtime_progress_read_uint(progress);
|
||||||
if (serialized_count == 0)
|
if (serialized_count == 0)
|
||||||
|
@ -413,7 +414,7 @@ static int rc_runtime_progress_read_variables(rc_runtime_progress_t* progress)
|
||||||
|
|
||||||
result = RC_OK;
|
result = RC_OK;
|
||||||
for (; serialized_count > 0 && result == RC_OK; --serialized_count) {
|
for (; serialized_count > 0 && result == RC_OK; --serialized_count) {
|
||||||
unsigned djb2 = rc_runtime_progress_read_uint(progress);
|
uint32_t djb2 = rc_runtime_progress_read_uint(progress);
|
||||||
for (i = 0; i < count; ++i) {
|
for (i = 0; i < count; ++i) {
|
||||||
if (pending_variables[i].djb2 == djb2) {
|
if (pending_variables[i].djb2 == djb2) {
|
||||||
variable = pending_variables[i].variable;
|
variable = pending_variables[i].variable;
|
||||||
|
@ -491,7 +492,7 @@ static int rc_runtime_progress_read_trigger(rc_runtime_progress_t* progress, rc_
|
||||||
|
|
||||||
static int rc_runtime_progress_write_achievements(rc_runtime_progress_t* progress)
|
static int rc_runtime_progress_write_achievements(rc_runtime_progress_t* progress)
|
||||||
{
|
{
|
||||||
unsigned i;
|
uint32_t i;
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
|
@ -532,8 +533,8 @@ static int rc_runtime_progress_write_achievements(rc_runtime_progress_t* progres
|
||||||
|
|
||||||
static int rc_runtime_progress_read_achievement(rc_runtime_progress_t* progress)
|
static int rc_runtime_progress_read_achievement(rc_runtime_progress_t* progress)
|
||||||
{
|
{
|
||||||
unsigned id = rc_runtime_progress_read_uint(progress);
|
uint32_t id = rc_runtime_progress_read_uint(progress);
|
||||||
unsigned i;
|
uint32_t i;
|
||||||
|
|
||||||
for (i = 0; i < progress->runtime->trigger_count; ++i) {
|
for (i = 0; i < progress->runtime->trigger_count; ++i) {
|
||||||
rc_runtime_trigger_t* runtime_trigger = &progress->runtime->triggers[i];
|
rc_runtime_trigger_t* runtime_trigger = &progress->runtime->triggers[i];
|
||||||
|
@ -553,8 +554,8 @@ static int rc_runtime_progress_read_achievement(rc_runtime_progress_t* progress)
|
||||||
|
|
||||||
static int rc_runtime_progress_write_leaderboards(rc_runtime_progress_t* progress)
|
static int rc_runtime_progress_write_leaderboards(rc_runtime_progress_t* progress)
|
||||||
{
|
{
|
||||||
unsigned i;
|
uint32_t i;
|
||||||
unsigned flags;
|
uint32_t flags;
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
|
@ -610,8 +611,8 @@ static int rc_runtime_progress_write_leaderboards(rc_runtime_progress_t* progres
|
||||||
|
|
||||||
static int rc_runtime_progress_read_leaderboard(rc_runtime_progress_t* progress)
|
static int rc_runtime_progress_read_leaderboard(rc_runtime_progress_t* progress)
|
||||||
{
|
{
|
||||||
unsigned id = rc_runtime_progress_read_uint(progress);
|
uint32_t id = rc_runtime_progress_read_uint(progress);
|
||||||
unsigned i;
|
uint32_t i;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
for (i = 0; i < progress->runtime->lboard_count; ++i) {
|
for (i = 0; i < progress->runtime->lboard_count; ++i) {
|
||||||
|
@ -621,7 +622,7 @@ static int rc_runtime_progress_read_leaderboard(rc_runtime_progress_t* progress)
|
||||||
if (runtime_lboard->lboard->state == RC_TRIGGER_STATE_UNUPDATED) {
|
if (runtime_lboard->lboard->state == RC_TRIGGER_STATE_UNUPDATED) {
|
||||||
/* only update state if definition hasn't changed (md5 matches) */
|
/* only update state if definition hasn't changed (md5 matches) */
|
||||||
if (rc_runtime_progress_match_md5(progress, runtime_lboard->md5)) {
|
if (rc_runtime_progress_match_md5(progress, runtime_lboard->md5)) {
|
||||||
unsigned flags = rc_runtime_progress_read_uint(progress);
|
uint32_t flags = rc_runtime_progress_read_uint(progress);
|
||||||
|
|
||||||
result = rc_runtime_progress_read_trigger(progress, &runtime_lboard->lboard->start);
|
result = rc_runtime_progress_read_trigger(progress, &runtime_lboard->lboard->start);
|
||||||
if (result != RC_OK)
|
if (result != RC_OK)
|
||||||
|
@ -701,7 +702,7 @@ static int rc_runtime_progress_read_rich_presence(rc_runtime_progress_t* progres
|
||||||
static int rc_runtime_progress_serialize_internal(rc_runtime_progress_t* progress)
|
static int rc_runtime_progress_serialize_internal(rc_runtime_progress_t* progress)
|
||||||
{
|
{
|
||||||
md5_state_t state;
|
md5_state_t state;
|
||||||
unsigned char md5[16];
|
uint8_t md5[16];
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
rc_runtime_progress_write_uint(progress, RC_RUNTIME_MARKER);
|
rc_runtime_progress_write_uint(progress, RC_RUNTIME_MARKER);
|
||||||
|
@ -757,20 +758,20 @@ int rc_runtime_serialize_progress(void* buffer, const rc_runtime_t* runtime, lua
|
||||||
return RC_INVALID_STATE;
|
return RC_INVALID_STATE;
|
||||||
|
|
||||||
rc_runtime_progress_init(&progress, runtime, L);
|
rc_runtime_progress_init(&progress, runtime, L);
|
||||||
progress.buffer = (unsigned char*)buffer;
|
progress.buffer = (uint8_t*)buffer;
|
||||||
|
|
||||||
return rc_runtime_progress_serialize_internal(&progress);
|
return rc_runtime_progress_serialize_internal(&progress);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_runtime_deserialize_progress(rc_runtime_t* runtime, const unsigned char* serialized, lua_State* L)
|
int rc_runtime_deserialize_progress(rc_runtime_t* runtime, const uint8_t* serialized, lua_State* L)
|
||||||
{
|
{
|
||||||
rc_runtime_progress_t progress;
|
rc_runtime_progress_t progress;
|
||||||
md5_state_t state;
|
md5_state_t state;
|
||||||
unsigned char md5[16];
|
uint8_t md5[16];
|
||||||
unsigned chunk_id;
|
uint32_t chunk_id;
|
||||||
unsigned chunk_size;
|
uint32_t chunk_size;
|
||||||
unsigned next_chunk_offset;
|
uint32_t next_chunk_offset;
|
||||||
unsigned i;
|
uint32_t i;
|
||||||
int seen_rich_presence = 0;
|
int seen_rich_presence = 0;
|
||||||
int result = RC_OK;
|
int result = RC_OK;
|
||||||
|
|
||||||
|
@ -780,7 +781,7 @@ int rc_runtime_deserialize_progress(rc_runtime_t* runtime, const unsigned char*
|
||||||
}
|
}
|
||||||
|
|
||||||
rc_runtime_progress_init(&progress, runtime, L);
|
rc_runtime_progress_init(&progress, runtime, L);
|
||||||
progress.buffer = (unsigned char*)serialized;
|
progress.buffer = (uint8_t*)serialized;
|
||||||
|
|
||||||
if (rc_runtime_progress_read_uint(&progress) != RC_RUNTIME_MARKER) {
|
if (rc_runtime_progress_read_uint(&progress) != RC_RUNTIME_MARKER) {
|
||||||
rc_runtime_reset(runtime);
|
rc_runtime_reset(runtime);
|
||||||
|
|
|
@ -96,7 +96,7 @@ int rc_trigger_state_active(int state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rc_condset_is_measured_from_hitcount(const rc_condset_t* condset, unsigned measured_value)
|
static int rc_condset_is_measured_from_hitcount(const rc_condset_t* condset, uint32_t measured_value)
|
||||||
{
|
{
|
||||||
const rc_condition_t* condition;
|
const rc_condition_t* condition;
|
||||||
for (condition = condset->conditions; condition; condition = condition->next) {
|
for (condition = condset->conditions; condition; condition = condition->next) {
|
||||||
|
@ -280,6 +280,9 @@ int rc_test_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, lua_State* L)
|
||||||
}
|
}
|
||||||
|
|
||||||
void rc_reset_trigger(rc_trigger_t* self) {
|
void rc_reset_trigger(rc_trigger_t* self) {
|
||||||
|
if (!self)
|
||||||
|
return;
|
||||||
|
|
||||||
rc_reset_trigger_hitcounts(self);
|
rc_reset_trigger_hitcounts(self);
|
||||||
|
|
||||||
self->state = RC_TRIGGER_STATE_WAITING;
|
self->state = RC_TRIGGER_STATE_WAITING;
|
||||||
|
|
|
@ -255,7 +255,7 @@ int rc_evaluate_value_typed(rc_value_t* self, rc_typed_value_t* value, rc_peek_t
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc_evaluate_value(rc_value_t* self, rc_peek_t peek, void* ud, lua_State* L) {
|
int32_t rc_evaluate_value(rc_value_t* self, rc_peek_t peek, void* ud, lua_State* L) {
|
||||||
rc_typed_value_t result;
|
rc_typed_value_t result;
|
||||||
int valid = rc_evaluate_value_typed(self, &result, peek, ud, L);
|
int valid = rc_evaluate_value_typed(self, &result, peek, ud, L);
|
||||||
|
|
||||||
|
@ -304,12 +304,12 @@ void rc_init_parse_state_variables(rc_parse_state_t* parse, rc_value_t** variabl
|
||||||
*variables = 0;
|
*variables = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc_value_t* rc_alloc_helper_variable(const char* memaddr, int memaddr_len, rc_parse_state_t* parse)
|
rc_value_t* rc_alloc_helper_variable(const char* memaddr, size_t memaddr_len, rc_parse_state_t* parse)
|
||||||
{
|
{
|
||||||
rc_value_t** variables = parse->variables;
|
rc_value_t** variables = parse->variables;
|
||||||
rc_value_t* value;
|
rc_value_t* value;
|
||||||
const char* name;
|
const char* name;
|
||||||
unsigned measured_target;
|
uint32_t measured_target;
|
||||||
|
|
||||||
while ((value = *variables) != NULL) {
|
while ((value = *variables) != NULL) {
|
||||||
if (strncmp(value->name, memaddr, memaddr_len) == 0 && value->name[memaddr_len] == 0)
|
if (strncmp(value->name, memaddr, memaddr_len) == 0 && value->name[memaddr_len] == 0)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "rc_hash.h"
|
#include "rc_hash.h"
|
||||||
|
|
||||||
#include "../rcheevos/rc_compat.h"
|
#include "../rc_compat.h"
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -31,7 +31,7 @@ struct cdrom_t
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static int cdreader_get_sector(unsigned char header[16])
|
static int cdreader_get_sector(uint8_t header[16])
|
||||||
{
|
{
|
||||||
int minutes = (header[12] >> 4) * 10 + (header[12] & 0x0F);
|
int minutes = (header[12] >> 4) * 10 + (header[12] & 0x0F);
|
||||||
int seconds = (header[13] >> 4) * 10 + (header[13] & 0x0F);
|
int seconds = (header[13] >> 4) * 10 + (header[13] & 0x0F);
|
||||||
|
@ -50,11 +50,11 @@ static void cdreader_determine_sector_size(struct cdrom_t* cdrom)
|
||||||
* Then check for the presence of "CD001", which is gauranteed to be in either the
|
* Then check for the presence of "CD001", which is gauranteed to be in either the
|
||||||
* boot record or primary volume descriptor, one of which is always at sector 16.
|
* boot record or primary volume descriptor, one of which is always at sector 16.
|
||||||
*/
|
*/
|
||||||
const unsigned char sync_pattern[] = {
|
const uint8_t sync_pattern[] = {
|
||||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00
|
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned char header[32];
|
uint8_t header[32];
|
||||||
const int64_t toc_sector = 16 + cdrom->track_pregap_sectors;
|
const int64_t toc_sector = 16 + cdrom->track_pregap_sectors;
|
||||||
|
|
||||||
cdrom->sector_size = 0;
|
cdrom->sector_size = 0;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "rc_hash.h"
|
#include "rc_hash.h"
|
||||||
|
|
||||||
#include "../rcheevos/rc_compat.h"
|
#include "../rc_compat.h"
|
||||||
|
|
||||||
#include "md5.h"
|
#include "md5.h"
|
||||||
|
|
||||||
|
@ -225,11 +225,11 @@ static void rc_cd_close_track(void* track_handle)
|
||||||
rc_hash_error("no hook registered for cdreader_close_track");
|
rc_hash_error("no hook registered for cdreader_close_track");
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t rc_cd_find_file_sector(void* track_handle, const char* path, unsigned* size)
|
static uint32_t rc_cd_find_file_sector(void* track_handle, const char* path, uint32_t* size)
|
||||||
{
|
{
|
||||||
uint8_t buffer[2048], *tmp;
|
uint8_t buffer[2048], *tmp;
|
||||||
int sector;
|
int sector;
|
||||||
unsigned num_sectors = 0;
|
uint32_t num_sectors = 0;
|
||||||
size_t filename_length;
|
size_t filename_length;
|
||||||
const char* slash;
|
const char* slash;
|
||||||
|
|
||||||
|
@ -258,7 +258,7 @@ static uint32_t rc_cd_find_file_sector(void* track_handle, const char* path, uns
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
unsigned logical_block_size;
|
uint32_t logical_block_size;
|
||||||
|
|
||||||
/* find the cd information */
|
/* find the cd information */
|
||||||
if (!rc_cd_read_sector(track_handle, rc_cd_first_track_sector(track_handle) + 16, buffer, 256))
|
if (!rc_cd_read_sector(track_handle, rc_cd_first_track_sector(track_handle) + 16, buffer, 256))
|
||||||
|
@ -452,7 +452,7 @@ static int rc_hash_buffer(char hash[33], const uint8_t* buffer, size_t buffer_si
|
||||||
return rc_hash_finalize(&md5, hash);
|
return rc_hash_finalize(&md5, hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rc_hash_cd_file(md5_state_t* md5, void* track_handle, uint32_t sector, const char* name, unsigned size, const char* description)
|
static int rc_hash_cd_file(md5_state_t* md5, void* track_handle, uint32_t sector, const char* name, uint32_t size, const char* description)
|
||||||
{
|
{
|
||||||
uint8_t buffer[2048];
|
uint8_t buffer[2048];
|
||||||
size_t num_read;
|
size_t num_read;
|
||||||
|
@ -760,11 +760,11 @@ static int rc_hash_jaguar_cd(char hash[33], const char* path)
|
||||||
void* track_handle;
|
void* track_handle;
|
||||||
md5_state_t md5;
|
md5_state_t md5;
|
||||||
int byteswapped = 0;
|
int byteswapped = 0;
|
||||||
unsigned size = 0;
|
uint32_t size = 0;
|
||||||
unsigned offset = 0;
|
uint32_t offset = 0;
|
||||||
unsigned sector = 0;
|
uint32_t sector = 0;
|
||||||
unsigned remaining;
|
uint32_t remaining;
|
||||||
unsigned i;
|
uint32_t i;
|
||||||
|
|
||||||
/* Jaguar CD header is in the first sector of the first data track OF THE SECOND SESSION.
|
/* Jaguar CD header is in the first sector of the first data track OF THE SECOND SESSION.
|
||||||
* The first track must be an audio track, but may be a warning message or actual game audio */
|
* The first track must be an audio track, but may be a warning message or actual game audio */
|
||||||
|
@ -905,7 +905,7 @@ static int rc_hash_neogeo_cd(char hash[33], const char* path)
|
||||||
char buffer[1024], *ptr;
|
char buffer[1024], *ptr;
|
||||||
void* track_handle;
|
void* track_handle;
|
||||||
uint32_t sector;
|
uint32_t sector;
|
||||||
unsigned size;
|
uint32_t size;
|
||||||
md5_state_t md5;
|
md5_state_t md5;
|
||||||
|
|
||||||
track_handle = rc_cd_open_track(path, 1);
|
track_handle = rc_cd_open_track(path, 1);
|
||||||
|
@ -1091,7 +1091,7 @@ static int rc_hash_nintendo_ds(char hash[33], const char* path)
|
||||||
{
|
{
|
||||||
uint8_t header[512];
|
uint8_t header[512];
|
||||||
uint8_t* hash_buffer;
|
uint8_t* hash_buffer;
|
||||||
unsigned int hash_size, arm9_size, arm9_addr, arm7_size, arm7_addr, icon_addr;
|
uint32_t hash_size, arm9_size, arm9_addr, arm7_size, arm7_addr, icon_addr;
|
||||||
size_t num_read;
|
size_t num_read;
|
||||||
int64_t offset = 0;
|
int64_t offset = 0;
|
||||||
md5_state_t md5;
|
md5_state_t md5;
|
||||||
|
@ -1332,8 +1332,8 @@ static int rc_hash_pce_track(char hash[33], void* track_handle)
|
||||||
{
|
{
|
||||||
uint8_t buffer[2048];
|
uint8_t buffer[2048];
|
||||||
md5_state_t md5;
|
md5_state_t md5;
|
||||||
int sector, num_sectors;
|
uint32_t sector, num_sectors;
|
||||||
unsigned size;
|
uint32_t size;
|
||||||
|
|
||||||
/* the PC-Engine uses the second sector to specify boot information and program name.
|
/* the PC-Engine uses the second sector to specify boot information and program name.
|
||||||
* the string "PC Engine CD-ROM SYSTEM" should exist at 32 bytes into the sector
|
* the string "PC Engine CD-ROM SYSTEM" should exist at 32 bytes into the sector
|
||||||
|
@ -1518,7 +1518,7 @@ static int rc_hash_dreamcast(char hash[33], const char* path)
|
||||||
uint8_t buffer[256] = "";
|
uint8_t buffer[256] = "";
|
||||||
void* track_handle;
|
void* track_handle;
|
||||||
char exe_file[32] = "";
|
char exe_file[32] = "";
|
||||||
unsigned size;
|
uint32_t size;
|
||||||
uint32_t sector;
|
uint32_t sector;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
md5_state_t md5;
|
md5_state_t md5;
|
||||||
|
@ -1612,10 +1612,10 @@ static int rc_hash_dreamcast(char hash[33], const char* path)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rc_hash_find_playstation_executable(void* track_handle, const char* boot_key, const char* cdrom_prefix,
|
static int rc_hash_find_playstation_executable(void* track_handle, const char* boot_key, const char* cdrom_prefix,
|
||||||
char exe_name[], unsigned exe_name_size, unsigned* exe_size)
|
char exe_name[], uint32_t exe_name_size, uint32_t* exe_size)
|
||||||
{
|
{
|
||||||
uint8_t buffer[2048];
|
uint8_t buffer[2048];
|
||||||
unsigned size;
|
uint32_t size;
|
||||||
char* ptr;
|
char* ptr;
|
||||||
char* start;
|
char* start;
|
||||||
const size_t boot_key_len = strlen(boot_key);
|
const size_t boot_key_len = strlen(boot_key);
|
||||||
|
@ -1626,7 +1626,7 @@ static int rc_hash_find_playstation_executable(void* track_handle, const char* b
|
||||||
if (!sector)
|
if (!sector)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
size = (unsigned)rc_cd_read_sector(track_handle, sector, buffer, sizeof(buffer) - 1);
|
size = (uint32_t)rc_cd_read_sector(track_handle, sector, buffer, sizeof(buffer) - 1);
|
||||||
buffer[size] = '\0';
|
buffer[size] = '\0';
|
||||||
|
|
||||||
sector = 0;
|
sector = 0;
|
||||||
|
@ -1653,7 +1653,7 @@ static int rc_hash_find_playstation_executable(void* track_handle, const char* b
|
||||||
while (!isspace((unsigned char)*ptr) && *ptr != ';')
|
while (!isspace((unsigned char)*ptr) && *ptr != ';')
|
||||||
++ptr;
|
++ptr;
|
||||||
|
|
||||||
size = (unsigned)(ptr - start);
|
size = (uint32_t)(ptr - start);
|
||||||
if (size >= exe_name_size)
|
if (size >= exe_name_size)
|
||||||
size = exe_name_size - 1;
|
size = exe_name_size - 1;
|
||||||
|
|
||||||
|
@ -1685,7 +1685,7 @@ static int rc_hash_psx(char hash[33], const char* path)
|
||||||
char exe_name[64] = "";
|
char exe_name[64] = "";
|
||||||
void* track_handle;
|
void* track_handle;
|
||||||
uint32_t sector;
|
uint32_t sector;
|
||||||
unsigned size;
|
uint32_t size;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
md5_state_t md5;
|
md5_state_t md5;
|
||||||
|
|
||||||
|
@ -1749,7 +1749,7 @@ static int rc_hash_ps2(char hash[33], const char* path)
|
||||||
char exe_name[64] = "";
|
char exe_name[64] = "";
|
||||||
void* track_handle;
|
void* track_handle;
|
||||||
uint32_t sector;
|
uint32_t sector;
|
||||||
unsigned size;
|
uint32_t size;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
md5_state_t md5;
|
md5_state_t md5;
|
||||||
|
|
||||||
|
@ -1797,7 +1797,7 @@ static int rc_hash_psp(char hash[33], const char* path)
|
||||||
{
|
{
|
||||||
void* track_handle;
|
void* track_handle;
|
||||||
uint32_t sector;
|
uint32_t sector;
|
||||||
unsigned size;
|
uint32_t size;
|
||||||
md5_state_t md5;
|
md5_state_t md5;
|
||||||
|
|
||||||
track_handle = rc_cd_open_track(path, 1);
|
track_handle = rc_cd_open_track(path, 1);
|
||||||
|
@ -1868,6 +1868,21 @@ static int rc_hash_sega_cd(char hash[33], const char* path)
|
||||||
return rc_hash_buffer(hash, buffer, sizeof(buffer));
|
return rc_hash_buffer(hash, buffer, sizeof(buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rc_hash_scv(char hash[33], const uint8_t* buffer, size_t buffer_size)
|
||||||
|
{
|
||||||
|
/* if the file contains a header, ignore it */
|
||||||
|
/* https://gitlab.com/MaaaX-EmuSCV/libretro-emuscv/-/blob/master/readme.txt#L211 */
|
||||||
|
if (memcmp(buffer, "EmuSCV", 6) == 0)
|
||||||
|
{
|
||||||
|
rc_hash_verbose("Ignoring SCV header");
|
||||||
|
|
||||||
|
buffer += 32;
|
||||||
|
buffer_size -= 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc_hash_buffer(hash, buffer, buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
static int rc_hash_snes(char hash[33], const uint8_t* buffer, size_t buffer_size)
|
static int rc_hash_snes(char hash[33], const uint8_t* buffer, size_t buffer_size)
|
||||||
{
|
{
|
||||||
/* if the file contains a header, ignore it */
|
/* if the file contains a header, ignore it */
|
||||||
|
@ -2028,6 +2043,9 @@ int rc_hash_generate_from_buffer(char hash[33], int console_id, const uint8_t* b
|
||||||
case RC_CONSOLE_PC_ENGINE: /* NOTE: does not support PCEngine CD */
|
case RC_CONSOLE_PC_ENGINE: /* NOTE: does not support PCEngine CD */
|
||||||
return rc_hash_pce(hash, buffer, buffer_size);
|
return rc_hash_pce(hash, buffer, buffer_size);
|
||||||
|
|
||||||
|
case RC_CONSOLE_SUPER_CASSETTEVISION:
|
||||||
|
return rc_hash_scv(hash, buffer, buffer_size);
|
||||||
|
|
||||||
case RC_CONSOLE_SUPER_NINTENDO:
|
case RC_CONSOLE_SUPER_NINTENDO:
|
||||||
return rc_hash_snes(hash, buffer, buffer_size);
|
return rc_hash_snes(hash, buffer, buffer_size);
|
||||||
|
|
||||||
|
@ -2324,6 +2342,7 @@ int rc_hash_generate_from_file(char hash[33], int console_id, const char* path)
|
||||||
case RC_CONSOLE_ATARI_LYNX:
|
case RC_CONSOLE_ATARI_LYNX:
|
||||||
case RC_CONSOLE_NINTENDO:
|
case RC_CONSOLE_NINTENDO:
|
||||||
case RC_CONSOLE_PC_ENGINE:
|
case RC_CONSOLE_PC_ENGINE:
|
||||||
|
case RC_CONSOLE_SUPER_CASSETTEVISION:
|
||||||
case RC_CONSOLE_SUPER_NINTENDO:
|
case RC_CONSOLE_SUPER_NINTENDO:
|
||||||
/* additional logic whole-file hash - buffer then call rc_hash_generate_from_buffer */
|
/* additional logic whole-file hash - buffer then call rc_hash_generate_from_buffer */
|
||||||
return rc_hash_buffered_file(hash, console_id, path);
|
return rc_hash_buffered_file(hash, console_id, path);
|
||||||
|
@ -2542,7 +2561,7 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
|
||||||
}
|
}
|
||||||
|
|
||||||
/* bin is associated with MegaDrive, Sega32X, Atari 2600, Watara Supervision, MegaDuck,
|
/* bin is associated with MegaDrive, Sega32X, Atari 2600, Watara Supervision, MegaDuck,
|
||||||
* Fairchild Channel F, Arcadia 2001, and Interton VC 4000.
|
* Fairchild Channel F, Arcadia 2001, Interton VC 4000, and Super Cassette Vision.
|
||||||
* Since they all use the same hashing algorithm, only specify one of them */
|
* Since they all use the same hashing algorithm, only specify one of them */
|
||||||
iterator->consoles[0] = RC_CONSOLE_MEGA_DRIVE;
|
iterator->consoles[0] = RC_CONSOLE_MEGA_DRIVE;
|
||||||
}
|
}
|
||||||
|
@ -2572,9 +2591,10 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
|
||||||
iterator->consoles[1] = RC_CONSOLE_PLAYSTATION_2;
|
iterator->consoles[1] = RC_CONSOLE_PLAYSTATION_2;
|
||||||
iterator->consoles[2] = RC_CONSOLE_DREAMCAST;
|
iterator->consoles[2] = RC_CONSOLE_DREAMCAST;
|
||||||
iterator->consoles[3] = RC_CONSOLE_SEGA_CD; /* ASSERT: handles both Sega CD and Saturn */
|
iterator->consoles[3] = RC_CONSOLE_SEGA_CD; /* ASSERT: handles both Sega CD and Saturn */
|
||||||
iterator->consoles[4] = RC_CONSOLE_PC_ENGINE_CD;
|
iterator->consoles[4] = RC_CONSOLE_PSP;
|
||||||
iterator->consoles[5] = RC_CONSOLE_3DO;
|
iterator->consoles[5] = RC_CONSOLE_PC_ENGINE_CD;
|
||||||
iterator->consoles[6] = RC_CONSOLE_PCFX;
|
iterator->consoles[6] = RC_CONSOLE_3DO;
|
||||||
|
iterator->consoles[7] = RC_CONSOLE_PCFX;
|
||||||
need_path = 1;
|
need_path = 1;
|
||||||
}
|
}
|
||||||
else if (rc_path_compare_extension(ext, "col"))
|
else if (rc_path_compare_extension(ext, "col"))
|
||||||
|
@ -2589,6 +2609,10 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
|
||||||
{
|
{
|
||||||
iterator->consoles[0] = RC_CONSOLE_FAIRCHILD_CHANNEL_F;
|
iterator->consoles[0] = RC_CONSOLE_FAIRCHILD_CHANNEL_F;
|
||||||
}
|
}
|
||||||
|
else if (rc_path_compare_extension(ext, "cart"))
|
||||||
|
{
|
||||||
|
iterator->consoles[0] = RC_CONSOLE_SUPER_CASSETTEVISION;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'd':
|
case 'd':
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "rc_url.h"
|
#include "rc_url.h"
|
||||||
|
|
||||||
#include "../rcheevos/rc_compat.h"
|
#include "../rc_compat.h"
|
||||||
#include "../rhash/md5.h"
|
#include "../rhash/md5.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
Loading…
Reference in a new issue