gemba 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/THIRD_PARTY_NOTICES +37 -2
- data/assets/placeholder_boxart.png +0 -0
- data/bin/gemba +2 -2
- data/ext/gemba/extconf.rb +23 -1
- data/ext/gemba/gemba_ext.c +436 -2
- data/ext/gemba/gemba_ext.h +2 -0
- data/gemba.gemspec +5 -3
- data/lib/gemba/achievements/achievement.rb +23 -0
- data/lib/gemba/achievements/backend.rb +186 -0
- data/lib/gemba/achievements/cache.rb +70 -0
- data/lib/gemba/achievements/credentials_presenter.rb +142 -0
- data/lib/gemba/achievements/fake_backend.rb +205 -0
- data/lib/gemba/achievements/null_backend.rb +11 -0
- data/lib/gemba/achievements/offline_backend.rb +168 -0
- data/lib/gemba/achievements/retro_achievements/backend.rb +453 -0
- data/lib/gemba/achievements/retro_achievements/cli_sync_requester.rb +64 -0
- data/lib/gemba/achievements/retro_achievements/ping_worker.rb +27 -0
- data/lib/gemba/achievements.rb +19 -0
- data/lib/gemba/achievements_window.rb +556 -0
- data/lib/gemba/app_controller.rb +1015 -0
- data/lib/gemba/bios.rb +54 -0
- data/lib/gemba/boxart_fetcher/libretro_backend.rb +39 -0
- data/lib/gemba/boxart_fetcher/null_backend.rb +12 -0
- data/lib/gemba/boxart_fetcher.rb +79 -0
- data/lib/gemba/bus_emitter.rb +13 -0
- data/lib/gemba/child_window.rb +24 -1
- data/lib/gemba/cli/commands/config_cmd.rb +83 -0
- data/lib/gemba/cli/commands/decode.rb +154 -0
- data/lib/gemba/cli/commands/patch.rb +78 -0
- data/lib/gemba/cli/commands/play.rb +78 -0
- data/lib/gemba/cli/commands/record.rb +114 -0
- data/lib/gemba/cli/commands/replay.rb +161 -0
- data/lib/gemba/cli/commands/retro_achievements.rb +213 -0
- data/lib/gemba/cli/commands/version.rb +22 -0
- data/lib/gemba/cli.rb +52 -364
- data/lib/gemba/config.rb +134 -1
- data/lib/gemba/data/gb_games.json +1 -0
- data/lib/gemba/data/gb_md5.json +1 -0
- data/lib/gemba/data/gba_games.json +1 -0
- data/lib/gemba/data/gba_md5.json +1 -0
- data/lib/gemba/data/gbc_games.json +1 -0
- data/lib/gemba/data/gbc_md5.json +1 -0
- data/lib/gemba/emulator_frame.rb +1060 -0
- data/lib/gemba/event_bus.rb +48 -0
- data/lib/gemba/frame_stack.rb +60 -0
- data/lib/gemba/game_index.rb +84 -0
- data/lib/gemba/game_picker_frame.rb +268 -0
- data/lib/gemba/gamepad_map.rb +103 -0
- data/lib/gemba/headless.rb +6 -5
- data/lib/gemba/headless_player.rb +33 -3
- data/lib/gemba/help_window.rb +61 -0
- data/lib/gemba/hotkey_map.rb +3 -1
- data/lib/gemba/input_recorder.rb +107 -0
- data/lib/gemba/input_replayer.rb +119 -0
- data/lib/gemba/keyboard_map.rb +90 -0
- data/lib/gemba/locales/en.yml +97 -5
- data/lib/gemba/locales/ja.yml +97 -5
- data/lib/gemba/main_window.rb +56 -0
- data/lib/gemba/modal_stack.rb +81 -0
- data/lib/gemba/patcher_window.rb +223 -0
- data/lib/gemba/platform/gb.rb +21 -0
- data/lib/gemba/platform/gba.rb +21 -0
- data/lib/gemba/platform/gbc.rb +23 -0
- data/lib/gemba/platform.rb +20 -0
- data/lib/gemba/platform_open.rb +19 -0
- data/lib/gemba/recorder.rb +4 -3
- data/lib/gemba/replay_player.rb +691 -0
- data/lib/gemba/rom_info.rb +57 -0
- data/lib/gemba/rom_info_window.rb +16 -3
- data/lib/gemba/rom_library.rb +106 -0
- data/lib/gemba/rom_overrides.rb +47 -0
- data/lib/gemba/rom_patcher/bps.rb +161 -0
- data/lib/gemba/rom_patcher/ips.rb +101 -0
- data/lib/gemba/rom_patcher/ups.rb +118 -0
- data/lib/gemba/rom_patcher.rb +109 -0
- data/lib/gemba/{rom_loader.rb → rom_resolver.rb} +7 -6
- data/lib/gemba/runtime.rb +59 -26
- data/lib/gemba/save_state_manager.rb +4 -7
- data/lib/gemba/save_state_picker.rb +17 -4
- data/lib/gemba/session_logger.rb +64 -0
- data/lib/gemba/settings/audio_tab.rb +77 -0
- data/lib/gemba/settings/gamepad_tab.rb +351 -0
- data/lib/gemba/settings/hotkeys_tab.rb +259 -0
- data/lib/gemba/settings/paths.rb +11 -0
- data/lib/gemba/settings/recording_tab.rb +83 -0
- data/lib/gemba/settings/save_states_tab.rb +91 -0
- data/lib/gemba/settings/system_tab.rb +362 -0
- data/lib/gemba/settings/video_tab.rb +318 -0
- data/lib/gemba/settings_window.rb +162 -1036
- data/lib/gemba/version.rb +1 -1
- data/lib/gemba/virtual_keyboard.rb +19 -0
- data/lib/gemba.rb +2 -12
- data/test/achievements_window/test_bulk_sync.rb +218 -0
- data/test/achievements_window/test_bus_events.rb +125 -0
- data/test/achievements_window/test_close_confirmation.rb +201 -0
- data/test/achievements_window/test_initial_state.rb +164 -0
- data/test/achievements_window/test_sorting.rb +227 -0
- data/test/achievements_window/test_tree_rendering.rb +133 -0
- data/test/fixtures/fake_bios.bin +0 -0
- data/test/fixtures/pong.gba +0 -0
- data/test/fixtures/test.gb +0 -0
- data/test/fixtures/test.gbc +0 -0
- data/test/fixtures/test_quicksave.ss +0 -0
- data/test/screenshots/no_focus.png +0 -0
- data/test/shared/teek_test_worker.rb +17 -1
- data/test/shared/tk_test_helper.rb +91 -4
- data/test/support/achievements_window_helpers.rb +18 -0
- data/test/support/fake_core.rb +25 -0
- data/test/support/fake_ra_runtime.rb +74 -0
- data/test/support/fake_requester.rb +68 -0
- data/test/support/player_helpers.rb +20 -5
- data/test/test_achievement.rb +32 -0
- data/test/{test_player.rb → test_app_controller.rb} +353 -85
- data/test/test_bios.rb +123 -0
- data/test/test_boxart_fetcher.rb +150 -0
- data/test/test_cli.rb +17 -265
- data/test/test_cli_config.rb +64 -0
- data/test/test_cli_decode.rb +97 -0
- data/test/test_cli_patch.rb +58 -0
- data/test/test_cli_play.rb +213 -0
- data/test/test_cli_ra.rb +175 -0
- data/test/test_cli_record.rb +69 -0
- data/test/test_cli_replay.rb +72 -0
- data/test/test_cli_sync_requester.rb +152 -0
- data/test/test_cli_version.rb +27 -0
- data/test/test_config.rb +2 -3
- data/test/test_config_ra.rb +69 -0
- data/test/test_core.rb +62 -1
- data/test/test_credentials_presenter.rb +192 -0
- data/test/test_event_bus.rb +100 -0
- data/test/test_fake_backend_achievements.rb +130 -0
- data/test/test_fake_backend_auth.rb +68 -0
- data/test/test_game_index.rb +77 -0
- data/test/test_game_picker_frame.rb +310 -0
- data/test/test_gamepad_map.rb +1 -3
- data/test/test_headless_player.rb +17 -3
- data/test/test_help_window.rb +82 -0
- data/test/test_hotkey_map.rb +22 -1
- data/test/test_input_recorder.rb +179 -0
- data/test/test_input_replay_determinism.rb +113 -0
- data/test/test_input_replayer.rb +162 -0
- data/test/test_keyboard_map.rb +1 -3
- data/test/test_libretro_backend.rb +41 -0
- data/test/test_locale.rb +1 -1
- data/test/test_logging.rb +123 -0
- data/test/test_null_backend.rb +42 -0
- data/test/test_offline_backend.rb +116 -0
- data/test/test_overlay_renderer.rb +1 -1
- data/test/test_platform.rb +149 -0
- data/test/test_ra_backend.rb +313 -0
- data/test/test_ra_backend_unlock_gate.rb +56 -0
- data/test/test_recorder.rb +0 -3
- data/test/test_replay_player.rb +316 -0
- data/test/test_rom_info.rb +149 -0
- data/test/test_rom_overrides.rb +86 -0
- data/test/test_rom_patcher.rb +382 -0
- data/test/{test_rom_loader.rb → test_rom_resolver.rb} +25 -26
- data/test/test_save_state_manager.rb +2 -4
- data/test/test_settings_audio.rb +107 -0
- data/test/test_settings_hotkeys.rb +83 -66
- data/test/test_settings_recording.rb +49 -0
- data/test/test_settings_save_states.rb +97 -0
- data/test/test_settings_system.rb +133 -0
- data/test/test_settings_video.rb +450 -0
- data/test/test_settings_window.rb +76 -507
- data/test/test_tip_service.rb +6 -6
- data/test/test_toast_overlay.rb +1 -1
- data/test/test_virtual_events.rb +156 -0
- data/test/test_virtual_keyboard.rb +1 -1
- data/vendor/rcheevos/CHANGELOG.md +495 -0
- data/vendor/rcheevos/LICENSE +21 -0
- data/vendor/rcheevos/Package.swift +33 -0
- data/vendor/rcheevos/README.md +67 -0
- data/vendor/rcheevos/include/module.modulemap +70 -0
- data/vendor/rcheevos/include/rc_api_editor.h +296 -0
- data/vendor/rcheevos/include/rc_api_info.h +280 -0
- data/vendor/rcheevos/include/rc_api_request.h +77 -0
- data/vendor/rcheevos/include/rc_api_runtime.h +417 -0
- data/vendor/rcheevos/include/rc_api_user.h +262 -0
- data/vendor/rcheevos/include/rc_client.h +877 -0
- data/vendor/rcheevos/include/rc_client_raintegration.h +101 -0
- data/vendor/rcheevos/include/rc_consoles.h +138 -0
- data/vendor/rcheevos/include/rc_error.h +59 -0
- data/vendor/rcheevos/include/rc_export.h +100 -0
- data/vendor/rcheevos/include/rc_hash.h +200 -0
- data/vendor/rcheevos/include/rc_runtime.h +148 -0
- data/vendor/rcheevos/include/rc_runtime_types.h +452 -0
- data/vendor/rcheevos/include/rc_util.h +51 -0
- data/vendor/rcheevos/include/rcheevos.h +8 -0
- data/vendor/rcheevos/src/rapi/rc_api_common.c +1379 -0
- data/vendor/rcheevos/src/rapi/rc_api_common.h +88 -0
- data/vendor/rcheevos/src/rapi/rc_api_editor.c +625 -0
- data/vendor/rcheevos/src/rapi/rc_api_info.c +587 -0
- data/vendor/rcheevos/src/rapi/rc_api_runtime.c +901 -0
- data/vendor/rcheevos/src/rapi/rc_api_user.c +483 -0
- data/vendor/rcheevos/src/rc_client.c +6941 -0
- data/vendor/rcheevos/src/rc_client_external.c +281 -0
- data/vendor/rcheevos/src/rc_client_external.h +177 -0
- data/vendor/rcheevos/src/rc_client_external_versions.h +171 -0
- data/vendor/rcheevos/src/rc_client_internal.h +409 -0
- data/vendor/rcheevos/src/rc_client_raintegration.c +566 -0
- data/vendor/rcheevos/src/rc_client_raintegration_internal.h +61 -0
- data/vendor/rcheevos/src/rc_client_types.natvis +396 -0
- data/vendor/rcheevos/src/rc_compat.c +251 -0
- data/vendor/rcheevos/src/rc_compat.h +121 -0
- data/vendor/rcheevos/src/rc_libretro.c +915 -0
- data/vendor/rcheevos/src/rc_libretro.h +98 -0
- data/vendor/rcheevos/src/rc_util.c +199 -0
- data/vendor/rcheevos/src/rc_version.c +11 -0
- data/vendor/rcheevos/src/rc_version.h +32 -0
- data/vendor/rcheevos/src/rcheevos/alloc.c +312 -0
- data/vendor/rcheevos/src/rcheevos/condition.c +754 -0
- data/vendor/rcheevos/src/rcheevos/condset.c +777 -0
- data/vendor/rcheevos/src/rcheevos/consoleinfo.c +1215 -0
- data/vendor/rcheevos/src/rcheevos/format.c +330 -0
- data/vendor/rcheevos/src/rcheevos/lboard.c +287 -0
- data/vendor/rcheevos/src/rcheevos/memref.c +805 -0
- data/vendor/rcheevos/src/rcheevos/operand.c +607 -0
- data/vendor/rcheevos/src/rcheevos/rc_internal.h +390 -0
- data/vendor/rcheevos/src/rcheevos/rc_runtime_types.natvis +541 -0
- data/vendor/rcheevos/src/rcheevos/rc_validate.c +1406 -0
- data/vendor/rcheevos/src/rcheevos/rc_validate.h +18 -0
- data/vendor/rcheevos/src/rcheevos/richpresence.c +922 -0
- data/vendor/rcheevos/src/rcheevos/runtime.c +852 -0
- data/vendor/rcheevos/src/rcheevos/runtime_progress.c +1073 -0
- data/vendor/rcheevos/src/rcheevos/trigger.c +344 -0
- data/vendor/rcheevos/src/rcheevos/value.c +935 -0
- data/vendor/rcheevos/src/rhash/aes.c +480 -0
- data/vendor/rcheevos/src/rhash/aes.h +49 -0
- data/vendor/rcheevos/src/rhash/cdreader.c +838 -0
- data/vendor/rcheevos/src/rhash/hash.c +1402 -0
- data/vendor/rcheevos/src/rhash/hash_disc.c +1340 -0
- data/vendor/rcheevos/src/rhash/hash_encrypted.c +566 -0
- data/vendor/rcheevos/src/rhash/hash_rom.c +426 -0
- data/vendor/rcheevos/src/rhash/hash_zip.c +460 -0
- data/vendor/rcheevos/src/rhash/md5.c +382 -0
- data/vendor/rcheevos/src/rhash/md5.h +91 -0
- data/vendor/rcheevos/src/rhash/rc_hash_internal.h +116 -0
- data/vendor/rcheevos/test/libretro.h +205 -0
- data/vendor/rcheevos/test/rapi/test_rc_api_common.c +941 -0
- data/vendor/rcheevos/test/rapi/test_rc_api_editor.c +931 -0
- data/vendor/rcheevos/test/rapi/test_rc_api_info.c +545 -0
- data/vendor/rcheevos/test/rapi/test_rc_api_runtime.c +2213 -0
- data/vendor/rcheevos/test/rapi/test_rc_api_user.c +998 -0
- data/vendor/rcheevos/test/rcheevos/mock_memory.h +32 -0
- data/vendor/rcheevos/test/rcheevos/test_condition.c +570 -0
- data/vendor/rcheevos/test/rcheevos/test_condset.c +5170 -0
- data/vendor/rcheevos/test/rcheevos/test_consoleinfo.c +203 -0
- data/vendor/rcheevos/test/rcheevos/test_format.c +112 -0
- data/vendor/rcheevos/test/rcheevos/test_lboard.c +746 -0
- data/vendor/rcheevos/test/rcheevos/test_memref.c +520 -0
- data/vendor/rcheevos/test/rcheevos/test_operand.c +692 -0
- data/vendor/rcheevos/test/rcheevos/test_rc_validate.c +502 -0
- data/vendor/rcheevos/test/rcheevos/test_richpresence.c +1564 -0
- data/vendor/rcheevos/test/rcheevos/test_runtime.c +1667 -0
- data/vendor/rcheevos/test/rcheevos/test_runtime_progress.c +1821 -0
- data/vendor/rcheevos/test/rcheevos/test_timing.c +166 -0
- data/vendor/rcheevos/test/rcheevos/test_trigger.c +2521 -0
- data/vendor/rcheevos/test/rcheevos/test_value.c +870 -0
- data/vendor/rcheevos/test/rcheevos-test.sln +46 -0
- data/vendor/rcheevos/test/rcheevos-test.vcxproj +239 -0
- data/vendor/rcheevos/test/rcheevos-test.vcxproj.filters +335 -0
- data/vendor/rcheevos/test/rhash/data.c +657 -0
- data/vendor/rcheevos/test/rhash/data.h +32 -0
- data/vendor/rcheevos/test/rhash/mock_filereader.c +236 -0
- data/vendor/rcheevos/test/rhash/mock_filereader.h +31 -0
- data/vendor/rcheevos/test/rhash/test_cdreader.c +920 -0
- data/vendor/rcheevos/test/rhash/test_hash.c +310 -0
- data/vendor/rcheevos/test/rhash/test_hash_disc.c +1450 -0
- data/vendor/rcheevos/test/rhash/test_hash_rom.c +899 -0
- data/vendor/rcheevos/test/rhash/test_hash_zip.c +551 -0
- data/vendor/rcheevos/test/test.c +113 -0
- data/vendor/rcheevos/test/test_framework.h +205 -0
- data/vendor/rcheevos/test/test_rc_client.c +10509 -0
- data/vendor/rcheevos/test/test_rc_client_external.c +2197 -0
- data/vendor/rcheevos/test/test_rc_client_raintegration.c +441 -0
- data/vendor/rcheevos/test/test_rc_libretro.c +952 -0
- data/vendor/rcheevos/test/test_types.natvis +9 -0
- data/vendor/rcheevos/validator/validator.c +658 -0
- data/vendor/rcheevos/validator/validator.vcxproj +152 -0
- data/vendor/rcheevos/validator/validator.vcxproj.filters +82 -0
- metadata +274 -11
- data/lib/gemba/input_mappings.rb +0 -214
- data/lib/gemba/player.rb +0 -1525
|
@@ -0,0 +1,625 @@
|
|
|
1
|
+
#include "rc_api_editor.h"
|
|
2
|
+
#include "rc_api_common.h"
|
|
3
|
+
#include "rc_api_runtime.h"
|
|
4
|
+
|
|
5
|
+
#include "../rc_compat.h"
|
|
6
|
+
#include "../rhash/md5.h"
|
|
7
|
+
|
|
8
|
+
#include <stdlib.h>
|
|
9
|
+
#include <string.h>
|
|
10
|
+
|
|
11
|
+
/* --- Fetch Code Notes --- */
|
|
12
|
+
|
|
13
|
+
int rc_api_init_fetch_code_notes_request(rc_api_request_t* request, const rc_api_fetch_code_notes_request_t* api_params) {
|
|
14
|
+
return rc_api_init_fetch_code_notes_request_hosted(request, api_params, &g_host);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
int rc_api_init_fetch_code_notes_request_hosted(rc_api_request_t* request,
|
|
18
|
+
const rc_api_fetch_code_notes_request_t* api_params,
|
|
19
|
+
const rc_api_host_t* host) {
|
|
20
|
+
rc_api_url_builder_t builder;
|
|
21
|
+
|
|
22
|
+
rc_api_url_build_dorequest_url(request, host);
|
|
23
|
+
|
|
24
|
+
if (api_params->game_id == 0)
|
|
25
|
+
return RC_INVALID_STATE;
|
|
26
|
+
|
|
27
|
+
rc_url_builder_init(&builder, &request->buffer, 48);
|
|
28
|
+
rc_url_builder_append_str_param(&builder, "r", "codenotes2");
|
|
29
|
+
rc_url_builder_append_unum_param(&builder, "g", api_params->game_id);
|
|
30
|
+
|
|
31
|
+
request->post_data = rc_url_builder_finalize(&builder);
|
|
32
|
+
request->content_type = RC_CONTENT_TYPE_URLENCODED;
|
|
33
|
+
|
|
34
|
+
return builder.result;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
int rc_api_process_fetch_code_notes_response(rc_api_fetch_code_notes_response_t* response, const char* server_response) {
|
|
38
|
+
rc_api_server_response_t response_obj;
|
|
39
|
+
|
|
40
|
+
memset(&response_obj, 0, sizeof(response_obj));
|
|
41
|
+
response_obj.body = server_response;
|
|
42
|
+
response_obj.body_length = rc_json_get_object_string_length(server_response);
|
|
43
|
+
|
|
44
|
+
return rc_api_process_fetch_code_notes_server_response(response, &response_obj);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
int rc_api_process_fetch_code_notes_server_response(rc_api_fetch_code_notes_response_t* response, const rc_api_server_response_t* server_response) {
|
|
48
|
+
rc_json_field_t array_field;
|
|
49
|
+
rc_json_iterator_t iterator;
|
|
50
|
+
rc_api_code_note_t* note;
|
|
51
|
+
const char* address_str;
|
|
52
|
+
const char* last_author = "";
|
|
53
|
+
size_t last_author_len = 0;
|
|
54
|
+
size_t len;
|
|
55
|
+
int result;
|
|
56
|
+
|
|
57
|
+
rc_json_field_t fields[] = {
|
|
58
|
+
RC_JSON_NEW_FIELD("Success"),
|
|
59
|
+
RC_JSON_NEW_FIELD("Error"),
|
|
60
|
+
RC_JSON_NEW_FIELD("CodeNotes")
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
rc_json_field_t note_fields[] = {
|
|
64
|
+
RC_JSON_NEW_FIELD("Address"),
|
|
65
|
+
RC_JSON_NEW_FIELD("User"),
|
|
66
|
+
RC_JSON_NEW_FIELD("Note")
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
memset(response, 0, sizeof(*response));
|
|
70
|
+
rc_buffer_init(&response->response.buffer);
|
|
71
|
+
|
|
72
|
+
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
|
73
|
+
if (result != RC_OK || !response->response.succeeded)
|
|
74
|
+
return result;
|
|
75
|
+
|
|
76
|
+
if (!rc_json_get_required_array(&response->num_notes, &array_field, &response->response, &fields[2], "CodeNotes"))
|
|
77
|
+
return RC_MISSING_VALUE;
|
|
78
|
+
|
|
79
|
+
if (response->num_notes) {
|
|
80
|
+
response->notes = (rc_api_code_note_t*)rc_buffer_alloc(&response->response.buffer, response->num_notes * sizeof(rc_api_code_note_t));
|
|
81
|
+
if (!response->notes)
|
|
82
|
+
return RC_OUT_OF_MEMORY;
|
|
83
|
+
|
|
84
|
+
memset(&iterator, 0, sizeof(iterator));
|
|
85
|
+
iterator.json = array_field.value_start;
|
|
86
|
+
iterator.end = array_field.value_end;
|
|
87
|
+
|
|
88
|
+
note = response->notes;
|
|
89
|
+
while (rc_json_get_array_entry_object(note_fields, sizeof(note_fields) / sizeof(note_fields[0]), &iterator)) {
|
|
90
|
+
/* an empty note represents a record that was deleted on the server */
|
|
91
|
+
/* a note set to '' also represents a deleted note (remnant of a bug) */
|
|
92
|
+
/* NOTE: len will include the quotes */
|
|
93
|
+
if (note_fields[2].value_start) {
|
|
94
|
+
len = note_fields[2].value_end - note_fields[2].value_start;
|
|
95
|
+
if (len == 2 || (len == 4 && note_fields[2].value_start[1] == '\'' && note_fields[2].value_start[2] == '\'')) {
|
|
96
|
+
--response->num_notes;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (!rc_json_get_required_string(&address_str, &response->response, ¬e_fields[0], "Address"))
|
|
102
|
+
return RC_MISSING_VALUE;
|
|
103
|
+
note->address = (uint32_t)strtoul(address_str, NULL, 16);
|
|
104
|
+
if (!rc_json_get_required_string(¬e->note, &response->response, ¬e_fields[2], "Note"))
|
|
105
|
+
return RC_MISSING_VALUE;
|
|
106
|
+
|
|
107
|
+
len = note_fields[1].value_end - note_fields[1].value_start;
|
|
108
|
+
if (len == last_author_len && memcmp(note_fields[1].value_start, last_author, len) == 0) {
|
|
109
|
+
note->author = last_author;
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
if (!rc_json_get_required_string(¬e->author, &response->response, ¬e_fields[1], "User"))
|
|
113
|
+
return RC_MISSING_VALUE;
|
|
114
|
+
|
|
115
|
+
if (note->author == NULL) {
|
|
116
|
+
/* ensure we don't pass NULL out to client */
|
|
117
|
+
last_author = note->author = "";
|
|
118
|
+
last_author_len = 0;
|
|
119
|
+
} else {
|
|
120
|
+
last_author = note->author;
|
|
121
|
+
last_author_len = len;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
++note;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return RC_OK;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
void rc_api_destroy_fetch_code_notes_response(rc_api_fetch_code_notes_response_t* response) {
|
|
133
|
+
rc_buffer_destroy(&response->response.buffer);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/* --- Update Code Note --- */
|
|
137
|
+
|
|
138
|
+
int rc_api_init_update_code_note_request(rc_api_request_t* request, const rc_api_update_code_note_request_t* api_params) {
|
|
139
|
+
return rc_api_init_update_code_note_request_hosted(request, api_params, &g_host);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
int rc_api_init_update_code_note_request_hosted(rc_api_request_t* request,
|
|
143
|
+
const rc_api_update_code_note_request_t* api_params,
|
|
144
|
+
const rc_api_host_t* host) {
|
|
145
|
+
rc_api_url_builder_t builder;
|
|
146
|
+
|
|
147
|
+
rc_api_url_build_dorequest_url(request, host);
|
|
148
|
+
|
|
149
|
+
if (api_params->game_id == 0)
|
|
150
|
+
return RC_INVALID_STATE;
|
|
151
|
+
|
|
152
|
+
rc_url_builder_init(&builder, &request->buffer, 128);
|
|
153
|
+
if (!rc_api_url_build_dorequest(&builder, "submitcodenote", api_params->username, api_params->api_token))
|
|
154
|
+
return builder.result;
|
|
155
|
+
|
|
156
|
+
rc_url_builder_append_unum_param(&builder, "g", api_params->game_id);
|
|
157
|
+
rc_url_builder_append_unum_param(&builder, "m", api_params->address);
|
|
158
|
+
|
|
159
|
+
if (api_params->note && *api_params->note)
|
|
160
|
+
rc_url_builder_append_str_param(&builder, "n", api_params->note);
|
|
161
|
+
|
|
162
|
+
request->post_data = rc_url_builder_finalize(&builder);
|
|
163
|
+
request->content_type = RC_CONTENT_TYPE_URLENCODED;
|
|
164
|
+
|
|
165
|
+
return builder.result;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
int rc_api_process_update_code_note_response(rc_api_update_code_note_response_t* response, const char* server_response) {
|
|
169
|
+
rc_api_server_response_t response_obj;
|
|
170
|
+
|
|
171
|
+
memset(&response_obj, 0, sizeof(response_obj));
|
|
172
|
+
response_obj.body = server_response;
|
|
173
|
+
response_obj.body_length = rc_json_get_object_string_length(server_response);
|
|
174
|
+
|
|
175
|
+
return rc_api_process_update_code_note_server_response(response, &response_obj);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
int rc_api_process_update_code_note_server_response(rc_api_update_code_note_response_t* response, const rc_api_server_response_t* server_response) {
|
|
179
|
+
int result;
|
|
180
|
+
|
|
181
|
+
rc_json_field_t fields[] = {
|
|
182
|
+
RC_JSON_NEW_FIELD("Success"),
|
|
183
|
+
RC_JSON_NEW_FIELD("Error")
|
|
184
|
+
/* unused fields
|
|
185
|
+
RC_JSON_NEW_FIELD("GameID"),
|
|
186
|
+
RC_JSON_NEW_FIELD("Address"),
|
|
187
|
+
RC_JSON_NEW_FIELD("Note")
|
|
188
|
+
*/
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
memset(response, 0, sizeof(*response));
|
|
192
|
+
rc_buffer_init(&response->response.buffer);
|
|
193
|
+
|
|
194
|
+
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
|
195
|
+
if (result != RC_OK || !response->response.succeeded)
|
|
196
|
+
return result;
|
|
197
|
+
|
|
198
|
+
return RC_OK;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
void rc_api_destroy_update_code_note_response(rc_api_update_code_note_response_t* response) {
|
|
202
|
+
rc_buffer_destroy(&response->response.buffer);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/* --- Update Achievement --- */
|
|
206
|
+
|
|
207
|
+
static const char* rc_type_string(uint32_t type) {
|
|
208
|
+
switch (type) {
|
|
209
|
+
case RC_ACHIEVEMENT_TYPE_MISSABLE: return "missable";
|
|
210
|
+
case RC_ACHIEVEMENT_TYPE_PROGRESSION: return "progression";
|
|
211
|
+
case RC_ACHIEVEMENT_TYPE_WIN: return "win_condition";
|
|
212
|
+
default: return "";
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
int rc_api_init_update_achievement_request(rc_api_request_t* request, const rc_api_update_achievement_request_t* api_params) {
|
|
217
|
+
return rc_api_init_update_achievement_request_hosted(request, api_params, &g_host);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
int rc_api_init_update_achievement_request_hosted(rc_api_request_t* request,
|
|
221
|
+
const rc_api_update_achievement_request_t* api_params,
|
|
222
|
+
const rc_api_host_t* host) {
|
|
223
|
+
rc_api_url_builder_t builder;
|
|
224
|
+
char buffer[33];
|
|
225
|
+
md5_state_t md5;
|
|
226
|
+
md5_byte_t hash[16];
|
|
227
|
+
|
|
228
|
+
rc_api_url_build_dorequest_url(request, host);
|
|
229
|
+
|
|
230
|
+
if (api_params->game_id == 0 || api_params->category == 0)
|
|
231
|
+
return RC_INVALID_STATE;
|
|
232
|
+
if (!api_params->title || !*api_params->title)
|
|
233
|
+
return RC_INVALID_STATE;
|
|
234
|
+
if (!api_params->description || !*api_params->description)
|
|
235
|
+
return RC_INVALID_STATE;
|
|
236
|
+
if (!api_params->trigger || !*api_params->trigger)
|
|
237
|
+
return RC_INVALID_STATE;
|
|
238
|
+
|
|
239
|
+
rc_url_builder_init(&builder, &request->buffer, 128);
|
|
240
|
+
if (!rc_api_url_build_dorequest(&builder, "uploadachievement", api_params->username, api_params->api_token))
|
|
241
|
+
return builder.result;
|
|
242
|
+
|
|
243
|
+
if (api_params->achievement_id)
|
|
244
|
+
rc_url_builder_append_unum_param(&builder, "a", api_params->achievement_id);
|
|
245
|
+
rc_url_builder_append_unum_param(&builder, "g", api_params->game_id);
|
|
246
|
+
rc_url_builder_append_str_param(&builder, "n", api_params->title);
|
|
247
|
+
rc_url_builder_append_str_param(&builder, "d", api_params->description);
|
|
248
|
+
rc_url_builder_append_str_param(&builder, "m", api_params->trigger);
|
|
249
|
+
rc_url_builder_append_unum_param(&builder, "z", api_params->points);
|
|
250
|
+
rc_url_builder_append_unum_param(&builder, "f", api_params->category);
|
|
251
|
+
if (api_params->badge)
|
|
252
|
+
rc_url_builder_append_str_param(&builder, "b", api_params->badge);
|
|
253
|
+
rc_url_builder_append_str_param(&builder, "x", rc_type_string(api_params->type));
|
|
254
|
+
|
|
255
|
+
/* Evaluate the signature. */
|
|
256
|
+
md5_init(&md5);
|
|
257
|
+
md5_append(&md5, (md5_byte_t*)api_params->username, (int)strlen(api_params->username));
|
|
258
|
+
md5_append(&md5, (md5_byte_t*)"SECRET", 6);
|
|
259
|
+
snprintf(buffer, sizeof(buffer), "%u", api_params->achievement_id);
|
|
260
|
+
md5_append(&md5, (md5_byte_t*)buffer, (int)strlen(buffer));
|
|
261
|
+
md5_append(&md5, (md5_byte_t*)"SEC", 3);
|
|
262
|
+
md5_append(&md5, (md5_byte_t*)api_params->trigger, (int)strlen(api_params->trigger));
|
|
263
|
+
snprintf(buffer, sizeof(buffer), "%u", api_params->points);
|
|
264
|
+
md5_append(&md5, (md5_byte_t*)buffer, (int)strlen(buffer));
|
|
265
|
+
md5_append(&md5, (md5_byte_t*)"RE2", 3);
|
|
266
|
+
snprintf(buffer, sizeof(buffer), "%u", api_params->points * 3);
|
|
267
|
+
md5_append(&md5, (md5_byte_t*)buffer, (int)strlen(buffer));
|
|
268
|
+
md5_finish(&md5, hash);
|
|
269
|
+
rc_format_md5(buffer, hash);
|
|
270
|
+
rc_url_builder_append_str_param(&builder, "h", buffer);
|
|
271
|
+
|
|
272
|
+
request->post_data = rc_url_builder_finalize(&builder);
|
|
273
|
+
request->content_type = RC_CONTENT_TYPE_URLENCODED;
|
|
274
|
+
|
|
275
|
+
return builder.result;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
int rc_api_process_update_achievement_response(rc_api_update_achievement_response_t* response, const char* server_response) {
|
|
279
|
+
rc_api_server_response_t response_obj;
|
|
280
|
+
|
|
281
|
+
memset(&response_obj, 0, sizeof(response_obj));
|
|
282
|
+
response_obj.body = server_response;
|
|
283
|
+
response_obj.body_length = rc_json_get_object_string_length(server_response);
|
|
284
|
+
|
|
285
|
+
return rc_api_process_update_achievement_server_response(response, &response_obj);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
int rc_api_process_update_achievement_server_response(rc_api_update_achievement_response_t* response, const rc_api_server_response_t* server_response) {
|
|
289
|
+
int result;
|
|
290
|
+
|
|
291
|
+
rc_json_field_t fields[] = {
|
|
292
|
+
RC_JSON_NEW_FIELD("Success"),
|
|
293
|
+
RC_JSON_NEW_FIELD("Error"),
|
|
294
|
+
RC_JSON_NEW_FIELD("AchievementID")
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
memset(response, 0, sizeof(*response));
|
|
298
|
+
rc_buffer_init(&response->response.buffer);
|
|
299
|
+
|
|
300
|
+
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
|
301
|
+
if (result != RC_OK || !response->response.succeeded)
|
|
302
|
+
return result;
|
|
303
|
+
|
|
304
|
+
if (!rc_json_get_required_unum(&response->achievement_id, &response->response, &fields[2], "AchievementID"))
|
|
305
|
+
return RC_MISSING_VALUE;
|
|
306
|
+
|
|
307
|
+
return RC_OK;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
void rc_api_destroy_update_achievement_response(rc_api_update_achievement_response_t* response) {
|
|
311
|
+
rc_buffer_destroy(&response->response.buffer);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/* --- Update Leaderboard --- */
|
|
315
|
+
|
|
316
|
+
int rc_api_init_update_leaderboard_request(rc_api_request_t* request, const rc_api_update_leaderboard_request_t* api_params) {
|
|
317
|
+
return rc_api_init_update_leaderboard_request_hosted(request, api_params, &g_host);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
int rc_api_init_update_leaderboard_request_hosted(rc_api_request_t* request,
|
|
321
|
+
const rc_api_update_leaderboard_request_t* api_params,
|
|
322
|
+
const rc_api_host_t* host) {
|
|
323
|
+
rc_api_url_builder_t builder;
|
|
324
|
+
char buffer[33];
|
|
325
|
+
md5_state_t md5;
|
|
326
|
+
md5_byte_t hash[16];
|
|
327
|
+
|
|
328
|
+
rc_api_url_build_dorequest_url(request, host);
|
|
329
|
+
|
|
330
|
+
if (api_params->game_id == 0)
|
|
331
|
+
return RC_INVALID_STATE;
|
|
332
|
+
if (!api_params->title || !*api_params->title)
|
|
333
|
+
return RC_INVALID_STATE;
|
|
334
|
+
if (!api_params->description)
|
|
335
|
+
return RC_INVALID_STATE;
|
|
336
|
+
if (!api_params->start_trigger || !*api_params->start_trigger)
|
|
337
|
+
return RC_INVALID_STATE;
|
|
338
|
+
if (!api_params->submit_trigger || !*api_params->submit_trigger)
|
|
339
|
+
return RC_INVALID_STATE;
|
|
340
|
+
if (!api_params->cancel_trigger || !*api_params->cancel_trigger)
|
|
341
|
+
return RC_INVALID_STATE;
|
|
342
|
+
if (!api_params->value_definition || !*api_params->value_definition)
|
|
343
|
+
return RC_INVALID_STATE;
|
|
344
|
+
if (!api_params->format || !*api_params->format)
|
|
345
|
+
return RC_INVALID_STATE;
|
|
346
|
+
|
|
347
|
+
rc_url_builder_init(&builder, &request->buffer, 128);
|
|
348
|
+
if (!rc_api_url_build_dorequest(&builder, "uploadleaderboard", api_params->username, api_params->api_token))
|
|
349
|
+
return builder.result;
|
|
350
|
+
|
|
351
|
+
if (api_params->leaderboard_id)
|
|
352
|
+
rc_url_builder_append_unum_param(&builder, "i", api_params->leaderboard_id);
|
|
353
|
+
rc_url_builder_append_unum_param(&builder, "g", api_params->game_id);
|
|
354
|
+
rc_url_builder_append_str_param(&builder, "n", api_params->title);
|
|
355
|
+
rc_url_builder_append_str_param(&builder, "d", api_params->description);
|
|
356
|
+
rc_url_builder_append_str_param(&builder, "s", api_params->start_trigger);
|
|
357
|
+
rc_url_builder_append_str_param(&builder, "b", api_params->submit_trigger);
|
|
358
|
+
rc_url_builder_append_str_param(&builder, "c", api_params->cancel_trigger);
|
|
359
|
+
rc_url_builder_append_str_param(&builder, "l", api_params->value_definition);
|
|
360
|
+
rc_url_builder_append_num_param(&builder, "w", api_params->lower_is_better);
|
|
361
|
+
rc_url_builder_append_str_param(&builder, "f", api_params->format);
|
|
362
|
+
|
|
363
|
+
/* Evaluate the signature. */
|
|
364
|
+
md5_init(&md5);
|
|
365
|
+
md5_append(&md5, (md5_byte_t*)api_params->username, (int)strlen(api_params->username));
|
|
366
|
+
md5_append(&md5, (md5_byte_t*)"SECRET", 6);
|
|
367
|
+
snprintf(buffer, sizeof(buffer), "%u", api_params->leaderboard_id);
|
|
368
|
+
md5_append(&md5, (md5_byte_t*)buffer, (int)strlen(buffer));
|
|
369
|
+
md5_append(&md5, (md5_byte_t*)"SEC", 3);
|
|
370
|
+
md5_append(&md5, (md5_byte_t*)api_params->start_trigger, (int)strlen(api_params->start_trigger));
|
|
371
|
+
md5_append(&md5, (md5_byte_t*)api_params->submit_trigger, (int)strlen(api_params->submit_trigger));
|
|
372
|
+
md5_append(&md5, (md5_byte_t*)api_params->cancel_trigger, (int)strlen(api_params->cancel_trigger));
|
|
373
|
+
md5_append(&md5, (md5_byte_t*)api_params->value_definition, (int)strlen(api_params->value_definition));
|
|
374
|
+
md5_append(&md5, (md5_byte_t*)"RE2", 3);
|
|
375
|
+
md5_append(&md5, (md5_byte_t*)api_params->format, (int)strlen(api_params->format));
|
|
376
|
+
md5_finish(&md5, hash);
|
|
377
|
+
rc_format_md5(buffer, hash);
|
|
378
|
+
rc_url_builder_append_str_param(&builder, "h", buffer);
|
|
379
|
+
|
|
380
|
+
request->post_data = rc_url_builder_finalize(&builder);
|
|
381
|
+
request->content_type = RC_CONTENT_TYPE_URLENCODED;
|
|
382
|
+
|
|
383
|
+
return builder.result;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
int rc_api_process_update_leaderboard_response(rc_api_update_leaderboard_response_t* response, const char* server_response) {
|
|
387
|
+
rc_api_server_response_t response_obj;
|
|
388
|
+
|
|
389
|
+
memset(&response_obj, 0, sizeof(response_obj));
|
|
390
|
+
response_obj.body = server_response;
|
|
391
|
+
response_obj.body_length = rc_json_get_object_string_length(server_response);
|
|
392
|
+
|
|
393
|
+
return rc_api_process_update_leaderboard_server_response(response, &response_obj);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
int rc_api_process_update_leaderboard_server_response(rc_api_update_leaderboard_response_t* response, const rc_api_server_response_t* server_response) {
|
|
397
|
+
int result;
|
|
398
|
+
|
|
399
|
+
rc_json_field_t fields[] = {
|
|
400
|
+
RC_JSON_NEW_FIELD("Success"),
|
|
401
|
+
RC_JSON_NEW_FIELD("Error"),
|
|
402
|
+
RC_JSON_NEW_FIELD("LeaderboardID")
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
memset(response, 0, sizeof(*response));
|
|
406
|
+
rc_buffer_init(&response->response.buffer);
|
|
407
|
+
|
|
408
|
+
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
|
409
|
+
if (result != RC_OK || !response->response.succeeded)
|
|
410
|
+
return result;
|
|
411
|
+
|
|
412
|
+
if (!rc_json_get_required_unum(&response->leaderboard_id, &response->response, &fields[2], "LeaderboardID"))
|
|
413
|
+
return RC_MISSING_VALUE;
|
|
414
|
+
|
|
415
|
+
return RC_OK;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
void rc_api_destroy_update_leaderboard_response(rc_api_update_leaderboard_response_t* response) {
|
|
419
|
+
rc_buffer_destroy(&response->response.buffer);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/* --- Update Rich Presence --- */
|
|
423
|
+
|
|
424
|
+
int rc_api_init_update_rich_presence_request(rc_api_request_t* request, const rc_api_update_rich_presence_request_t* api_params) {
|
|
425
|
+
return rc_api_init_update_rich_presence_request_hosted(request, api_params, &g_host);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
int rc_api_init_update_rich_presence_request_hosted(rc_api_request_t* request,
|
|
429
|
+
const rc_api_update_rich_presence_request_t* api_params,
|
|
430
|
+
const rc_api_host_t* host) {
|
|
431
|
+
rc_api_url_builder_t builder;
|
|
432
|
+
|
|
433
|
+
rc_api_url_build_dorequest_url(request, host);
|
|
434
|
+
|
|
435
|
+
if (api_params->game_id == 0)
|
|
436
|
+
return RC_INVALID_STATE;
|
|
437
|
+
if (!api_params->script)
|
|
438
|
+
return RC_INVALID_STATE;
|
|
439
|
+
|
|
440
|
+
rc_url_builder_init(&builder, &request->buffer, 128);
|
|
441
|
+
if (!rc_api_url_build_dorequest(&builder, "submitrichpresence", api_params->username, api_params->api_token))
|
|
442
|
+
return builder.result;
|
|
443
|
+
|
|
444
|
+
rc_url_builder_append_unum_param(&builder, "g", api_params->game_id);
|
|
445
|
+
rc_url_builder_append_str_param(&builder, "d", api_params->script);
|
|
446
|
+
|
|
447
|
+
request->post_data = rc_url_builder_finalize(&builder);
|
|
448
|
+
request->content_type = RC_CONTENT_TYPE_URLENCODED;
|
|
449
|
+
|
|
450
|
+
return builder.result;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
int rc_api_process_update_rich_presence_server_response(rc_api_update_rich_presence_response_t* response, const rc_api_server_response_t* server_response) {
|
|
454
|
+
int result;
|
|
455
|
+
|
|
456
|
+
rc_json_field_t fields[] = {
|
|
457
|
+
RC_JSON_NEW_FIELD("Success"),
|
|
458
|
+
RC_JSON_NEW_FIELD("Error"),
|
|
459
|
+
RC_JSON_NEW_FIELD("Code"),
|
|
460
|
+
};
|
|
461
|
+
|
|
462
|
+
memset(response, 0, sizeof(*response));
|
|
463
|
+
rc_buffer_init(&response->response.buffer);
|
|
464
|
+
|
|
465
|
+
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
|
466
|
+
if (result != RC_OK || !response->response.succeeded)
|
|
467
|
+
return result;
|
|
468
|
+
|
|
469
|
+
return RC_OK;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
void rc_api_destroy_update_rich_presence_response(rc_api_update_rich_presence_response_t* response) {
|
|
473
|
+
rc_buffer_destroy(&response->response.buffer);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/* --- Fetch Badge Range --- */
|
|
477
|
+
|
|
478
|
+
int rc_api_init_fetch_badge_range_request(rc_api_request_t* request, const rc_api_fetch_badge_range_request_t* api_params) {
|
|
479
|
+
return rc_api_init_fetch_badge_range_request_hosted(request, api_params, &g_host);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
int rc_api_init_fetch_badge_range_request_hosted(rc_api_request_t* request,
|
|
483
|
+
const rc_api_fetch_badge_range_request_t* api_params,
|
|
484
|
+
const rc_api_host_t* host) {
|
|
485
|
+
rc_api_url_builder_t builder;
|
|
486
|
+
|
|
487
|
+
rc_api_url_build_dorequest_url(request, host);
|
|
488
|
+
|
|
489
|
+
rc_url_builder_init(&builder, &request->buffer, 48);
|
|
490
|
+
rc_url_builder_append_str_param(&builder, "r", "badgeiter");
|
|
491
|
+
|
|
492
|
+
request->post_data = rc_url_builder_finalize(&builder);
|
|
493
|
+
request->content_type = RC_CONTENT_TYPE_URLENCODED;
|
|
494
|
+
|
|
495
|
+
(void)api_params;
|
|
496
|
+
|
|
497
|
+
return builder.result;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
int rc_api_process_fetch_badge_range_response(rc_api_fetch_badge_range_response_t* response, const char* server_response) {
|
|
501
|
+
rc_api_server_response_t response_obj;
|
|
502
|
+
|
|
503
|
+
memset(&response_obj, 0, sizeof(response_obj));
|
|
504
|
+
response_obj.body = server_response;
|
|
505
|
+
response_obj.body_length = rc_json_get_object_string_length(server_response);
|
|
506
|
+
|
|
507
|
+
return rc_api_process_fetch_badge_range_server_response(response, &response_obj);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
int rc_api_process_fetch_badge_range_server_response(rc_api_fetch_badge_range_response_t* response, const rc_api_server_response_t* server_response) {
|
|
511
|
+
int result;
|
|
512
|
+
|
|
513
|
+
rc_json_field_t fields[] = {
|
|
514
|
+
RC_JSON_NEW_FIELD("Success"),
|
|
515
|
+
RC_JSON_NEW_FIELD("Error"),
|
|
516
|
+
RC_JSON_NEW_FIELD("FirstBadge"),
|
|
517
|
+
RC_JSON_NEW_FIELD("NextBadge")
|
|
518
|
+
};
|
|
519
|
+
|
|
520
|
+
memset(response, 0, sizeof(*response));
|
|
521
|
+
rc_buffer_init(&response->response.buffer);
|
|
522
|
+
|
|
523
|
+
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
|
524
|
+
if (result != RC_OK || !response->response.succeeded)
|
|
525
|
+
return result;
|
|
526
|
+
|
|
527
|
+
if (!rc_json_get_required_unum(&response->first_badge_id, &response->response, &fields[2], "FirstBadge"))
|
|
528
|
+
return RC_MISSING_VALUE;
|
|
529
|
+
if (!rc_json_get_required_unum(&response->next_badge_id, &response->response, &fields[3], "NextBadge"))
|
|
530
|
+
return RC_MISSING_VALUE;
|
|
531
|
+
|
|
532
|
+
return RC_OK;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
void rc_api_destroy_fetch_badge_range_response(rc_api_fetch_badge_range_response_t* response) {
|
|
536
|
+
rc_buffer_destroy(&response->response.buffer);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/* --- Add Game Hash --- */
|
|
540
|
+
|
|
541
|
+
int rc_api_init_add_game_hash_request(rc_api_request_t* request, const rc_api_add_game_hash_request_t* api_params) {
|
|
542
|
+
return rc_api_init_add_game_hash_request_hosted(request, api_params, &g_host);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
int rc_api_init_add_game_hash_request_hosted(rc_api_request_t* request,
|
|
546
|
+
const rc_api_add_game_hash_request_t* api_params,
|
|
547
|
+
const rc_api_host_t* host) {
|
|
548
|
+
rc_api_url_builder_t builder;
|
|
549
|
+
|
|
550
|
+
rc_api_url_build_dorequest_url(request, host);
|
|
551
|
+
|
|
552
|
+
if (api_params->console_id == 0)
|
|
553
|
+
return RC_INVALID_STATE;
|
|
554
|
+
if (!api_params->hash || !*api_params->hash)
|
|
555
|
+
return RC_INVALID_STATE;
|
|
556
|
+
if (api_params->game_id == 0 && (!api_params->title || !*api_params->title))
|
|
557
|
+
return RC_INVALID_STATE;
|
|
558
|
+
|
|
559
|
+
rc_url_builder_init(&builder, &request->buffer, 128);
|
|
560
|
+
if (!rc_api_url_build_dorequest(&builder, "submitgametitle", api_params->username, api_params->api_token))
|
|
561
|
+
return builder.result;
|
|
562
|
+
|
|
563
|
+
rc_url_builder_append_unum_param(&builder, "c", api_params->console_id);
|
|
564
|
+
rc_url_builder_append_str_param(&builder, "m", api_params->hash);
|
|
565
|
+
if (api_params->title)
|
|
566
|
+
rc_url_builder_append_str_param(&builder, "i", api_params->title);
|
|
567
|
+
if (api_params->game_id)
|
|
568
|
+
rc_url_builder_append_unum_param(&builder, "g", api_params->game_id);
|
|
569
|
+
if (api_params->hash_description && *api_params->hash_description)
|
|
570
|
+
rc_url_builder_append_str_param(&builder, "d", api_params->hash_description);
|
|
571
|
+
|
|
572
|
+
request->post_data = rc_url_builder_finalize(&builder);
|
|
573
|
+
request->content_type = RC_CONTENT_TYPE_URLENCODED;
|
|
574
|
+
|
|
575
|
+
return builder.result;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
int rc_api_process_add_game_hash_response(rc_api_add_game_hash_response_t* response, const char* server_response) {
|
|
579
|
+
rc_api_server_response_t response_obj;
|
|
580
|
+
|
|
581
|
+
memset(&response_obj, 0, sizeof(response_obj));
|
|
582
|
+
response_obj.body = server_response;
|
|
583
|
+
response_obj.body_length = rc_json_get_object_string_length(server_response);
|
|
584
|
+
|
|
585
|
+
return rc_api_process_add_game_hash_server_response(response, &response_obj);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
int rc_api_process_add_game_hash_server_response(rc_api_add_game_hash_response_t* response, const rc_api_server_response_t* server_response) {
|
|
589
|
+
int result;
|
|
590
|
+
|
|
591
|
+
rc_json_field_t fields[] = {
|
|
592
|
+
RC_JSON_NEW_FIELD("Success"),
|
|
593
|
+
RC_JSON_NEW_FIELD("Error"),
|
|
594
|
+
RC_JSON_NEW_FIELD("Response")
|
|
595
|
+
};
|
|
596
|
+
|
|
597
|
+
rc_json_field_t response_fields[] = {
|
|
598
|
+
RC_JSON_NEW_FIELD("GameID")
|
|
599
|
+
/* unused fields
|
|
600
|
+
RC_JSON_NEW_FIELD("MD5"),
|
|
601
|
+
RC_JSON_NEW_FIELD("ConsoleID"),
|
|
602
|
+
RC_JSON_NEW_FIELD("GameTitle"),
|
|
603
|
+
RC_JSON_NEW_FIELD("Success")
|
|
604
|
+
*/
|
|
605
|
+
};
|
|
606
|
+
|
|
607
|
+
memset(response, 0, sizeof(*response));
|
|
608
|
+
rc_buffer_init(&response->response.buffer);
|
|
609
|
+
|
|
610
|
+
result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0]));
|
|
611
|
+
if (result != RC_OK || !response->response.succeeded)
|
|
612
|
+
return result;
|
|
613
|
+
|
|
614
|
+
if (!rc_json_get_required_object(response_fields, sizeof(response_fields) / sizeof(response_fields[0]), &response->response, &fields[2], "Response"))
|
|
615
|
+
return RC_MISSING_VALUE;
|
|
616
|
+
|
|
617
|
+
if (!rc_json_get_required_unum(&response->game_id, &response->response, &response_fields[0], "GameID"))
|
|
618
|
+
return RC_MISSING_VALUE;
|
|
619
|
+
|
|
620
|
+
return RC_OK;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
void rc_api_destroy_add_game_hash_response(rc_api_add_game_hash_response_t* response) {
|
|
624
|
+
rc_buffer_destroy(&response->response.buffer);
|
|
625
|
+
}
|