using System; using UdonSharp; using UnityEngine; using UnityEngine.Serialization; using VRC.SDK3.Data; using UnityEditor; namespace VRCBoard.Components { [UdonBehaviourSyncMode(BehaviourSyncMode.None)] public class VRCBoardImage : VRCBoardBaseComponent { [Header("Uploader ID (only applies to images of 'shared' or 'instance' type)")] public string uploaderIdOverride; [Header("Material Override (Optional, if set the properties are applied globally to all renderers using the material)")] public Material materialOverride; [HideInInspector] public string[] imageIds = new string[0]; [HideInInspector] public string[] texturePropertyMappings = new string[0]; [HideInInspector] public Texture2D[] defaultTextures = new Texture2D[0]; private string _mainType = ""; private string _uploaderId = ""; protected override void OnRegister() { Debug.Log("Registering image component"); } private string GetUploader() { string uploaderId = ""; if (string.IsNullOrEmpty(uploaderIdOverride) && imageIds.Length > 0) { string firstImageID = imageIds[0]; GetImageAtlasTexture(firstImageID, null, out Texture2D albedoTexture, out int albedoAtlasPosition, out int albedoAtlasSize, out string albedoType); if (albedoType == null) { Debug.LogError("Failed to get image type for albedo image"); return ""; } _mainType = albedoType; if (_mainType == "shared") { uploaderId = GetRandomUploader(firstImageID); } else { DataDictionary ownerInfo = manager.GetSupporterDataFromPlayer(manager.instanceOwner); if (ownerInfo == null) { Debug.LogWarning("Failed to get owner info, user has likely not linked their account."); return ""; } bool ownerSuccess = ownerInfo.TryGetValue("id", out DataToken ownerToken); if (!ownerSuccess || ownerToken.TokenType != TokenType.String) { Debug.LogWarning("Failed to get owner ID from owner info."); return ""; } uploaderId = ownerToken.String; } Debug.Log("image uploader: " + uploaderId); } else { uploaderId = uploaderIdOverride; } return uploaderId; } private void TryGetUploader() { if (!string.IsNullOrEmpty(_uploaderId)) return; _uploaderId = GetUploader(); if (string.IsNullOrEmpty(_uploaderId)) { Debug.LogError("Failed to get uploader ID"); return; } for (int i = 0; i < imageIds.Length; i++) { string imageId = imageIds[i]; RequestImageLoad(imageId, _uploaderId); } } protected override void OnInitialize() { TryGetUploader(); } protected override void OnImageDataUpdate() { TryGetUploader(); } protected override void OnSupporterDataUpdate() { TryGetUploader(); } protected override void OnImageLoaded() { Debug.Log("Image loaded VRCBoardImage"); //bool textureSuccess = GetImageAtlasTexture(albedoImageId, _uploaderId, out Texture2D texture, out int atlasPosition, out int atlasSize, out string type1); MaterialPropertyBlock propertyBlock = new MaterialPropertyBlock(); for (int i = 0; i < imageIds.Length; i++) { if (i >= texturePropertyMappings.Length) continue; string propertyName = texturePropertyMappings[i]; Texture2D texture = manager.GetTexture2D(_uploaderId, imageIds[i]); if (texture == null) { texture = defaultTextures[i]; if (texture == null) continue; } if (string.IsNullOrEmpty(propertyName)) continue; propertyBlock.SetTexture(propertyName, texture); if (materialOverride != null) materialOverride.SetTexture(propertyName, texture); } GetComponent().SetPropertyBlock(propertyBlock); } } #if UNITY_EDITOR && !COMPILER_UDONSHARP [CustomEditor(typeof(VRCBoardImage), true)] public class VRCBoardImageComponentEditor : Editor { public override void OnInspectorGUI() { VRCBoardImage script = (VRCBoardImage)target; Renderer renderer = script.GetComponent(); Material material = renderer.sharedMaterial; if (script.materialOverride) { EditorGUILayout.HelpBox("Material override enabled", MessageType.Info); material = script.materialOverride; } string[] materialPropertyNames = material.GetPropertyNames(MaterialPropertyType.Texture); base.OnInspectorGUI(); bool equals = Equals(script.imageIds.Length, script.defaultTextures.Length) && Equals(script.imageIds.Length, script.defaultTextures.Length); EditorGUILayout.Separator(); GUILayout.BeginVertical("Images", "window"); int newSize = script.imageIds.Length; GUILayout.BeginHorizontal(); if (GUILayout.Button("+")) { newSize++; } if (GUILayout.Button("-")) { newSize--; } GUILayout.EndHorizontal(); if (newSize != script.imageIds.Length || !equals) { Debug.Log("Resized arrays to"+newSize); Array.Resize(ref script.imageIds, newSize); Array.Resize(ref script.texturePropertyMappings, newSize); Array.Resize(ref script.defaultTextures, newSize); EditorUtility.SetDirty(script); } MaterialPropertyBlock propertyBlock = new MaterialPropertyBlock(); for (int i = 0; i < script.imageIds.Length; i++) { EditorGUILayout.Space(); GUILayout.BeginVertical("Image "+i, "window"); string imageId = script.imageIds[i]; string propertyName = script.texturePropertyMappings[i]; Texture2D defaultImage = script.defaultTextures[i]; imageId = EditorGUILayout.TextField("Image Id:", imageId); int selectedIndex = Array.IndexOf(materialPropertyNames, propertyName); selectedIndex = EditorGUILayout.Popup("Material Property:", selectedIndex, materialPropertyNames); bool propertyExists = Array.Exists(materialPropertyNames, materialProperty => materialProperty == propertyName); if (propertyExists) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Default Texture:"); defaultImage = EditorGUILayout.ObjectField(defaultImage, typeof(Texture2D), false) as Texture2D; EditorGUILayout.EndHorizontal(); if (defaultImage != null) propertyBlock.SetTexture(propertyName, defaultImage); if (script.materialOverride != null) script.materialOverride.SetTexture(propertyName, defaultImage); } if (script.defaultTextures[i] != defaultImage) { script.defaultTextures[i] = defaultImage; EditorUtility.SetDirty(script); } if (script.imageIds[i] != imageId) { script.imageIds[i] = imageId; EditorUtility.SetDirty(script); } if (selectedIndex >= 0 && selectedIndex < materialPropertyNames.Length && script.texturePropertyMappings[i] != materialPropertyNames[selectedIndex]) { script.texturePropertyMappings[i] = materialPropertyNames[selectedIndex]; EditorUtility.SetDirty(script); } GUILayout.EndVertical(); } renderer.SetPropertyBlock(propertyBlock); EditorGUILayout.EndHorizontal(); } } #endif }