(msg);
-
- conPrint("Received RemoteClientAudioStreamToServerEnded, avatar_uid: " + m->avatar_uid.toString());
-
- if(world_state.nonNull())
- {
- Lock lock(this->world_state->mutex);
-
- auto res = this->world_state->avatars.find(m->avatar_uid);
- if(res != this->world_state->avatars.end())
- {
- Avatar* avatar = res->second.getPointer();
-
- // Remove audio source for voice chat, if it exists
- if(avatar->audio_source.nonNull() && !avatar->isOurAvatar())
- {
- audio_engine.removeSource(avatar->audio_source);
- avatar->audio_source = NULL;
-
- world_state->avatars_changed = 1; // Inform ClientUDPHandlerThread
- }
-
- // Remove speaker icon by nametag.
- checkRemoveObAndSetRefToNull(opengl_engine, avatar->speaker_gl_ob);
- }
- }
- }
- break;
- case Msg_ClientProtocolTooOldMessage:
- {
- ui_interface->showHTMLMessageBox("Client too old", "Sorry, your Substrata client is too old.
Please download and install an updated client from substrata.info
");
- }
- break;
- case Msg_ClientDisconnectedFromServerMessage:
- {
- const ClientDisconnectedFromServerMessage* m = checkedDowncastPtr(msg);
- if(!m->error_message.empty() && !m->closed_gracefully)
- {
- showErrorNotification(m->error_message);
- }
- logMessage("Client disconnected from server " + (m->closed_gracefully ? std::string("gracefully") : std::string("ungracefully")) + ": " + m->error_message);
- this->connection_state = ServerConnectionState_NotConnected;
-
- this->logged_in_user_id = UserID::invalidUserID();
- this->logged_in_user_name = "";
- this->logged_in_user_flags = 0;
- this->logged_in_avatar_settings = AvatarSettings();
-
- ui_interface->setTextAsNotLoggedIn();
-
- ui_interface->updateWorldSettingsControlsEditable();
-
- //updateStatusBar();
- }
- break;
- case Msg_AvatarIsHereMessage:
- {
- const AvatarIsHereMessage* m = checkedDowncastPtr(msg);
-
- if(world_state)
- {
- Lock lock(this->world_state->mutex);
-
- auto res = this->world_state->avatars.find(m->avatar_uid);
- if(res != this->world_state->avatars.end())
- {
- const Avatar* avatar = res->second.getPointer();
-
- if(!avatar->isChatBotAvatar()) // Don't announce that Chatbots are here.
- {
- const std::string use_name = avatar->getUseName();
-
- ui_interface->appendChatMessage("name_colour.r * 255) + ", " + toString(avatar->name_colour.g * 255) + ", " + toString(avatar->name_colour.b * 255) +
- ")\">" + web::Escaping::HTMLEscape(use_name) + " is here.");
- ui_interface->updateOnlineUsersList();
-
- chat_ui.appendMessage(use_name, avatar->name_colour, " is here.");
- }
- }
- }
- }
- break;
- case Msg_AvatarCreatedMessage:
- {
- const AvatarCreatedMessage* m = checkedDowncastPtr(msg);
-
- if(world_state.nonNull())
- {
- Lock lock(this->world_state->mutex);
-
- auto res = this->world_state->avatars.find(m->avatar_uid);
- if(res != this->world_state->avatars.end())
- {
- const Avatar* avatar = res->second.getPointer();
- const std::string use_name = avatar->getUseName();
-
- ui_interface->appendChatMessage("name_colour.r * 255) + ", " + toString(avatar->name_colour.g * 255) + ", " + toString(avatar->name_colour.b * 255) +
- ")\">" + web::Escaping::HTMLEscape(use_name) + " joined.");
- ui_interface->updateOnlineUsersList();
-
- chat_ui.appendMessage(use_name, avatar->name_colour, " joined.");
- }
- }
- }
- break;
- case Msg_AvatarPerformGestureMessage:
- {
- const AvatarPerformGestureMessage* m = checkedDowncastPtr(msg);
-
- if(m->avatar_uid != client_avatar_uid) // Ignore messages about our own avatar
- {
- // For backwards compatibility, if gesture_URL was not sent, just use the gesture name with ".subanim" appended.
- const URLString anim_resource_URL = m->gesture_URL.empty() ? (URLString(m->gesture_name) + ".subanim") : m->gesture_URL;
- if(resource_manager->isFileForURLPresent(anim_resource_URL)) // If the gesture animation file is present on the local disk:
- {
- if(world_state)
- {
- Lock lock(this->world_state->mutex);
-
- auto res = this->world_state->avatars.find(m->avatar_uid);
- if(res != this->world_state->avatars.end())
- {
- // Sync playback.
- // Consider at some time t, 10 seconds from now:
- // t = cur_time + 10
- // and start_global_time = 100, cur_global_time = 105 (e.g. anim was started 5 secs ago by another user)
- // then time_in_anim = t + use_time_offset = (cur_time + 10) + (-cur_time + (cur_global_time - start_global_time))
- // = 10 + (105 - 100) = 10 + 5 = 15
- const double time_offset = world_state->getCurrentGlobalTime() - m->start_global_time;
-
- Avatar* avatar = res->second.getPointer();
- avatar->performGesture(cur_time, m->gesture_name, anim_resource_URL, m->flags, m->start_global_time, time_offset, animation_manager, *resource_manager);
- }
- }
- }
- else
- {
- // Start downloading the animation resource.
- DownloadingResourceInfo info;
- info.pos = cam_controller.getPosition();
- info.size_factor = LoadItemQueueItem::sizeFactorForAABBWS(2.f, /*importance_factor=*/1.f);
- info.used_by_other = true;
- startDownloadingResource(anim_resource_URL, /*centroid_ws=*/cam_controller.getPosition().toVec4fPoint(), 2.f, info);
-
- // Set a variable on the avatar so we know to start playing the gesture when the animation file is downloaded.
- {
- Lock lock(this->world_state->mutex);
- auto res = this->world_state->avatars.find(m->avatar_uid);
- if(res != this->world_state->avatars.end())
- {
- Avatar* avatar = res->second.getPointer();
- avatar->setPendingGesture(m->gesture_name, anim_resource_URL, m->flags, m->start_global_time);
- }
- }
- }
- }
- }
- break;
- case Msg_AvatarStopGestureMessage:
- {
- const AvatarStopGestureMessage* m = checkedDowncastPtr(msg);
-
- if(m->avatar_uid != client_avatar_uid) // Ignore messages about our own avatar
- {
- if(world_state.nonNull())
- {
- Lock lock(this->world_state->mutex);
-
- auto res = this->world_state->avatars.find(m->avatar_uid);
- if(res != this->world_state->avatars.end())
- {
- Avatar* avatar = res->second.getPointer();
- avatar->stopGesture(cur_time);
- avatar->clearPendingGesture(); // Since we have received a stop-gesture message for this avatar, we don't want to start playing the anim when we download the animation file.
- }
- }
- }
- }
- break;
- case Msg_ChatMessage:
- {
- const ChatMessage* m = checkedDowncastPtr(msg);
-
- if(world_state.nonNull())
- {
- // Look up sending avatar name colour. TODO: could do this with sending avatar UID, would be faster + simpler.
- Colour3f col(0.8f);
- std::string use_avatar_name = m->name;
- {
- Lock lock(this->world_state->mutex);
-
- auto res = this->world_state->avatars.find(m->sender_avatar_uid);
- if(res != this->world_state->avatars.end())
- {
- use_avatar_name = res->second->getUseName();
- col = res->second->name_colour;
- }
- }
-
- ui_interface->appendChatMessage(
- "" + web::Escaping::HTMLEscape(use_avatar_name) + ": " +
- web::Escaping::HTMLEscape(m->msg) + "
");
-
- chat_ui.appendMessage(use_avatar_name, col, ": " + m->msg);
-
-
- // Execute any onChatMessage event handlers.
- if(m->sender_avatar_uid.valid())
- {
- WorldStateLock lock(world_state->mutex);
-
- WorldObjectRef* const objects_data = scripted_ob_proximity_checker.objects.vector.data(); // NOTE: scripted_ob_proximity_checker just has all objects with Lua scripts currently.
- const size_t objects_size = scripted_ob_proximity_checker.objects.vector.size();
- for(size_t i=0; ievent_handlers && ob->event_handlers->onChatMessage_handlers.nonEmpty())
- {
- ob->event_handlers->executeOnChatMessageHandlers(m->sender_avatar_uid, m->msg, lock);
- }
- }
- }
- }
- }
- break;
- case Msg_InfoMessage:
- {
- const InfoMessage* m = checkedDowncastPtr(msg);
- showInfoNotification(m->msg);
- }
- break;
- case Msg_ErrorMessage:
- {
- const ErrorMessage* m = checkedDowncastPtr(msg);
- showErrorNotification(m->msg);
- }
- break;
- case Msg_LogMessage:
- {
- const LogMessage* m = checkedDowncastPtr(msg);
- logMessage(m->msg);
- }
- break;
- case Msg_LoggedInMessage:
- {
- const LoggedInMessage* m = checkedDowncastPtr(msg);
-
- ui_interface->setTextAsLoggedIn(m->username);
- this->logged_in_user_id = m->user_id;
- this->logged_in_user_name = m->username;
- this->logged_in_user_flags = m->user_flags;
- this->logged_in_avatar_settings = m->avatar_settings;
-
- logMessage("Logged in as '" + m->username + "', id " + toString(this->logged_in_user_id.value()));
-
- recolourParcelsForLoggedInState();
- ui_interface->updateWorldSettingsControlsEditable();
-
- misc_info_ui.showLoggedInButton(m->username);
-
- // If this server has sent the user's custom gesture settings, update the gesture UI with them.
- if(!m->gesture_settings.gesture_settings.empty())
- gesture_ui.setCurrentGestureSettings(m->gesture_settings);
-
-
- // Send AvatarFullUpdate message, to change the nametag on our avatar.
- const Vec3d cam_angles = this->cam_controller.getAvatarAngles();
- Avatar avatar;
- avatar.uid = this->client_avatar_uid;
- avatar.pos = Vec3d(this->cam_controller.getFirstPersonPosition());
- avatar.rotation = Vec3f(0, (float)cam_angles.y, (float)cam_angles.x);
- avatar.avatar_settings = m->avatar_settings;
- avatar.name = m->username;
-
- MessageUtils::initPacket(scratch_packet, Protocol::AvatarFullUpdate);
- writeAvatarToNetworkStream(avatar, scratch_packet);
-
- enqueueMessageToSend(*this->client_thread, scratch_packet);
- }
- break;
- case Msg_LoggedOutMessage:
- {
- ui_interface->setTextAsNotLoggedIn();
- this->logged_in_user_id = UserID::invalidUserID();
- this->logged_in_user_name = "";
- this->logged_in_user_flags = 0;
- this->logged_in_avatar_settings = AvatarSettings();
-
- recolourParcelsForLoggedInState();
- ui_interface->updateWorldSettingsControlsEditable();
-
- misc_info_ui.showLogInAndSignUpButtons();
-
- // Send AvatarFullUpdate message, to change the nametag on our avatar.
- const Vec3d cam_angles = this->cam_controller.getAvatarAngles();
- Avatar avatar;
- avatar.uid = this->client_avatar_uid;
- avatar.pos = Vec3d(this->cam_controller.getFirstPersonPosition());
- avatar.rotation = Vec3f(0, (float)cam_angles.y, (float)cam_angles.x);
- avatar.avatar_settings.model_url = "";
- avatar.name = "Anonymous";
-
- MessageUtils::initPacket(scratch_packet, Protocol::AvatarFullUpdate);
- writeAvatarToNetworkStream(avatar, scratch_packet);
-
- enqueueMessageToSend(*this->client_thread, scratch_packet);
- }
- break;
- case Msg_SignedUpMessage:
- {
- const SignedUpMessage* m = checkedDowncastPtr(msg);
- ui_interface->showPlainTextMessageBox("Signed up", "Successfully signed up and logged in.");
-
- ui_interface->setTextAsLoggedIn(m->username);
- this->logged_in_user_id = m->user_id;
- this->logged_in_user_name = m->username;
- this->logged_in_user_flags = 0;
-
- misc_info_ui.showLoggedInButton(m->username);
-
- // Send AvatarFullUpdate message, to change the nametag on our avatar.
- const Vec3d cam_angles = this->cam_controller.getAvatarAngles();
- Avatar avatar;
- avatar.uid = this->client_avatar_uid;
- avatar.pos = Vec3d(this->cam_controller.getFirstPersonPosition());
- avatar.rotation = Vec3f(0, (float)cam_angles.y, (float)cam_angles.x);
- avatar.avatar_settings.model_url = "";
- avatar.name = m->username;
-
- MessageUtils::initPacket(scratch_packet, Protocol::AvatarFullUpdate);
- writeAvatarToNetworkStream(avatar, scratch_packet);
-
- enqueueMessageToSend(*this->client_thread, scratch_packet);
- }
- break;
- case Msg_ServerAdminMessage:
- {
- const ServerAdminMessage* m = checkedDowncastPtr(msg);
-
- misc_info_ui.showServerAdminMessage(m->msg);
- }
- break;
- case Msg_WorldSettingsReceivedMessage:
- {
- const WorldSettingsReceivedMessage* m = checkedDowncastPtr(msg);
-
- this->connected_world_settings.copyNetworkStateFrom(m->world_settings); // Store world settings to be used later
- this->received_world_settings_since_connect_or_world_change = true;
-
- this->ui_interface->updateWorldSettingsUIFromWorldSettings(); // Update UI
-
- if(!m->is_initial_send)
- showInfoNotification("World settings updated");
-
- // Reload terrain by shutting it down, will be recreated in GUIClient::updateGroundPlane().
- if(this->terrain_system.nonNull())
- {
- terrain_system->shutdown();
- terrain_system = NULL;
- }
-
- if(physics_world.nonNull())
- {
- physics_world->setWaterBuoyancyEnabled(BitUtils::isBitSet(this->connected_world_settings.terrain_spec.flags, TerrainSpec::WATER_ENABLED_FLAG));
- const float use_water_z = myClamp(this->connected_world_settings.terrain_spec.water_z, -1.0e8f, 1.0e8f); // Avoid NaNs, Infs etc.
- physics_world->setWaterZ(use_water_z);
- }
-
- if(opengl_engine)
- {
- const float sun_phi = this->connected_world_settings.sun_phi;
- const float sun_theta = this->connected_world_settings.sun_theta;
- opengl_engine->setEnvMapTransform(Matrix3f::rotationAroundZAxis(sun_phi));
-
- {
- OpenGLMaterial env_mat;
- env_mat.tex_matrix = Matrix2f(-1 / Maths::get2Pi(), 0, 0, 1 / Maths::pi());
- opengl_engine->setEnvMat(env_mat);
- }
-
- opengl_engine->setSunDir(normalise(Vec4f(std::cos(sun_phi) * sin(sun_theta), std::sin(sun_phi) * sin(sun_theta), cos(sun_theta), 0)));
- }
- }
- break;
- case Msg_WorldDetailsReceivedMessage:
- {
- const WorldDetailsReceivedMessage* m = checkedDowncastPtr(msg);
-
- this->connected_world_details = m->world_details;
- }
- break;
- case Msg_MapTilesResultReceivedMessage:
- {
- const MapTilesResultReceivedMessage* m = checkedDowncastPtr(msg);
-
- if(minimap)
- this->minimap->handleMapTilesResultReceivedMessage(*m);
- }
- break;
- case Msg_UserSelectedObjectMessage:
- {
- if(world_state.nonNull())
- {
- //print("GUIClient: Received UserSelectedObjectMessage");
- const UserSelectedObjectMessage* m = checkedDowncastPtr(msg);
- Lock lock(this->world_state->mutex);
- const bool is_ob_with_uid_inserted = this->world_state->objects.find(m->object_uid) != this->world_state->objects.end();
- if(this->world_state->avatars.count(m->avatar_uid) != 0 && is_ob_with_uid_inserted)
- {
- this->world_state->avatars[m->avatar_uid]->selected_object_uid = m->object_uid;
- }
- }
- }
- break;
- case Msg_UserDeselectedObjectMessage:
- {
- if(world_state.nonNull())
- {
- //print("GUIClient: Received UserDeselectedObjectMessage");
- const UserDeselectedObjectMessage* m = checkedDowncastPtr(msg);
- Lock lock(this->world_state->mutex);
- if(this->world_state->avatars.count(m->avatar_uid) != 0)
- {
- this->world_state->avatars[m->avatar_uid]->selected_object_uid = UID::invalidUID();
- }
- }
- }
- break;
- case Msg_GetFileMessage:
- {
- // When the server wants a file from the client, it will send the client a GetFile protocol message.
- const GetFileMessage* m = checkedDowncastPtr(msg);
-
- if(ResourceManager::isValidURL(m->URL))
- {
- if(resource_manager->isFileForURLPresent(m->URL))
- {
- const std::string path = resource_manager->pathForURL(m->URL);
-
- const std::string username = ui_interface->getUsernameForDomain(server_hostname);
- const std::string password = ui_interface->getDecryptedPasswordForDomain(server_hostname);
-
- this->num_resources_uploading++;
-#if EMSCRIPTEN
- const size_t max_num_upload_threads = 1;
-#else
- const size_t max_num_upload_threads = 4;
-#endif
- if(resource_upload_thread_manager.getNumThreads() == 0)
- {
- for(size_t q=0; qmsg_queue, &upload_queue, server_hostname, server_port, username, password, this->client_tls_config,
- &this->num_resources_uploading));
- }
-
- upload_queue.enqueue(new ResourceToUpload(path, m->URL));
-
- print("Received GetFileMessage, Uploading resource with URL '" + toStdString(m->URL) + "' to server.");
- }
- else
- print("Could not upload resource with URL '" + toStdString(m->URL) + "' to server, not present on client.");
- }
- }
- break;
- case Msg_NewResourceOnServerMessage:
- {
- // When the server has a file uploaded to it, it will send a NewResourceOnServer message to clients, so they can download it.
-
- const NewResourceOnServerMessage* m = checkedDowncastPtr(msg);
-
- if(world_state.nonNull())
- {
- logMessage("Got NewResourceOnServerMessage, URL: " + toStdString(m->URL));
-
- // A download of this resource may have failed earlier, but should succeed now.
- resource_manager->removeFromDownloadFailedURLs(m->URL);
-
- if(ResourceManager::isValidURL(m->URL))
- {
- if(!resource_manager->isFileForURLPresent(m->URL)) // If we don't have this file yet:
- {
- conPrint("Do not have resource.");
-
- DownloadingResourceInfo downloading_info;
- Vec4f centroid_ws(0,0,0,1);
- float aabb_ws_longest_len = 1.f;
-
- // Iterate over objects and see if they were using a placeholder model for this resource.
- Lock lock(this->world_state->mutex);
- bool need_resource = false;
- for(auto it = this->world_state->objects.valuesBegin(); it != this->world_state->objects.valuesEnd(); ++it)
- {
- WorldObject* ob = it.getValue().ptr();
-
- const int ob_lod_level = ob->getLODLevel(cam_controller.getPosition());
-
- //if(ob->using_placeholder_model)
- {
- glare::ArenaFrame frame(arena_allocator);
- glare::STLArenaAllocator stl_arena_allocator(&arena_allocator);
-
- WorldObject::GetDependencyOptions options;
- options.use_basis = this->server_has_basis_textures;
- options.include_lightmaps = this->use_lightmaps;
- options.get_optimised_mesh = this->server_has_optimised_meshes;
- options.opt_mesh_version = this->server_opt_mesh_version;
- options.allocator = &arena_allocator;
-
- DependencyURLSet URL_set(std::less(), stl_arena_allocator);
- ob->getDependencyURLSet(ob_lod_level, options, URL_set);
-
- if(URL_set.count(DependencyURL(m->URL)) != 0)
- {
- downloading_info.texture_params.use_sRGB = true; // TEMP HACK
- downloading_info.build_dynamic_physics_ob = ob->isDynamic();
- downloading_info.pos = ob->pos;
- downloading_info.size_factor = LoadItemQueueItem::sizeFactorForAABBWS(ob->getAABBWSLongestLength(), /*importance_factor=*/1.f);
- downloading_info.using_objects.using_object_uids.push_back(ob->uid);
- centroid_ws = ob->getCentroidWS();
- aabb_ws_longest_len = ob->getAABBWSLongestLength();
-
- need_resource = true;
- }
- }
- }
-
- for(auto it = this->world_state->avatars.begin(); it != this->world_state->avatars.end(); ++it)
- {
- Avatar* av = it->second.getPointer();
-
- const int av_lod_level = av->getLODLevel(cam_controller.getPosition());
-
- //if(ob->using_placeholder_model)
- {
- glare::ArenaFrame frame(arena_allocator);
- glare::STLArenaAllocator stl_arena_allocator(&arena_allocator);
-
- Avatar::GetDependencyOptions options;
- options.get_optimised_mesh = this->server_has_optimised_meshes;
- options.opt_mesh_version = this->server_opt_mesh_version;
- options.use_basis = this->server_has_basis_textures;
-
- DependencyURLSet URL_set(std::less(), stl_arena_allocator);
- av->getDependencyURLSet(av_lod_level, options, URL_set);
-
- if(URL_set.count(DependencyURL(m->URL)) != 0)
- {
- downloading_info.texture_params.use_sRGB = true; // TEMP HACK
- downloading_info.build_physics_ob = false;
- downloading_info.pos = av->pos;
- downloading_info.size_factor = LoadItemQueueItem::sizeFactorForAABBWS(1.8f, /*importance_factor=*/1.f);
- downloading_info.used_by_other = true;
- centroid_ws = av->pos.toVec4fPoint();
- aabb_ws_longest_len = 1.8f;
-
- need_resource = true;
- }
- }
- }
-
- if(::hasExtension(m->URL, "subanim")) // Just consider all animations (used for gestures) needed for now.
- need_resource = true;
-
- const bool valid_extension = FileTypes::hasSupportedExtension(m->URL);
- conPrint("need_resource: " + boolToString(need_resource) + " valid_extension: " + boolToString(valid_extension));
-
- if(need_resource && valid_extension)// && !shouldStreamResourceViaHTTP(m->URL))
- {
- conPrint("Need resource, downloading: " + toStdString(m->URL));
-
- startDownloadingResource(m->URL, centroid_ws, aabb_ws_longest_len, downloading_info);
- }
- }
- }
- }
- }
- break;
- case Msg_ResourceDownloadedMessage:
- {
- const ResourceDownloadedMessage* m = checkedDowncastPtr(msg);
- const URLString& URL = m->URL;
- ResourceRef resource = m->resource;
-
-#if !defined(EMSCRIPTEN)
- logMessage("Resource downloaded: '" + toStdString(URL) + "'");
-#endif
-
- if(world_state.nonNull())
- {
- assert(resource.nonNull()); // The downloaded file should have been added as a resource in DownloadResourcesThread or NetDownloadResourcesThread.
- if(resource.nonNull())
- {
- // Get the local path, we will check the file type of the local path when determining what to do with the file, as the local path will have an extension given by the mime type
- // in the net download case.
- const std::string local_path = resource_manager->getLocalAbsPathForResource(*resource);
-
- auto res = URL_to_downloading_info.find(URL);
- if(res != URL_to_downloading_info.end())
- {
- const DownloadingResourceInfo& info = res->second;
- const Vec3d pos = info.pos;
- const float size_factor = info.size_factor;
-
- if(isDownloadingResourceCurrentlyNeeded(URL))
- {
- // If we just downloaded a texture, start loading it.
- if(ImageDecoding::hasSupportedImageExtension(local_path))
- {
- //conPrint("Downloaded texture resource, loading it...");
-
- const OpenGLTextureKey tex_path(local_path);
-
- // NOTE: For the terrain texture case, we need the CPU texture (Map2D), not just the GPU texture.
- // So load the texture in a LoadTextureTask even if the GPU texture is in the opengl engine.
-
- if(!opengl_engine->isOpenGLTextureInsertedForKey(tex_path) || info.used_by_terrain) // If texture is not uploaded to GPU already:
- {
- const bool just_added = checkAddTextureToProcessingSet(tex_path); // If not being loaded already:
- if(just_added)
- {
- Reference task = new LoadTextureTask(opengl_engine, resource_manager, &this->msg_queue, tex_path, resource, info.texture_params, info.used_by_terrain, worker_allocator,
- texture_loaded_msg_allocator, opengl_upload_thread);
- task->loaded_buffer = m->loaded_buffer;
- load_item_queue.enqueueItem(/*key=*/URL, pos.toVec4fPoint(), size_factor, task, /*max task dist=*/std::numeric_limits::infinity()); // NOTE: inf dist is a bit of a hack.
- }
- else
- load_item_queue.checkUpdateItemPosition(/*key=*/URL, pos.toVec4fPoint(), size_factor);
- }
- }
- else if(FileTypes::hasAudioFileExtension(local_path))
- {
- Lock lock(this->world_state->mutex);
- for(size_t i=0; iobjects.find(info.using_objects.using_object_uids[i]);
- if(ob_res != world_state->objects.end())
- {
- WorldObject* ob = ob_res.getValue().ptr();
- if(ob->audio_source_url == URL)
- loadAudioForObject(ob, m->loaded_buffer);
- }
- }
- }
- else if(ModelLoading::hasSupportedModelExtension(local_path)) // Else we didn't download a texture, but maybe a model:
- {
- try
- {
- // Start loading the model
- Reference load_model_task = new LoadModelTask();
-
- load_model_task->resource = resource;
- load_model_task->lod_model_url = URL;
- load_model_task->model_lod_level = WorldObject::getLODLevelForURL(URL);
- load_model_task->opengl_engine = this->opengl_engine;
- load_model_task->result_msg_queue = &this->msg_queue;
- load_model_task->resource_manager = resource_manager;
- load_model_task->build_physics_ob = info.build_physics_ob;
- load_model_task->build_dynamic_physics_ob = info.build_dynamic_physics_ob;
- load_model_task->loaded_buffer = m->loaded_buffer;
- load_model_task->worker_allocator = worker_allocator;
- load_model_task->upload_thread = opengl_upload_thread;
-
- // conPrint("handling ResourceDownloadedMessage: making LoadModelTask for " + URL);
-
- load_item_queue.enqueueItem(/*key=*/URL, pos.toVec4fPoint(), size_factor, load_model_task,
- /*max task dist=*/std::numeric_limits::infinity()); // NOTE: inf dist is a bit of a hack.
- }
- catch(glare::Exception& e)
- {
- print("Error while loading object: " + e.what());
- }
- }
- else if(hasExtension(local_path, "subanim"))
- {
- handleDownloadedAnimationResource(local_path, resource, m->loaded_buffer);
- }
- else
- {
- // TODO: Handle video files here?
-
- //print("file did not have a supported image, audio, or model extension: '" + getExtension(local_path) + "'");
- }
- }
- else
- {
- // conPrint("GUIClient handleMessage(): downloaded resource '" + toStdString(URL) + "' is not currently used, not loading.");
- }
- }
- else
- {
- assert(0); // If we downloaded the resource we should have added it to URL_to_downloading_info. NOTE: will this work with NewResourceOnServerMessage tho?
- }
- }
- }
- }
- break;
- case Msg_TerrainChunkGeneratedMsg:
- {
- const TerrainChunkGeneratedMsg* m = checkedDowncastPtr