void compile(const char* path, CompileOptions& opts)
	{
		Buffer buf = opts.read(path);
		JSONParser json(buf);
		JSONElement root = json.root();

		JSONElement texture  = root.key_or_nil("texture");
		JSONElement script   = root.key_or_nil("lua");
		JSONElement sound    = root.key_or_nil("sound");
		JSONElement mesh     = root.key_or_nil("mesh");
		JSONElement unit     = root.key_or_nil("unit");
		JSONElement sprite   = root.key_or_nil("sprite");
		JSONElement physics  = root.key_or_nil("physics");
		JSONElement material = root.key_or_nil("material");
		JSONElement font     = root.key_or_nil("font");
		JSONElement level    = root.key_or_nil("level");
		JSONElement phyconf  = root.key_or_nil("physics_config");
		JSONElement shader   = root.key_or_nil("shader");
		JSONElement sprite_animation = root.key_or_nil("sprite_animation");

		const uint32_t num_textures  = texture.is_nil() ? 0 : texture.size();
		const uint32_t num_scripts   = script.is_nil() ? 0 : script.size();
		const uint32_t num_sounds    = sound.is_nil() ? 0 : sound.size();
		const uint32_t num_meshes    = mesh.is_nil() ? 0 : mesh.size();
		const uint32_t num_units     = unit.is_nil() ? 0 : unit.size();
		const uint32_t num_sprites   = sprite.is_nil() ? 0 : sprite.size();
		const uint32_t num_physics   = physics.is_nil() ? 0 : physics.size();
		const uint32_t num_materials = material.is_nil() ? 0 : material.size();
		const uint32_t num_fonts     = font.is_nil() ? 0 : font.size();
		const uint32_t num_levels    = level.is_nil() ? 0 : level.size();
		const uint32_t num_phyconfs  = phyconf.is_nil() ? 0 : phyconf.size();
		const uint32_t num_shaders   = shader.is_nil() ? 0 : shader.size();
		const uint32_t num_sprite_animations = sprite_animation.is_nil() ? 0 : sprite_animation.size();

		// Write header
		opts.write(PACKAGE_VERSION);
		opts.write(num_textures);
		uint32_t offt = sizeof(PackageResource);
		opts.write(offt);

		opts.write(num_scripts);
		offt += sizeof(StringId64) * num_textures;
		opts.write(offt);

		opts.write(num_sounds);
		offt += sizeof(StringId64) * num_scripts;
		opts.write(offt);

		opts.write(num_meshes);
		offt += sizeof(StringId64) * num_sounds;
		opts.write(offt);

		opts.write(num_units);
		offt += sizeof(StringId64) * num_meshes;
		opts.write(offt);

		opts.write(num_sprites);
		offt += sizeof(StringId64) * num_units;
		opts.write(offt);

		opts.write(num_physics);
		offt += sizeof(StringId64) * num_sprites;
		opts.write(offt);

		opts.write(num_materials);
		offt += sizeof(StringId64) * num_physics;
		opts.write(offt);

		opts.write(num_fonts);
		offt += sizeof(StringId64) * num_materials;
		opts.write(offt);

		opts.write(num_levels);
		offt += sizeof(StringId64) * num_fonts;
		opts.write(offt);

		opts.write(num_phyconfs);
		offt += sizeof(StringId64) * num_levels;
		opts.write(offt);

		opts.write(num_shaders);
		offt += sizeof(StringId64) * num_phyconfs;
		opts.write(offt);

		opts.write(num_sprite_animations);
		offt += sizeof(StringId64) * num_shaders;
		opts.write(offt);

		// Write resource ids
		for (uint32_t i = 0; i < num_textures; i++)
			opts.write(texture[i].to_resource_id());

		for (uint32_t i = 0; i < num_scripts; i++)
			opts.write(script[i].to_resource_id());

		for (uint32_t i = 0; i < num_sounds; i++)
			opts.write(sound[i].to_resource_id());

		for (uint32_t i = 0; i < num_meshes; i++)
			opts.write(mesh[i].to_resource_id());

		for (uint32_t i = 0; i < num_units; i++)
			opts.write(unit[i].to_resource_id());

		for (uint32_t i = 0; i < num_sprites; i++)
			opts.write(sprite[i].to_resource_id());

		for (uint32_t i = 0; i < num_physics; i++)
			opts.write(physics[i].to_resource_id());

		for (uint32_t i = 0; i < num_materials; i++)
			opts.write(material[i].to_resource_id());

		for (uint32_t i = 0; i < num_fonts; i++)
			opts.write(font[i].to_resource_id());

		for (uint32_t i = 0; i < num_levels; i++)
			opts.write(level[i].to_resource_id());

		for (uint32_t i = 0; i < num_phyconfs; i++)
			opts.write(phyconf[i].to_resource_id());

		for (uint32_t i = 0; i < num_shaders; i++)
			opts.write(shader[i].to_resource_id());

		for (uint32_t i = 0; i < num_sprite_animations; i++)
			opts.write(sprite_animation[i].to_resource_id());
	}