Skip to content
This repository was archived by the owner on Oct 11, 2024. It is now read-only.
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 135 additions & 34 deletions com.cyan.playerobjectpool/Editor/CyanPlayerObjectPoolEditor.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using UdonSharpEditor;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using VRC.Core;
using VRC.SDKBase.Editor.Api;
using VRC.Udon;
using VRC.SDK3.Editor;
using VRC.SDKBase.Editor;

namespace Cyan.PlayerObjectPool
{
Expand All @@ -18,15 +24,17 @@ public class CyanPlayerObjectPoolEditor : Editor
private const int MinPoolObjects = 1;
// Maximum world capacity is ~82, but allowing more since it doesn't break the system.
private const int MaxPoolObjects = 100;

private Texture2D _typesBackgroundTexture;

private CyanPlayerObjectPool _instance;
private UdonBehaviour _udon;

private int _poolSize;
private bool _multiplePools;

private static VRCWorld world;

private SerializedProperty _autoPoolSizeProp;
private SerializedProperty _sizeProp;
private SerializedProperty _debugProp;

Expand All @@ -36,16 +44,17 @@ public class CyanPlayerObjectPoolEditor : Editor

private void Awake()
{
_instance = (CyanPlayerObjectPool) target;
_instance = (CyanPlayerObjectPool)target;
_udon = UdonSharpEditorUtility.GetBackingUdonBehaviour(_instance);
_poolSize = _instance.poolSize;


_autoPoolSizeProp = serializedObject.FindProperty(nameof(CyanPlayerObjectPool.autoPoolSize));
_sizeProp = serializedObject.FindProperty(nameof(CyanPlayerObjectPool.poolSize));
_debugProp = serializedObject.FindProperty(nameof(CyanPlayerObjectPool.printDebugLogs));
_typesBackgroundTexture = CyanPlayerObjectPoolEditorHelpers.CreateTexture(3, 3,
(x, y) => x == 1 && y == 1
? CyanPlayerObjectPoolEditorHelpers.BackgroundColor

_typesBackgroundTexture = CyanPlayerObjectPoolEditorHelpers.CreateTexture(3, 3,
(x, y) => x == 1 && y == 1
? CyanPlayerObjectPoolEditorHelpers.BackgroundColor
: CyanPlayerObjectPoolEditorHelpers.LineColorDark);

_multiplePools = false;
Expand All @@ -60,43 +69,125 @@ private void Awake()
}

_multiplePools = count > 1;

// Go through each setup helper and verify their pool size.
foreach (var helper in FindObjectsOfType<CyanPoolSetupHelper>())
{
helper.VerifyPoolSize();
}

AutoSizePool();
}
}

[InitializeOnLoadMethod]
private static void Initialize()
{
EditorApplication.update += CheckForSDKFocus;

// Go through each setup helper and verify their pool size.
foreach (var helper in FindObjectsOfType<CyanPoolSetupHelper>())
{
helper.VerifyPoolSize();
}

AutoSizePool();
}

private static string previousFocusedWindow = string.Empty;
// Checks if the SDK window becomes focused, and if so will verify the pool size.
private static void CheckForSDKFocus()
{
string focusedWindow = string.Empty;
try { focusedWindow = UnityEditor.EditorWindow.focusedWindow.ToString(); }
catch { return; }
if (UnityEditor.EditorWindow.focusedWindow.ToString().Contains("VRCSdkControlPanel") && UnityEditor.EditorWindow.focusedWindow.ToString() != previousFocusedWindow)
{
// Go through each setup helper and verify their pool size.
foreach (var helper in FindObjectsOfType<CyanPoolSetupHelper>())
{
helper.VerifyPoolSize();
}

AutoSizePool();
}

previousFocusedWindow = UnityEditor.EditorWindow.focusedWindow.ToString();
}

private static async void AutoSizePool()
{
// find CyanPlayerObjectPool
CyanPlayerObjectPool cyanPlayerObjectPool = FindObjectOfType<CyanPlayerObjectPool>();

// print pool size
if (cyanPlayerObjectPool != null)
{
if (cyanPlayerObjectPool.autoPoolSize)
{
// get world
await GetWorld();

// check if the pool size matches the world size
if (cyanPlayerObjectPool.poolSize != world.Capacity + 2)
{
Debug.Log("Automatically adjusting pools to match world size");

// set pool size to world size
cyanPlayerObjectPool.poolSize = world.Capacity + 2;

//reverify pool size
foreach (var helper in FindObjectsOfType<CyanPoolSetupHelper>())
{
helper.VerifyPoolSize();
}
}
}
}
}

private static async Task GetWorld()
{
//get the pipeline manager by finding the PipelineManager component in the current scene
PipelineManager pipelineManager = GameObject.FindObjectOfType<PipelineManager>();
var worldId = pipelineManager.blueprintId;

//if its a new world (no id), skip
if (worldId != null)
{
//get the world from the api
world = await VRCApi.GetWorld(worldId, false);
}
}

private bool ShouldCheckScene()
{
return _udon != null
&& _udon.gameObject.scene.isLoaded
return _udon != null
&& _udon.gameObject.scene.isLoaded
&& !EditorSceneManager.IsPreviewSceneObject(_udon);
}

