Beispiel #1
0
static void load_packages(const char *dir, const char *unionmp) {
	// go over the packages in dir in alphapetical order and merge them into unionmp
	// e.g. files in 00-aaa.zip will be shadowed by files in 99-zzz.zip

	size_t numpaks = 0;
	char **paklist = vfs_dir_list_sorted(dir, &numpaks, vfs_dir_list_order_ascending, NULL);

	if(!paklist) {
		log_fatal("VFS error: %s", vfs_get_error());
	}

	for(size_t i = 0; i < numpaks; ++i) {
		const char *entry = paklist[i];
		struct pkg_loader_t *loader = find_loader(entry);

		if(loader == NULL) {
			continue;
		}

		log_info("Adding package: %s", entry);
		assert(loader->mount != NULL);

		char *tmp = strfmt("%s/%s", dir, entry);

		if(!loader->mount(unionmp, tmp)) {
			log_error("VFS error: %s", vfs_get_error());
		}

		free(tmp);
	}

	vfs_dir_list_free(paklist, numpaks);
}
Beispiel #2
0
bool vfs_mount_syspath(const char *mountpoint, const char *fspath, uint flags) {
	VFSNode *rdir = vfs_alloc();

	if(!vfs_syspath_init(rdir, fspath)) {
		vfs_set_error("Can't initialize path: %s", vfs_get_error());
		vfs_decref(rdir);
		return false;
	}

	if((flags & VFS_SYSPATH_MOUNT_MKDIR) && !vfs_node_mkdir(rdir, NULL)) {
		vfs_set_error("Can't create directory: %s", vfs_get_error());
		vfs_decref(rdir);
		return false;
	}

	if(flags & VFS_SYSPATH_MOUNT_READONLY) {
		VFSNode *rdir_ro = vfs_ro_wrap(rdir);
		vfs_decref(rdir);
		rdir = rdir_ro;
	}

	return vfs_mount_or_decref(vfs_root, mountpoint, rdir);
}
Beispiel #3
0
bool replay_save(Replay *rpy, const char *name) {
	char *p = replay_getpath(name, !strendswith(name, REPLAY_EXTENSION));
	char *sp = vfs_repr(p, true);
	log_info("Saving %s", sp);
	free(sp);

	SDL_RWops *file = vfs_open(p, VFS_MODE_WRITE);
	free(p);

	if(!file) {
		log_warn("VFS error: %s", vfs_get_error());
		return false;
	}

	bool result = replay_write(rpy, file, REPLAY_STRUCT_VERSION_WRITE);
	SDL_RWclose(file);
	return result;
}
Beispiel #4
0
static int gamepad_load_mappings(const char *vpath, int warn_noexist) {
	char *repr = vfs_repr(vpath, true);
	char *errstr = NULL;
	const char *const_errstr = NULL;

	SDL_RWops *mappings = vfs_open(vpath, VFS_MODE_READ | VFS_MODE_SEEKABLE);
	int num_loaded = -1;
	LogLevel loglvl = LOG_WARN;

	if(!mappings) {
		if(!warn_noexist) {
			VFSInfo vinfo = vfs_query(vpath);

			if(!vinfo.error && !vinfo.exists && !vinfo.is_dir) {
				loglvl = LOG_INFO;
				const_errstr = errstr = strfmt("Custom mappings file '%s' does not exist (this is ok)", repr);
				goto cleanup;
			}
		}

		const_errstr = vfs_get_error();
		goto cleanup;
	}

	if((num_loaded = SDL_GameControllerAddMappingsFromRW(mappings, true)) < 0) {
		const_errstr = SDL_GetError();
	}

cleanup:
	if(const_errstr) {
		log_custom(loglvl, "Couldn't load mappings: %s", const_errstr);
	} else if(num_loaded >= 0) {
		log_info("Loaded %i mappings from '%s'", num_loaded, repr);
	}

	free(repr);
	free(errstr);
	return num_loaded;
}
Beispiel #5
0
bool replay_load(Replay *rpy, const char *name, ReplayReadMode mode) {
	char *p = replay_getpath(name, !strendswith(name, REPLAY_EXTENSION));
	char *sp = vfs_repr(p, true);
	log_info("Loading %s (%s)", sp, replay_mode_string(mode));

	SDL_RWops *file = vfs_open(p, VFS_MODE_READ);
	free(p);

	if(!file) {
		log_warn("VFS error: %s", vfs_get_error());
		free(sp);
		return false;
	}

	bool result = replay_read(rpy, file, mode, sp);

	if(!result) {
		replay_destroy(rpy);
	}

	free(sp);
	SDL_RWclose(file);
	return result;
}
Beispiel #6
0
static bool parse_obj(const char *filename, ObjFileData *data) {
	SDL_RWops *rw = vfs_open(filename, VFS_MODE_READ);

	if(!rw) {
		log_error("VFS error: %s", vfs_get_error());
		return false;
	}

	char line[256], *save;
	vec3_noalign buf;
	char mode;
	int linen = 0;

	memset(data, 0, sizeof(ObjFileData));

	while(SDL_RWgets(rw, line, sizeof(line))) {
		linen++;

		char *first;
		first = strtok_r(line, " \n", &save);

		if(strcmp(first, "v") == 0)
			mode = 'v';
		else if(strcmp(first, "vt") == 0)
			mode = 't';
		else if(strcmp(first, "vn") == 0)
			mode = 'n';
		else if(strcmp(first, "f") == 0)
			mode = 'f';
		else
			mode = 0;

		if(mode != 0 && mode != 'f') {
			buf[0] = atof(strtok_r(NULL, " \n", &save));
			char *wtf = strtok_r(NULL, " \n", &save);
			buf[1] = atof(wtf);
			if(mode != 't')
				buf[2] = atof(strtok_r(NULL, " \n", &save));

			switch(mode) {
			case 'v':
				data->xs = realloc(data->xs, sizeof(vec3_noalign)*(++data->xcount));
				memcpy(data->xs[data->xcount-1], buf, sizeof(vec3_noalign));
				break;
			case 't':
				data->texcoords = realloc(data->texcoords, sizeof(vec3_noalign)*(++data->tcount));
				memcpy(data->texcoords[data->tcount-1], buf, sizeof(vec3_noalign));
				break;
			case 'n':
				data->normals = realloc(data->normals, sizeof(vec3_noalign)*(++data->ncount));
				memcpy(data->normals[data->ncount-1], buf, sizeof(vec3_noalign));
				break;
			}
		} else if(mode == 'f') {
			char *segment, *seg;
			int j = 0, jj;
			ivec3_noalign ibuf;
			memset(ibuf, 0, sizeof(ibuf));

			while((segment = strtok_r(NULL, " \n", &save))) {
				seg = segment;
				j++;

				jj = 0;
				while(jj < 3) {
					ibuf[jj] = atoi(seg);
					jj++;

					while(*seg != '\0' && *(++seg) != '/');

					if(*seg == '\0')
						break;
					else
						seg++;
				}

				if(strstr(segment, "//")) {
					ibuf[2] = ibuf[1];
					ibuf[1] = 0;
				}

				if(jj == 0 || jj > 3 || segment[0] == '/') {
					log_error("OBJ file '%s:%d': Parsing error: Corrupt face definition", filename, linen);
					goto fail;
				}

				data->indices = realloc(data->indices, sizeof(ivec3_noalign)*(++data->icount));
				memcpy(data->indices[data->icount-1], ibuf, sizeof(ivec3_noalign));
			}

			if(data->fverts == 0)
				data->fverts = j;

			if(data->fverts != j) {
				log_error("OBJ file '%s:%d': Parsing error: face vertex count must stay the same in the whole file", filename, linen);
				goto fail;
			}

			if(data->fverts != 3) {
				log_error("OBJ file '%s:%d': Parsing error: face vertex count must be 3", filename, linen);
				goto fail;
			}
		}
	}

	SDL_RWclose(rw);
	return true;

fail:
	SDL_RWclose(rw);
	free(data->indices);
	free(data->normals);
	free(data->xs);
	return false;
}
Beispiel #7
0
void vfs_setup(CallChain next) {
	char *res_path, *storage_path, *cache_path;
	get_core_paths(&res_path, &storage_path, &cache_path);

	char *local_res_path = strfmt("%s%cresources", storage_path, vfs_get_syspath_separator());
	vfs_syspath_normalize_inplace(local_res_path);

	log_info("Resource path: %s", res_path);
	log_info("Storage path: %s", storage_path);
	log_info("Local resource path: %s", local_res_path);
	log_info("Cache path: %s", cache_path);

	struct mpoint_t {
		const char *dest;    const char *syspath; bool loadpaks; uint flags;
	} mpts[] = {
		// per-user directory, where configs, replays, screenshots, etc. get stored
		{ "storage",         storage_path,        false,         VFS_SYSPATH_MOUNT_MKDIR },

		// system-wide directory, contains all of the game assets
		{ "resdirs",         res_path,            true,          VFS_SYSPATH_MOUNT_READONLY },

		// subpath of storage, files here override the global assets
		{ "resdirs",         local_res_path,      true,          VFS_SYSPATH_MOUNT_MKDIR | VFS_SYSPATH_MOUNT_READONLY },

		// per-user directory, to contain various cached resources to speed up loading times
		{ "cache",           cache_path,          false,         VFS_SYSPATH_MOUNT_MKDIR },

		{NULL}
	};

	vfs_init();

	// temporary union of the "real" directories
	vfs_create_union_mountpoint("resdirs");

	// temporary union of the packages (e.g. zip files)
	vfs_create_union_mountpoint("respkgs");

	// permanent union of respkgs and resdirs
	// this way, files in any of the "real" directories always have priority over anything in packages
	vfs_create_union_mountpoint("res");

	for(struct mpoint_t *mp = mpts; mp->dest; ++mp) {
		if(mp->loadpaks) {
			// mount it to a temporary mountpoint to get a list of packages from this directory
			if(!vfs_mount_syspath("tmp", mp->syspath, mp->flags)) {
				log_fatal("Failed to mount '%s': %s", mp->syspath, vfs_get_error());
			}

			if(!vfs_query("tmp").is_dir) {
				log_error("'%s' is not a directory", mp->syspath);
				vfs_unmount("tmp");
				continue;
			}

			// load all packages from this directory into the respkgs union
			load_packages("tmp", "respkgs");

			// now mount it to the intended destination, and remove the temporary mountpoint
			vfs_mount_alias(mp->dest, "tmp");
			vfs_unmount("tmp");
		} else if(!vfs_mount_syspath(mp->dest, mp->syspath, mp->flags)) {
			log_fatal("Failed to mount '%s': %s", mp->syspath, vfs_get_error());
		}
	}

	vfs_mkdir_required("storage/replays");
	vfs_mkdir_required("storage/screenshots");

	free(local_res_path);
	free(res_path);
	free(storage_path);
	free(cache_path);

	// set up the final "res" union and get rid of the temporaries

	vfs_mount_alias("res", "respkgs");
	vfs_mount_alias("res", "resdirs");
	// vfs_make_readonly("res");

	vfs_unmount("resdirs");
	vfs_unmount("respkgs");

	run_call_chain(&next, NULL);
}