diff options
Diffstat (limited to 'src/launch.c')
| -rw-r--r-- | src/launch.c | 257 |
1 files changed, 251 insertions, 6 deletions
diff --git a/src/launch.c b/src/launch.c index cc0721f..6ac2ff7 100644 --- a/src/launch.c +++ b/src/launch.c @@ -1,31 +1,276 @@ #include "l2su.h" +#include "launch.h" +#include "macros.h" +#include "version.h" +#include "assets.h" +#include "args.h" -/* TODO launch struct */ +#include <stdlib.h> +#include <stdarg.h> +#include <stdio.h> -int l2_launch_fill_substitutor(l2_subst_t *st, void *reserved, json_t *version, struct l2_instance *inst) +bool l2_launch__check_feature(const char *name, json_t *val, void *user); + +int l2_launch_init(struct l2_launch *launch, const char *vername, struct l2_instance *inst) +{ + unsigned res; + json_t *verjson = NULL; + struct l2_version_library *libs = NULL; + char *jarpath = NULL; + json_t *jassetidx = NULL; + char *assetrootpath = NULL; + char *assetpath = NULL; + char *nativesdir = NULL; + char *main_class_dup = NULL; + + l2_subst_t *subst = NULL; + + if (l2_subst_init(&subst) < 0) { + CMD_ERROR0("Failed to create argument substitutor"); + goto cleanup; + } + + CMD_INFO("Attempting to load version %s...", vername); + if ((res = l2_version_load_local(vername, &verjson)) != VERSION_SUCCESS) { + CMD_ERROR("Failed to load version: %s", l2_version_strerror(res)); + goto cleanup; + } + + const char *main_class; + if (json_unpack(verjson, "{s:s}", "mainClass", &main_class) < 0) { + CMD_ERROR0("Failed to find main class."); + goto cleanup; + } + + main_class_dup = strdup(main_class); + if (!main_class_dup) { + CMD_ERROR0("Allocation failed."); + goto cleanup; + } + + CMD_INFO0("Collecting libraries"); + if ((res = l2_version_collect_libraries(verjson, &libs, &l2_launch__check_feature, launch)) != VERSION_SUCCESS) { + CMD_ERROR("Failed to collect libraries: %s", l2_version_strerror(res)); + goto cleanup; + } + + CMD_INFO0("Downloading libraries"); + if ((res = l2_version_download_libraries(libs)) != VERSION_SUCCESS) { + CMD_ERROR("Failed to download libraries: %s", l2_version_strerror(res)); + goto cleanup; + } + + CMD_INFO0("Downloading client jar"); + if ((res = l2_version_download_jar(verjson, "client", &jarpath)) != VERSION_SUCCESS) { + CMD_ERROR("Failed to download client jar: %s", l2_version_strerror(res)); + goto cleanup; + } + + CMD_INFO0("Downloading asset index"); + if (l2_assets_load_index(verjson, &jassetidx) < 0) { + CMD_ERROR0("Failed to load asset index."); + goto cleanup; + } + + CMD_INFO0("Downloading assets"); + if (l2_assets_download_assets(jassetidx, &assetpath) < 0) { + CMD_ERROR0("Failed to download assets."); + goto cleanup; + } + + assetrootpath = l2_launcher_sprintf_alloc("%s/assets", l2_state.paths.data); + if (!assetrootpath) { + CMD_ERROR0("Allocation failed"); + goto cleanup; + } + + CMD_INFO0("Extracting natives"); + if ((res = l2_version_extract_natives(libs, &nativesdir)) != VERSION_SUCCESS) { + CMD_ERROR("Failed to extract natives: %s", l2_version_strerror(res)); + goto cleanup; + } + + launch->instance = inst; + launch->version = verjson; + launch->libraries = libs; + launch->jarpath = jarpath; + launch->asset_index = jassetidx; + launch->assets_root = assetrootpath; + launch->virtual_assets = assetpath; + launch->natives = nativesdir; + launch->arg_subst = subst; + launch->main_class = main_class_dup; + + return 0; + +cleanup: + json_decref(verjson); + l2_version_free_libraries(libs); + free(jarpath); + free(assetrootpath); + json_decref(jassetidx); + free(assetpath); + free(nativesdir); + free(main_class_dup); + if (subst) l2_subst_free(subst); + + return -1; +} + +void l2_launch_free_contents(struct l2_launch *launch) +{ + json_decref(launch->version); + l2_version_free_libraries(launch->libraries); + free(launch->jarpath); + free(launch->assets_root); + json_decref(launch->asset_index); + free(launch->virtual_assets); + free(launch->natives); + if (launch->arg_subst) l2_subst_free(launch->arg_subst); + free(launch->main_class); +} + +bool l2_launch__check_feature(const char *name, json_t *val, void *user) +{ + L2_UNUSED(name); + L2_UNUSED(val); + L2_UNUSED(user); + return false; +} + +int L2_FORMAT(printf, 3, 4) l2_launch__sprintf_resize(char **buf, size_t *cap, const char *fmt, ...) +{ + va_list pv; + va_start(pv, fmt); + size_t reqlen = vsnprintf(NULL, 0, fmt, pv); + va_end(pv); + + if (*cap <= reqlen) { + char *temp = realloc(*buf, reqlen + 1); + if (!temp) return -1; + *buf = temp; + *cap = reqlen + 1; + } + + va_start(pv, fmt); + vsnprintf(*buf, *cap, fmt, pv); + va_end(pv); + return 0; +} + +int l2_launch__fill_substitutor(struct l2_launch *launch) { #define L2_LAUNCH_ADD_SUB(_st, _name, _val) \ - if (l2_subst_add(_st, _name, _val) < 0) return -1 + if (l2_subst_add(_st, _name, _val) < 0) goto cleanup + + l2_subst_t *st = launch->arg_subst; + char *keyname = NULL, *apath = NULL; + size_t keycap = 0, acap = 0; const char *ver_name; - if (json_unpack(version, "{s:s}", "id", &ver_name) < 0) { + const char *assets_idx_name; + const char *version_type; + if (json_unpack(launch->version, "{s:s, s:{s:s}, s:s}", "id", &ver_name, "assetIndex", "id", &assets_idx_name, "type", &version_type) < 0) { return -1; } /* auth_access_token */ /* user_properties */ /* user_property_map */ + /* auth_xuid */ + /* clientid (lowercase i is real) */ L2_LAUNCH_ADD_SUB(st, "auth_session", "-"); L2_LAUNCH_ADD_SUB(st, "auth_player_name", "figboot"); L2_LAUNCH_ADD_SUB(st, "auth_uuid", "00000000000000000000000000000000"); L2_LAUNCH_ADD_SUB(st, "user_type", "legacy"); - L2_LAUNCH_ADD_SUB(st, "profile_name", inst->name); + if (launch->instance) { + L2_LAUNCH_ADD_SUB(st, "profile_name", launch->instance->name); + } + L2_LAUNCH_ADD_SUB(st, "version_name", ver_name); L2_LAUNCH_ADD_SUB(st, "game_directory", "."); - + L2_LAUNCH_ADD_SUB(st, "game_assets", launch->virtual_assets); + L2_LAUNCH_ADD_SUB(st, "assets_root", launch->assets_root); + L2_LAUNCH_ADD_SUB(st, "assets_index_name", assets_idx_name); + L2_LAUNCH_ADD_SUB(st, "version_type", version_type); + + if (l2_launch__check_feature("has_custom_resolution", json_true(), launch)) { + char *widthstr, *heightstr; + size_t tempsz; + L2_ASPRINTF(widthstr, tempsz, "%u", launch->resolution.width); + L2_ASPRINTF(heightstr, tempsz, "%u", launch->resolution.height); + + L2_LAUNCH_ADD_SUB(st, "resolution_width", widthstr); + L2_LAUNCH_ADD_SUB(st, "resolution_height", heightstr); + } + + L2_LAUNCH_ADD_SUB(st, "language", "en-us"); + + L2_LAUNCH_ADD_SUB(st, "launcher_name", PROJECT_NAME); + L2_LAUNCH_ADD_SUB(st, "launcher_version", "0.1.0"); + L2_LAUNCH_ADD_SUB(st, "natives_directory", launch->natives); + L2_LAUNCH_ADD_SUB(st, "classpath", "TODO"); + L2_LAUNCH_ADD_SUB(st, "classpath_separator", L2SU_CLASSPATH_SEP); + L2_LAUNCH_ADD_SUB(st, "primary_jar", launch->jarpath); + + const char *assetpath, *assethash; + json_t *objects = json_object_get(launch->asset_index, "objects"); + if (json_is_object(objects)) { + json_t *val; + json_object_foreach(objects, assetpath, val) { + json_t *hash_obj = json_object_get(val, "hash"); + if (!json_is_string(hash_obj)) goto cleanup; + assethash = json_string_value(hash_obj); + + if (l2_launch__sprintf_resize(&apath, &acap, "%s/assets/objects/%2.2s/%s", l2_state.paths.data, assethash, assethash) < 0) goto cleanup; + if (l2_launch__sprintf_resize(&keyname, &keycap, "asset=%s", assetpath) < 0) goto cleanup; + + L2_LAUNCH_ADD_SUB(st, keyname, apath); + } + } + + free(keyname); + free(apath); + + keyname = NULL; + apath = NULL; return 0; + +cleanup: + free(keyname); + free(apath); + + return -1; #undef L2_LAUNCH_ADD_SUB } + +void l2_launch__test(struct l2_launch *launch) +{ + if (l2_launch__fill_substitutor(launch) < 0) CMD_FATAL0("fill"); + + char **jvm_args, **game_args; + size_t njvm_args, ngame_args; + if (l2_args_get_jvm_args(launch->version, launch->arg_subst, &l2_launch__check_feature, launch, &jvm_args, &njvm_args) < 0) { + CMD_FATAL0("jvm"); + } + + if (l2_args_get_game_args(launch->version, launch->arg_subst, &l2_launch__check_feature, launch, &game_args, &ngame_args) < 0) { + CMD_FATAL0("game"); + } + + for (size_t s = 0; s < njvm_args; ++s) { + CMD_DEBUG("jvm: %s", jvm_args[s]); + free(jvm_args[s]); + } + + for(size_t s = 0; s < ngame_args; ++s) { + CMD_DEBUG("game: %s", game_args[s]); + free(game_args[s]); + } + + free(jvm_args); + free(game_args); +} |
