private void UpdateUI(LoadedAvatar avatar) { SetInteractableRecursively(avatar != null); UpdateCalibrationButtons(avatar); if (avatar == null) { _clearButton.interactable = false; _calibrateButton.interactable = false; _automaticCalibrationSetting.interactable = false; _automaticCalibrationHoverHint.text = "No avatar selected"; return; } _currentAvatarSettings = _settings.GetAvatarSettings(avatar.fileName); _currentAvatarManualCalibration = _calibrationData.GetAvatarManualCalibration(avatar.fileName); _ignoreExclusionsSetting.Value = _currentAvatarSettings.ignoreExclusions; _bypassCalibration.Value = _currentAvatarSettings.bypassCalibration; _automaticCalibrationSetting.Value = _currentAvatarSettings.useAutomaticCalibration; _automaticCalibrationSetting.interactable = avatar.descriptor.supportsAutomaticCalibration; _automaticCalibrationHoverHint.text = avatar.descriptor.supportsAutomaticCalibration ? "Use automatic calibration instead of manual calibration." : "Not supported by current avatar"; }
public static async Task <string> RecalculateHashForAvatar(LoadedAvatar info) { FileInfo file = new FileInfo(Path.Combine(Path.GetFullPath("CustomAvatars"), info.fullPath)); Plugin.log.Info($"Calculating hash for avatar \"{info.descriptor.name}\"..."); var newHash = await CalculateHash(Path.Combine(Path.GetFullPath("CustomAvatars"), info.fullPath)); HashData data = new HashData() { lastWriteTime = file.LastWriteTimeUtc, hash = newHash }; if (_hashes.ContainsKey(info.fullPath)) { _hashes[info.fullPath] = data; } else { _hashes.Add(info.fullPath, data); } Save(); return(newHash); }
private void UpdateUI(LoadedAvatar avatar) { DisableCalibrationMode(false); if (avatar == null) { _clearButton.interactable = false; _calibrateButton.interactable = false; _automaticCalibrationSetting.checkbox.interactable = false; _automaticCalibrationHoverHint.text = "No avatar selected"; return; } _currentAvatarSettings = _settings.GetAvatarSettings(avatar.fileName); _currentAvatarManualCalibration = _calibrationData.GetAvatarManualCalibration(avatar.fileName); UpdateCalibrationButtons(avatar); _ignoreExclusionsSetting.CheckboxValue = _currentAvatarSettings.ignoreExclusions; _bypassCalibration.CheckboxValue = _currentAvatarSettings.bypassCalibration; _bypassCalibration.checkbox.interactable = avatar.supportsFullBodyTracking; _bypassCalibrationHoverHint.text = avatar.supportsFullBodyTracking ? "Disable the need for calibration before full body tracking is applied." : "Not supported by current avatar"; _automaticCalibrationSetting.CheckboxValue = _currentAvatarSettings.useAutomaticCalibration; _automaticCalibrationSetting.checkbox.interactable = avatar.descriptor.supportsAutomaticCalibration; _automaticCalibrationHoverHint.text = avatar.descriptor.supportsAutomaticCalibration ? "Use automatic calibration instead of manual calibration." : "Not supported by current avatar"; }
internal AvatarListItem(LoadedAvatar avatar) { name = avatar.descriptor.name; author = avatar.descriptor.author; icon = avatar.descriptor.cover?.texture; this.avatar = avatar; }
public void GetAvatarsAsync(Action <LoadedAvatar> success, Action <Exception> error) { Plugin.logger.Info("Loading all avatars from " + kCustomAvatarsPath); foreach (string fileName in GetAvatarFileNames()) { SharedCoroutineStarter.instance.StartCoroutine(LoadedAvatar.FromFileCoroutine(fileName, success, error)); } }
public void SwitchToAvatarAsync(string filePath) { SharedCoroutineStarter.instance.StartCoroutine(LoadedAvatar.FromFileCoroutine(filePath, avatar => { Plugin.logger.Info("Successfully loaded avatar " + avatar.descriptor.name); SwitchToAvatar(avatar); }, ex => { Plugin.logger.Error("Failed to load avatar: " + ex.Message); })); }
private void CreateAvatar(LoadedAvatar avatar) { loadedAvatar = avatar; if (spawnedAvatar != null) { Destroy(spawnedAvatar); } spawnedAvatar = _avatarSpawner.SpawnAvatar(avatar, new MultiplayerAvatarInput(poseController, transform.name != "MultiplayerLobbyAvatar(Clone)"), poseController.transform); spawnedAvatar.SetLocomotionEnabled(true); spawnedAvatar.scale = avatarData.scale; }
private void UpdateCalibrationButtons(LoadedAvatar avatar) { if (!_playerInput.TryGetUncalibratedPose(DeviceUse.Waist, out Pose _) && !_playerInput.TryGetUncalibratedPose(DeviceUse.LeftFoot, out Pose _) && !_playerInput.TryGetUncalibratedPose(DeviceUse.RightFoot, out Pose _)) { _autoCalibrateButton.interactable = false; _autoClearButton.interactable = _calibrationData.automaticCalibration.isCalibrated; _autoCalibrateButtonHoverHint.text = "No trackers detected"; _calibrateButton.interactable = false; _clearButton.interactable = _currentAvatarManualCalibration?.isCalibrated == true; _calibrateButtonHoverHint.text = "No trackers detected"; _calibrateButtonText.text = "Calibrate"; _clearButtonText.text = "Clear"; return; } bool isManualCalibrationPossible = avatar != null && avatar.supportsFullBodyTracking; bool isAutomaticCalibrationPossible = isManualCalibrationPossible && avatar.descriptor.supportsAutomaticCalibration; if (isAutomaticCalibrationPossible) { _autoCalibrateButton.interactable = true; _autoClearButton.interactable = _calibrationData.automaticCalibration.isCalibrated; _autoCalibrateButtonHoverHint.text = "Calibrate full body tracking automatically"; } else { _autoCalibrateButton.interactable = false; _autoClearButton.interactable = false; _autoCalibrateButtonHoverHint.text = "Not supported by current avatar"; } if (isManualCalibrationPossible) { _calibrateButton.interactable = true; _clearButton.interactable = _calibrating || _currentAvatarManualCalibration?.isCalibrated == true; _calibrateButtonHoverHint.text = "Start manual full body calibration"; _calibrateButtonText.text = _calibrating ? "Save" : "Calibrate"; _clearButtonText.text = _calibrating ? "Cancel" : "Clear"; } else { _calibrateButton.interactable = false; _clearButton.interactable = false; _calibrateButtonHoverHint.text = "Not supported by current avatar"; _calibrateButtonText.text = "Calibrate"; _clearButtonText.text = "Clear"; } }
private static SpawnedAvatar SpawnAvatar(LoadedAvatar customAvatar, AvatarInput input) { if (customAvatar == null) { throw new ArgumentNullException(nameof(customAvatar)); } if (input == null) { throw new ArgumentNullException(nameof(input)); } var spawnedAvatar = new SpawnedAvatar(customAvatar, input); return(spawnedAvatar); }
public static async Task <string> GetHashForAvatar(LoadedAvatar info, bool save = true) { if (_hashes.TryGetValue(info.fullPath, out var data)) { FileInfo file = new FileInfo(Path.Combine(Path.GetFullPath("CustomAvatars"), info.fullPath)); if (file.LastWriteTimeUtc != data.lastWriteTime) { Plugin.log.Info($"Calculating hash for avatar \"{info.descriptor.name}\"..."); var newHash = await CalculateHash(Path.Combine(Path.GetFullPath("CustomAvatars"), info.fullPath)); data.lastWriteTime = file.LastWriteTimeUtc; data.hash = newHash; _hashes[info.fullPath] = data; if (save) { Save(); } return(newHash); } else { return(data.hash); } } else { FileInfo file = new FileInfo(Path.Combine(Path.GetFullPath("CustomAvatars"), info.fullPath)); Plugin.log.Info($"Calculating hash for avatar \"{info.descriptor.name}\"..."); var newHash = await CalculateHash(Path.Combine(Path.GetFullPath("CustomAvatars"), info.fullPath)); data.lastWriteTime = file.LastWriteTimeUtc; data.hash = newHash; _hashes[info.fullPath] = data; if (save) { Save(); } return(newHash); } }
internal VRPlayerInput(TrackedDeviceManager trackedDeviceManager, LoadedAvatar avatar, Settings settings, CalibrationData calibrationData) { _deviceManager = trackedDeviceManager; _settings = settings; _avatarSettings = settings.GetAvatarSettings(avatar.fileName); _calibrationData = calibrationData; _manualCalibration = calibrationData.GetAvatarManualCalibration(avatar.fileName); _deviceManager.deviceAdded += OnDevicesUpdated; _deviceManager.deviceRemoved += OnDevicesUpdated; _deviceManager.deviceTrackingAcquired += OnDevicesUpdated; _deviceManager.deviceTrackingLost += OnDevicesUpdated; _leftHandAnimAction = new SkeletalInput("/actions/customavatars/in/lefthandanim"); _rightHandAnimAction = new SkeletalInput("/actions/customavatars/in/righthandanim"); }
private void UpdateCalibrationButtons(LoadedAvatar avatar) { if (!_trackedDeviceManager.waist.tracked && !_trackedDeviceManager.leftFoot.tracked && !_trackedDeviceManager.rightFoot.tracked) { _autoCalibrateButton.interactable = false; _autoClearButton.interactable = false; _autoCalibrateButtonHoverHint.text = "No trackers detected"; _calibrateButton.interactable = false; _clearButton.interactable = false; _calibrateButtonHoverHint.text = "No trackers detected"; return; } bool isManualCalibrationPossible = avatar != null && avatar.isIKAvatar && avatar.supportsFullBodyTracking; bool isAutomaticCalibrationPossible = isManualCalibrationPossible && avatar.descriptor.supportsAutomaticCalibration; if (isAutomaticCalibrationPossible) { _autoCalibrateButton.interactable = true; _autoClearButton.interactable = _currentAvatarManualCalibration.isCalibrated; _autoCalibrateButtonHoverHint.text = "Calibrate full body tracking automatically"; } else { _autoCalibrateButton.interactable = false; _autoClearButton.interactable = false; _autoCalibrateButtonHoverHint.text = "Not supported by current avatar"; } if (isManualCalibrationPossible) { _calibrateButton.interactable = true; _clearButton.interactable = _currentAvatarManualCalibration.isCalibrated; _calibrateButtonHoverHint.text = "Start manual full body calibration"; } else { _calibrateButton.interactable = false; _clearButton.interactable = false; _calibrateButtonHoverHint.text = "Not supported by current avatar"; } }
private void SwitchToAvatar(LoadedAvatar avatar) { if ((currentlySpawnedAvatar && currentlySpawnedAvatar.avatar == avatar) || avatar?.fullPath != _switchingToPath) { avatar?.Dispose(); return; } if (avatar == null) { _logger.Info("No avatar selected"); avatarChanged?.Invoke(null); _settings.previousAvatarPath = null; UpdateFloorOffsetForCurrentAvatar(); return; } var avatarInfo = new AvatarInfo(avatar); _settings.previousAvatarPath = avatarInfo.fileName; // cache avatar info since loading asset bundles is expensive if (_avatarInfos.ContainsKey(avatarInfo.fileName)) { _avatarInfos[avatarInfo.fileName] = avatarInfo; } else { _avatarInfos.Add(avatarInfo.fileName, avatarInfo); } currentlySpawnedAvatar = _spawner.SpawnAvatar(avatar, _container.Resolve <VRPlayerInput>(), _avatarContainer.transform); _currentAvatarSettings = _settings.GetAvatarSettings(avatar.fileName); ResizeCurrentAvatar(); UpdateFirstPersonVisibility(); UpdateLocomotionEnabled(); avatarChanged?.Invoke(currentlySpawnedAvatar); }
public static void LoadAvatars() { if (defaultAvatarInstance == null) { if (Config.Instance.DownloadAvatars) { defaultAvatarInstance = ModelSaberAPI.cachedAvatars.FirstOrDefault(x => x.Value.fullPath.ToLower().Contains("loading.avatar")).Value; if (defaultAvatarInstance == null)//fallback to multiplayer avatar { defaultAvatarInstance = ModelSaberAPI.cachedAvatars.FirstOrDefault(x => x.Value.fullPath.ToLower().Contains("multiplayer.avatar")).Value; } if (defaultAvatarInstance == null)//fallback to default avatar { defaultAvatarInstance = ModelSaberAPI.cachedAvatars.FirstOrDefault(x => x.Value.fullPath.ToLower().Contains("templatefullbody.avatar")).Value; } if (defaultAvatarInstance == null)//fallback to ANY avatar { defaultAvatarInstance = ModelSaberAPI.cachedAvatars.FirstOrDefault().Value; } } else { defaultAvatarInstance = ModelSaberAPI.cachedAvatars.FirstOrDefault(x => x.Value.fullPath.ToLower().Contains("multiplayer.avatar")).Value; if (defaultAvatarInstance == null)//fallback to default avatar { defaultAvatarInstance = ModelSaberAPI.cachedAvatars.FirstOrDefault(x => x.Value.fullPath.ToLower().Contains("templatefullbody.avatar")).Value; } if (defaultAvatarInstance == null)//fallback to ANY avatar { defaultAvatarInstance = ModelSaberAPI.cachedAvatars.FirstOrDefault().Value; } } } }
public void SwitchToAvatar(LoadedAvatar avatar) { if (currentlySpawnedAvatar?.customAvatar == avatar) { return; } currentlySpawnedAvatar?.Destroy(); currentlySpawnedAvatar = null; SettingsManager.settings.previousAvatarPath = avatar?.fullPath; if (avatar == null) { return; } currentlySpawnedAvatar = SpawnAvatar(avatar, new VRAvatarInput()); avatarChanged?.Invoke(currentlySpawnedAvatar); ResizeCurrentAvatar(); currentlySpawnedAvatar?.OnFirstPersonEnabledChanged(); }
public void SetPlayerInfo(PlayerInfo _playerInfo, float offset, bool isLocal) { if (_playerInfo == default) { if (playerNameText != null) { playerNameText.gameObject.SetActive(false); } if (playerSpeakerIcon != null) { playerSpeakerIcon.gameObject.SetActive(false); } if (avatar != null && avatar.eventsPlayer != null) { avatar.Destroy(); avatar = null; } return; } try { playerInfo = _playerInfo.updateInfo; playerId = _playerInfo.playerId; playerAvatarHash = _playerInfo.avatarHash; playerName = _playerInfo.playerName; if (playerNameText != null && playerSpeakerIcon != null) { if (isLocal) { playerNameText.gameObject.SetActive(false); playerSpeakerIcon.gameObject.SetActive(false); #if !DEBUG if (avatar != null && avatar.eventsPlayer != null) { avatar.Destroy(); } #endif } else { playerNameText.gameObject.SetActive(true); playerNameText.alignment = TextAlignmentOptions.Center; playerSpeakerIcon.gameObject.SetActive(InGameOnlineController.Instance.VoiceChatIsTalking(playerId)); } } else { return; } #if !DEBUG if ((avatar == null || currentAvatarHash != playerAvatarHash) && !isLocal) #else if ((avatar == null || currentAvatarHash != playerAvatarHash)) #endif { if (unableToSpawnAvatar) { if (retryTimeCounter + 5f > Time.realtimeSinceStartup) { retryTimeCounter = -1f; unableToSpawnAvatar = false; } } else { if (ModelSaberAPI.cachedAvatars.ContainsKey(playerAvatarHash)) { LoadedAvatar cachedAvatar = ModelSaberAPI.cachedAvatars[playerAvatarHash]; if (cachedAvatar != null) { if (avatar != null && avatar.eventsPlayer != null) { avatar.Destroy(); avatar = null; } avatar = AvatarManager.SpawnAvatar(cachedAvatar, avatarInput); avatar.SetChildrenToLayer(10); currentAvatarHash = playerAvatarHash; } else { unableToSpawnAvatar = true; retryTimeCounter = Time.realtimeSinceStartup; } } else { if (Config.Instance.DownloadAvatars) { if (!Config.Instance.DownloadNSFWAvatars && ModelSaberAPI.nsfwAvatars.Contains(playerAvatarHash)) { unableToSpawnAvatar = true; retryTimeCounter = Time.realtimeSinceStartup; } else { ModelSaberAPI.avatarDownloaded -= AvatarDownloaded; ModelSaberAPI.avatarDownloaded += AvatarDownloaded; if (!ModelSaberAPI.queuedAvatars.Contains(playerAvatarHash)) { SharedCoroutineStarter.instance.StartCoroutine(ModelSaberAPI.DownloadAvatarCoroutine(playerAvatarHash)); if (avatar != null && avatar.eventsPlayer != null) { avatar.Destroy(); } avatar = AvatarManager.SpawnAvatar(defaultAvatarInstance, avatarInput); avatar.SetChildrenToLayer(10); } } } } } } Vector3 offsetVector = new Vector3(offset, 0f, 0f); avatarInput.headPos = playerInfo.headPos + offsetVector; avatarInput.rightHandPos = playerInfo.rightHandPos + offsetVector; avatarInput.leftHandPos = playerInfo.leftHandPos + offsetVector; avatarInput.headRot = playerInfo.headRot; avatarInput.rightHandRot = playerInfo.rightHandRot; avatarInput.leftHandRot = playerInfo.leftHandRot; avatarInput.poseValid = true; avatarInput.fullBodyTracking = playerInfo.fullBodyTracking; if (playerInfo.fullBodyTracking) { avatarInput.rightLegPos = playerInfo.rightLegPos + offsetVector; avatarInput.leftLegPos = playerInfo.leftLegPos + offsetVector; avatarInput.pelvisPos = playerInfo.pelvisPos + offsetVector; avatarInput.rightLegRot = playerInfo.rightLegRot; avatarInput.leftLegRot = playerInfo.leftLegRot; avatarInput.pelvisRot = playerInfo.pelvisRot; } transform.position = avatarInput.headPos; playerNameText.text = playerName; if (playerInfo.playerFlags.rainbowName && !rainbowName) { playerNameText.color = playerInfo.playerNameColor; nameColor = HSBColor.FromColor(playerInfo.playerNameColor); } else if (!playerInfo.playerFlags.rainbowName && playerNameText.color != playerInfo.playerNameColor) { playerNameText.color = playerInfo.playerNameColor; } rainbowName = playerInfo.playerFlags.rainbowName; } catch (Exception e) { Plugin.log.Critical(e); } }
public static IEnumerator DownloadAvatarCoroutine(string hash) { queuedAvatars.Add(hash); string downloadUrl = ""; string avatarName = ""; UnityWebRequest www = SongDownloader.GetRequestForUrl("https://modelsaber.com/api/v1/avatar/get.php?filter=hash:" + hash); www.timeout = 10; yield return(www.SendWebRequest()); if (www.isNetworkError || www.isHttpError) { Plugin.log.Error($"Unable to download avatar! {(www.isNetworkError ? $"Network error: " + www.error : (www.isHttpError ? $"HTTP error: " + www.error : "Unknown error"))}"); queuedAvatars.Remove(hash); yield break; } else { Plugin.log.Debug("Received response from ModelSaber..."); JSONNode node = JSON.Parse(www.downloadHandler.text); if (node.Count == 0) { Plugin.log.Error($"Avatar with hash {hash} doesn't exist on ModelSaber!"); cachedAvatars.Add(hash, null); queuedAvatars.Remove(hash); yield break; } downloadUrl = node[0]["download"].Value; avatarName = downloadUrl.Substring(downloadUrl.LastIndexOf("/") + 1); } if (string.IsNullOrEmpty(downloadUrl)) { queuedAvatars.Remove(hash); yield break; } bool timeout = false; float time = 0f; UnityWebRequestAsyncOperation asyncRequest; try { www = SongDownloader.GetRequestForUrl(downloadUrl); www.timeout = 0; asyncRequest = www.SendWebRequest(); } catch (Exception e) { Plugin.log.Error($"Unable to download avatar! Exception: {e}"); queuedAvatars.Remove(hash); yield break; } while (!asyncRequest.isDone) { yield return(null); time += Time.deltaTime; if ((time >= 5f && asyncRequest.progress <= float.Epsilon)) { www.Abort(); timeout = true; Plugin.log.Error("Connection timed out!"); } } if (www.isNetworkError || www.isHttpError || timeout) { queuedAvatars.Remove(hash); Plugin.log.Error("Unable to download avatar! " + (www.isNetworkError ? $"Network error: {www.error}" : (www.isHttpError ? $"HTTP error: {www.error}" : "Unknown error"))); } else { Plugin.log.Debug("Received response from ModelSaber..."); string docPath = ""; string customAvatarPath = ""; byte[] data = www.downloadHandler.data; try { docPath = Application.dataPath; docPath = docPath.Substring(0, docPath.Length - 5); docPath = docPath.Substring(0, docPath.LastIndexOf("/")); customAvatarPath = docPath + "/CustomAvatars/" + avatarName; Plugin.log.Debug($"Saving avatar to \"{customAvatarPath}\"..."); File.WriteAllBytes(customAvatarPath, data); Plugin.log.Debug("Downloaded avatar!"); Plugin.log.Debug($"Loading avatar..."); SharedCoroutineStarter.instance.StartCoroutine(LoadedAvatar.FromFileCoroutine(avatarName, (LoadedAvatar avatar) => { queuedAvatars.Remove(hash); cachedAvatars.Add(hash, avatar); avatarDownloaded?.Invoke(hash); }, (Exception ex) => { Plugin.log.Error($"Unable to load avatar! Exception: {ex}"); queuedAvatars.Remove(hash); })); } catch (Exception e) { Plugin.log.Critical(e); queuedAvatars.Remove(hash); yield break; } } }
private void UpdateCalibrationButtons(LoadedAvatar avatar) { if (_playerInput.TryGetUncalibratedPose(DeviceUse.LeftHand, out Pose _) && _playerInput.TryGetUncalibratedPose(DeviceUse.RightHand, out Pose _)) { _measureButton.interactable = true; _measureButtonHoverHint.text = "For optimal results, hold your arms out to either side of your body and point the ends of the controllers outwards as far as possible (turn your hands if necessary)."; } else { _measureButton.interactable = false; _measureButtonHoverHint.text = "Controllers not detected"; } if (avatar == null) { _calibrateButton.interactable = false; _clearButton.interactable = false; _calibrateButtonHoverHint.text = "No avatar selected"; _calibrateButtonText.text = "Calibrate"; _clearButtonText.text = "Clear"; _autoCalibrateButton.interactable = false; _autoClearButton.interactable = false; _autoCalibrateButtonHoverHint.text = "No avatar selected"; return; } if (!_playerInput.TryGetUncalibratedPose(DeviceUse.Waist, out Pose _) && !_playerInput.TryGetUncalibratedPose(DeviceUse.LeftFoot, out Pose _) && !_playerInput.TryGetUncalibratedPose(DeviceUse.RightFoot, out Pose _)) { _autoCalibrateButton.interactable = false; _autoClearButton.interactable = _calibrationData.automaticCalibration.isCalibrated; _autoCalibrateButtonHoverHint.text = "No trackers detected"; _calibrateButton.interactable = false; _clearButton.interactable = _currentAvatarManualCalibration?.isCalibrated == true; _calibrateButtonHoverHint.text = "No trackers detected"; _calibrateButtonText.text = "Calibrate"; _clearButtonText.text = "Clear"; return; } _calibrateButton.interactable = true; _clearButton.interactable = _calibrating || _currentAvatarManualCalibration?.isCalibrated == true; _calibrateButtonHoverHint.text = "Start manual full body calibration"; _calibrateButtonText.text = _calibrating ? "Save" : "Calibrate"; _clearButtonText.text = _calibrating ? "Cancel" : "Clear"; if (avatar.descriptor.supportsAutomaticCalibration) { _autoCalibrateButton.interactable = true; _autoClearButton.interactable = _calibrationData.automaticCalibration.isCalibrated; _autoCalibrateButtonHoverHint.text = "Calibrate full body tracking automatically"; } else { _autoCalibrateButton.interactable = false; _autoClearButton.interactable = false; _autoCalibrateButtonHoverHint.text = "Not supported by current avatar"; } }