public override void OnInspectorGUI()
{
if (UdonSharpGUI.DrawDefaultUdonSharpBehaviourHeader(target)) return;
if (!UdonSharpEditorUtility.IsProxyBehaviour(_instance)) return;

CyanPlayerObjectPoolEditorHelpers.RenderHeader("Cyan Player Object Pool");

if (_multiplePools)
{
GUILayout.Space(5);
EditorGUILayout.HelpBox("Multiple Object Pools exist in the scene! Please only have one Object Pool!", MessageType.Error);
// TODO list all object pools
return;
}

serializedObject.UpdateIfRequiredOrScript();

RenderSettings();

serializedObject.ApplyModifiedProperties();

// Prevent modifying the scene if this is part of a prefab editor.
if (!ShouldCheckScene())
{
Expand All @@ -106,24 +197,34 @@ public override void OnInspectorGUI()
List<CyanPoolSetupHelper> helpers = new List<CyanPoolSetupHelper>(FindObjectsOfType<CyanPoolSetupHelper>());
// Sort based on name
helpers.Sort((h1, h2) => h1.name.CompareTo(h2.name));

UpdateHelpers(helpers);
RenderObjectAssigners(helpers);
}

private void RenderSettings()
{
GUILayout.Space(5);

EditorGUILayout.BeginVertical(EditorStyles.helpBox);

_showSettings = CyanPlayerObjectPoolEditorHelpers.RenderFoldout(_showSettings, _settingsFoldoutGuiContent);

if (_showSettings)
{
CyanPlayerObjectPoolEditorHelpers.AddIndent();


EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(_autoPoolSizeProp);
if (EditorGUI.EndChangeCheck())
{
serializedObject.ApplyModifiedProperties();
AutoSizePool();
}

GUI.enabled = !_autoPoolSizeProp.boolValue;
EditorGUILayout.PropertyField(_sizeProp);
GUI.enabled = true;
EditorGUILayout.PropertyField(_debugProp);

// Hard-cap the min and max size of the object pool.
Expand All @@ -132,7 +233,7 @@ private void RenderSettings()
{
_sizeProp.intValue = Mathf.Clamp(value, MinPoolObjects, MaxPoolObjects);
}

// Only display button to respawn objects if the scene can be edited.
if (ShouldCheckScene() && GUILayout.Button("Respawn All Pool Objects"))
{
Expand All @@ -141,10 +242,10 @@ private void RenderSettings()
helper.RespawnAllPoolObjects();
}
}

CyanPlayerObjectPoolEditorHelpers.RemoveIndent();
}

EditorGUILayout.EndVertical();
}

Expand Down Expand Up @@ -178,7 +279,7 @@ private void RenderObjectAssigners(List<CyanPoolSetupHelper> helpers)

var boxStyle = new GUIStyle
{
border = new RectOffset(1, 1, 1, 1),
border = new RectOffset(1, 1, 1, 1),
normal =
{
background = _typesBackgroundTexture
Expand All @@ -192,13 +293,13 @@ private void RenderObjectAssigners(List<CyanPoolSetupHelper> helpers)
float sectionHeight = 24;
float buttonHeight = 18;
float labelHeight = EditorGUIUtility.singleLineHeight;

float between = 9;
float betweenHalf = Mathf.Floor(between / 2f);
float betweenHalf = Mathf.Floor(between / 2f);
float indexLabelWidth = 20;
float pingWidth = 40;
float iconWidth = 25;

// Create vertical bars separating the sections
GUI.Box(new Rect(rect.x + indexLabelWidth + between, rect.y + 1, 1, height), GUIContent.none, boxStyle);
GUI.Box(new Rect(rect.x + indexLabelWidth + pingWidth + between * 2, rect.y + 1, 1, height), GUIContent.none, boxStyle);
Expand All @@ -207,7 +308,7 @@ private void RenderObjectAssigners(List<CyanPoolSetupHelper> helpers)
{
GUILayout.Space(sectionHeight);
}

for (int cur = 0; cur < helpers.Count; ++cur)
{
var helper = helpers[cur];
Expand All @@ -222,7 +323,7 @@ private void RenderObjectAssigners(List<CyanPoolSetupHelper> helpers)

float textY = rect.y + Mathf.Ceil((rect.height - labelHeight) / 2f);
float buttonY = rect.y + Mathf.Ceil((rect.height - buttonHeight) / 2f);

float indexLabelStartX = xStart + betweenHalf;
float pingStart = indexLabelStartX + indexLabelWidth + between;
float objectLabelStartX = pingStart + pingWidth + between;
Expand All @@ -231,9 +332,9 @@ private void RenderObjectAssigners(List<CyanPoolSetupHelper> helpers)
Rect indexRect = new Rect(indexLabelStartX, textY, indexLabelWidth, labelHeight);
Rect pingRect = new Rect(pingStart, buttonY, pingWidth, buttonHeight);
Rect objectLabelRect = new Rect(objectLabelStartX, textY, objectLabelWidth, labelHeight);

GUI.Label(indexRect, (1 + cur).ToString().PadLeft(2));

if (GUI.Button(pingRect, "Ping"))
{
EditorGUIUtility.PingObject(helper);
Expand All @@ -257,15 +358,15 @@ private void RenderObjectAssigners(List<CyanPoolSetupHelper> helpers)
// Display error saying object count does not match
content = errorIcon;
}

Rect iconRect = new Rect(objectLabelRect.xMax, buttonY, iconWidth, buttonHeight);
GUI.Label(iconRect, content);
}

GUILayout.Space(1);
EditorGUILayout.EndHorizontal();
}

EditorGUILayout.EndVertical();
GUILayout.Space(5);
}
Expand Down
Loading