aboutsummaryrefslogtreecommitdiffstats
path: root/src/launch.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/launch.c')
-rw-r--r--src/launch.c257
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);
+}