Files
BlockSpace-v1.5.0b/Assets/Scripts/Assembly-CSharp/BlockSpace/Voxels/VRVoxelBrush.cs
T
2026-06-01 17:19:55 +02:00

2909 lines
81 KiB
C#

using System.Collections.Generic;
using BlockSpace.Worlds;
using Photon.VR;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.XR;
using UnityEngine.XR.Interaction.Toolkit.Locomotion;
using UnityEngine.XR.Interaction.Toolkit.Locomotion.Movement;
namespace BlockSpace.Voxels
{
[DisallowMultipleComponent]
public sealed class VRVoxelBrush : MonoBehaviour
{
private sealed class AvatarEditSnapshot
{
public VoxelGroup group;
public Vector3Int position;
public byte packedRotation;
public Vector3Int size;
public byte[] voxels;
}
private sealed class AvatarEditUndoRecord
{
public AvatarEditSnapshot before;
public AvatarEditSnapshot after;
}
private const int PaletteColumns = 8;
private const int PaletteRows = 8;
private const float PaletteSize = 0.3f;
private const float PaletteCubeSize = 0.03f;
private const float PaletteSelectedCubeSize = 0.05f;
private const float PaletteUpOffset = 0.2f;
private const float PaletteForwardOffset = 0.14f;
private const float PaletteCellLift = 0.01f;
private const float PaletteCursorWidth = 0.0035f;
private const float ColorPickRadius = 0.2f;
private static readonly Color32 ColorPickIndicatorColor = new Color32(220, 120, byte.MaxValue, 140);
private static readonly Color32 PaletteCursorLightColor = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue);
private static readonly Color32 PaletteCursorDarkColor = new Color32(12, 12, 12, byte.MaxValue);
private static readonly Color32 IdleIndicatorColor = new Color32(64, 160, byte.MaxValue, 64);
private static readonly Color32 DrawingIndicatorColor = new Color32(64, 160, byte.MaxValue, 0);
private static readonly Color32 ErasingIndicatorColor = new Color32(byte.MaxValue, 72, 72, 64);
private static readonly Color32 PaintingIndicatorColor = new Color32(byte.MaxValue, 220, 72, 96);
private static readonly Color32 SelectingIndicatorColor = new Color32(72, byte.MaxValue, 96, 64);
[SerializeField]
private VoxelGroupManager groupManager;
[SerializeField]
private Transform trackingOrigin;
[SerializeField]
private Transform rightHandAnchor;
[SerializeField]
private Transform leftHandAnchor;
[SerializeField]
private float brushForwardOffset = 0.05f;
[SerializeField]
private float brushRadius = 0.125f;
[SerializeField]
private float minBrushRadius = 0.0625f;
[SerializeField]
private float maxBrushRadius = 0.625f;
[SerializeField]
private float brushRadiusStep = 0.0625f;
[SerializeField]
private float brushDistance = 1f;
[SerializeField]
private float minBrushDistance = 0.5f;
[SerializeField]
private float maxBrushDistance = 3f;
[SerializeField]
private float brushDistanceStep = 0.125f;
[SerializeField]
private float desktopSurfaceOffset = 0.01f;
[SerializeField]
private LayerMask desktopRaycastMask = -5;
[SerializeField]
private float triggerThreshold = 0.7f;
[SerializeField]
private float thumbstickDeadZone = 0.6f;
[SerializeField]
private float radiusRepeatDelay = 0.12f;
[SerializeField]
private float creatorToggleChordWindow = 0.12f;
[SerializeField]
private float avatarUndoChordWindow = 0.12f;
[SerializeField]
[Range(0f, 63f)]
private byte selectedColorIndex = 16;
[SerializeField]
private VoxelMaterial selectedMaterial;
private readonly HashSet<Vector3Int> strokeCells = new HashSet<Vector3Int>();
private readonly HashSet<VoxelGroup> activeEraseGroups = new HashSet<VoxelGroup>();
private readonly HashSet<VoxelGroup> activePaintGroups = new HashSet<VoxelGroup>();
private readonly Stack<AvatarEditUndoRecord> avatarUndoStack = new Stack<AvatarEditUndoRecord>();
private readonly List<ContinuousMoveProvider> moveProviders = new List<ContinuousMoveProvider>();
private readonly Dictionary<ContinuousMoveProvider, bool> moveProviderEnabledStates = new Dictionary<ContinuousMoveProvider, bool>();
private readonly List<LocomotionProvider> selectionLocomotionProviders = new List<LocomotionProvider>();
private readonly Dictionary<LocomotionProvider, bool> selectionLocomotionStates = new Dictionary<LocomotionProvider, bool>();
private readonly List<GameObject> paletteMoveObjects = new List<GameObject>();
private readonly Dictionary<GameObject, bool> paletteMoveObjectStates = new Dictionary<GameObject, bool>();
private InputDevice rightHand;
private InputDevice leftHand;
private bool useXRInput;
private bool lastDesktopBrushWasHit;
private bool lastDesktopBrushWasHitValid;
private bool lastBrushPointHadHit;
private bool lastErasePointHadHit;
private bool lastPaintPointHadHit;
private bool creatorMode = true;
private bool drawingStroke;
private bool erasing;
private bool painting;
private bool paletteOpen;
private byte activeStrokeVoxelValue;
private bool leftPrimaryPrevious;
private bool leftThumbstickClickPrevious;
private bool leftPaletteAxisLatched;
private bool leftCreatorChordConsumed;
private bool leftGripHeldPrevious;
private bool leftTriggerHeldPrevious;
private bool avatarUndoChordActive;
private bool suppressAvatarUndoUntilNeutral;
private float avatarClearChordStartTime = -1f;
private bool suppressAvatarClearUntilNeutral;
private float desktopAvatarClearStartTime = -1f;
private bool rightGripHeldPrevious;
private bool rightTriggerHeldPrevious;
private bool avatarEditUndoSessionActive;
private bool avatarEditUndoSessionChanged;
private bool selectionLocomotionBlocked;
private Vector3 lastBrushPoint;
private Vector3 lastErasePoint;
private Vector3 lastPaintPoint;
private float lastLeftGripPressTime = float.NegativeInfinity;
private float lastLeftTriggerPressTime = float.NegativeInfinity;
private float lastRightGripPressTime = float.NegativeInfinity;
private float lastRightTriggerPressTime = float.NegativeInfinity;
private float nextRadiusChangeTime;
private float nextToolHapticTime;
private float lastEraseChangedTime = float.NegativeInfinity;
private float lastPaintChangedTime = float.NegativeInfinity;
private bool colorPickerHeldPrevious;
private bool colorPickerActive;
private VoxelGroup activeStrokeGroup;
private bool activeStrokePreviewBroadcasting;
private bool activeErasePreviewBroadcasting;
private VoxelGroup avatarEditorTargetGroup;
private AvatarEditSnapshot avatarEditUndoBeforeSnapshot;
private Transform brushIndicator;
private MeshRenderer brushIndicatorRenderer;
private Transform colorPickIndicator;
private MeshRenderer colorPickIndicatorRenderer;
private Material brushIndicatorMaterial;
private Material colorPickIndicatorMaterial;
private Transform paletteRoot;
private LineRenderer paletteCursorRenderer;
private Material paletteCellMaterial;
private Material paletteCursorMaterial;
private readonly MeshRenderer[] paletteCellRenderers = new MeshRenderer[64];
private readonly MaterialPropertyBlock[] paletteCellBlocks = new MaterialPropertyBlock[64];
private int paletteColumn;
private int paletteRow;
public static VRVoxelBrush Instance { get; private set; }
public bool IsPaletteOpen => paletteOpen;
public bool UsingXRInput => useXRInput;
public Transform RightHandAnchor => rightHandAnchor;
public Transform LeftHandAnchor => leftHandAnchor;
public Transform TrackingOrigin => trackingOrigin;
public bool IsEditingAvatar => avatarEditorTargetGroup != null;
private void Awake()
{
Instance = this;
if (groupManager == null)
{
groupManager = Object.FindObjectOfType<VoxelGroupManager>();
}
if (groupManager != null)
{
creatorMode = groupManager.CreatorMode;
}
ApplyBrushRadiusLimits();
EnsureBrushIndicator();
EnsureColorPickIndicator();
EnsurePaletteUi();
EnsureGroupSelector();
EnsureNodeGraph();
EnsureDesktopRigController();
EnsureAvatarCustomizer();
RefreshMoveProviders();
RefreshSelectionLocomotionProviders();
SyncSelectionRadius();
SyncPaletteCursorToSelectedColor();
UpdatePaletteSelectionVisuals();
SetPaletteVisible(visible: false);
}
private void OnEnable()
{
AcquireDevices();
}
private void OnDisable()
{
CancelStroke();
if (erasing)
{
EndErase();
}
if (painting)
{
EndPaint();
}
paletteOpen = false;
ApplyPaletteLocomotionGate(disableMovement: false);
ApplySelectionLocomotionGate(disableMovement: false);
avatarUndoChordActive = false;
suppressAvatarUndoUntilNeutral = false;
SetPaletteVisible(visible: false);
SetBrushIndicatorVisible(visible: false);
SetColorPickIndicatorVisible(visible: false);
}
private void OnDestroy()
{
if (Instance == this)
{
Instance = null;
}
if (brushIndicatorMaterial != null)
{
Object.Destroy(brushIndicatorMaterial);
}
if (colorPickIndicatorMaterial != null)
{
Object.Destroy(colorPickIndicatorMaterial);
}
if (paletteCellMaterial != null)
{
Object.Destroy(paletteCellMaterial);
}
if (paletteCursorMaterial != null)
{
Object.Destroy(paletteCursorMaterial);
}
}
public void SetAvatarEditorTarget(VoxelGroup targetGroup)
{
if (!(avatarEditorTargetGroup == targetGroup))
{
FinishActiveAvatarEditSessions();
avatarEditorTargetGroup = targetGroup;
}
}
public void ClearAvatarEditorTarget()
{
if (!(avatarEditorTargetGroup == null))
{
FinishActiveAvatarEditSessions();
avatarEditorTargetGroup = null;
}
}
public bool UndoAvatarEditorAction()
{
if (drawingStroke || erasing || painting)
{
return false;
}
if (avatarUndoStack.Count == 0)
{
return false;
}
AvatarEditUndoRecord avatarEditUndoRecord = avatarUndoStack.Pop();
if (avatarEditUndoRecord == null || avatarEditUndoRecord.before == null)
{
return false;
}
avatarEditUndoBeforeSnapshot = null;
avatarEditUndoSessionActive = false;
avatarEditUndoSessionChanged = false;
RestoreAvatarEditSnapshot(avatarEditUndoRecord.before);
return true;
}
public void FinalizeAvatarEditorSessions()
{
FinishActiveAvatarEditSessions();
}
private void Update()
{
if (groupManager == null)
{
return;
}
creatorMode = groupManager.CreatorMode;
EnsureDevices();
useXRInput = DetectXRInputActive();
HandleCreatorToggle();
HandlePaletteToggleAndNavigation();
HandleMaterialCycle();
ApplyBrushRadiusLimits();
HandleBrushRadius();
SyncSelectionRadius();
UpdatePaletteUi();
UpdateToolHaptics();
HandleColorPickerTool();
VRGroupSelector instance = VRGroupSelector.Instance;
NodeGraphManager instance2 = NodeGraphManager.Instance;
bool flag = instance != null && instance.HasSelection;
bool flag2 = instance2 != null && instance2.BlocksRightHandActions;
ApplySelectionLocomotionGate((instance != null && (flag || instance.BlocksRightHandActions)) || flag2);
bool flag3 = instance != null && instance.IsSelecting;
bool flag4 = flag3;
bool flag5 = (instance != null && instance.BlocksRightHandActions) || flag2;
Vector3 worldPosition;
Quaternion worldRotation;
bool flag6 = TryGetActiveBrushPose(out worldPosition, out worldRotation);
bool currentHadHit = useXRInput || lastDesktopBrushWasHit;
bool flag7 = (useXRInput ? (ReadFloat(rightHand, CommonUsages.trigger) >= triggerThreshold) : Input.GetMouseButton(0));
bool flag8 = (useXRInput ? ReadGripHeld(rightHand) : Input.GetMouseButton(1));
bool flag9 = (useXRInput ? ReadBool(rightHand, CommonUsages.secondaryButton) : (Input.GetKey(KeyCode.Q) && !flag));
bool flag10 = HandleAvatarEditUndo(flag7, flag8);
bool flag11 = HandleDesktopUndoShortcut();
bool flag12 = HandleAvatarClearChord();
Vector3 vector = worldPosition;
if (flag6 && avatarEditorTargetGroup != null && creatorMode && !flag3 && (flag7 || drawingStroke))
{
vector = AdjustBrushPointForAvatarEditing(worldPosition);
}
if (!creatorMode)
{
if (paletteOpen)
{
paletteOpen = false;
leftPaletteAxisLatched = false;
ApplyPaletteLocomotionGate(disableMovement: false);
SetPaletteVisible(visible: false);
}
ApplySelectionLocomotionGate(disableMovement: false);
if (drawingStroke)
{
CancelStroke();
}
if (erasing)
{
EndErase();
}
if (painting)
{
EndPaint();
}
UpdateBrushIndicator(flag6, drawingStroke ? vector : worldPosition);
return;
}
if (flag12)
{
if (drawingStroke)
{
CancelStroke();
}
if (erasing)
{
EndErase();
}
if (painting)
{
EndPaint();
}
UpdateBrushIndicator(flag6, drawingStroke ? vector : worldPosition);
return;
}
if (flag10)
{
if (drawingStroke)
{
CancelStroke();
}
if (erasing)
{
EndErase();
}
if (painting)
{
EndPaint();
}
UpdateBrushIndicator(flag6, drawingStroke ? vector : worldPosition);
return;
}
if (flag11)
{
if (drawingStroke)
{
CancelStroke();
}
if (erasing)
{
EndErase();
}
if (painting)
{
EndPaint();
}
UpdateBrushIndicator(flag6, drawingStroke ? vector : worldPosition);
return;
}
if (flag5)
{
if (drawingStroke)
{
CancelStroke();
}
if (erasing)
{
EndErase();
}
if (painting)
{
EndPaint();
}
UpdateBrushIndicator(flag6, drawingStroke ? vector : worldPosition);
return;
}
if (flag6)
{
if (!flag3 && flag7)
{
if (painting)
{
EndPaint();
}
if (erasing)
{
EndErase();
}
if (!drawingStroke)
{
BeginStroke(vector);
}
else if (ShouldBreakContinuousEdit(lastBrushPoint, vector, lastBrushPointHadHit, currentHadHit))
{
lastBrushPoint = vector;
lastBrushPointHadHit = currentHadHit;
RasterizeSegment(vector, vector, brushRadius);
}
else
{
RasterizeSegment(lastBrushPoint, vector, brushRadius);
lastBrushPoint = vector;
lastBrushPointHadHit = currentHadHit;
}
}
else if (drawingStroke)
{
FinalizeStroke();
}
if (flag3)
{
if (drawingStroke)
{
CancelStroke();
}
if (erasing)
{
EndErase();
}
if (painting)
{
EndPaint();
}
if (instance2 != null && instance != null && instance.TryGetSelectionCenter(out var worldPosition2))
{
instance2.SelectNodesWithinSphere(worldPosition2, instance.SelectionRadius, additive: true);
}
}
else if (!drawingStroke)
{
if (flag8 && !flag4 && !flag)
{
if (painting)
{
EndPaint();
}
if (!erasing)
{
BeginErase(worldPosition);
}
else if (ShouldBreakContinuousEdit(lastErasePoint, worldPosition, lastErasePointHadHit, currentHadHit))
{
lastErasePoint = worldPosition;
lastErasePointHadHit = currentHadHit;
UpdateErase(worldPosition, worldPosition);
}
else
{
UpdateErase(lastErasePoint, worldPosition);
lastErasePoint = worldPosition;
lastErasePointHadHit = currentHadHit;
}
}
else if (erasing)
{
EndErase();
}
if (!erasing && !flag8 && !flag)
{
if (flag9)
{
if (!painting)
{
BeginPaint(worldPosition);
}
else if (ShouldBreakContinuousEdit(lastPaintPoint, worldPosition, lastPaintPointHadHit, currentHadHit))
{
lastPaintPoint = worldPosition;
lastPaintPointHadHit = currentHadHit;
UpdatePaint(worldPosition, worldPosition);
}
else
{
UpdatePaint(lastPaintPoint, worldPosition);
lastPaintPoint = worldPosition;
lastPaintPointHadHit = currentHadHit;
}
}
else if (painting)
{
EndPaint();
}
}
else if (painting)
{
EndPaint();
}
}
}
else
{
if (!flag7 && drawingStroke)
{
FinalizeStroke();
}
if (erasing)
{
EndErase();
}
if (painting)
{
EndPaint();
}
}
UpdateBrushIndicator(flag6, drawingStroke ? vector : worldPosition);
}
private void BeginStroke(Vector3 startPoint)
{
VRGroupSelector instance = VRGroupSelector.Instance;
if (instance != null && instance.HasSelection)
{
instance.ClearSelectionForToolUse();
}
NodeGraphManager.Instance?.ClearSelectionForToolUse();
strokeCells.Clear();
drawingStroke = true;
activeStrokeVoxelValue = GetCurrentBrushVoxelValue();
activeStrokeGroup = ((avatarEditorTargetGroup != null) ? avatarEditorTargetGroup : groupManager.BeginStrokeGroup(0));
activeStrokePreviewBroadcasting = false;
if (activeStrokeGroup == avatarEditorTargetGroup)
{
BeginAvatarEditUndoSession(activeStrokeGroup);
activeStrokeGroup.SetGreedyRenderMeshing(enabled: false);
}
else
{
BeginStrokePreviewBroadcast(startPoint);
}
lastBrushPoint = startPoint;
lastBrushPointHadHit = useXRInput || lastDesktopBrushWasHit;
RasterizeSegment(startPoint, startPoint, brushRadius);
}
private void FinalizeStroke()
{
drawingStroke = false;
if (activeStrokeGroup == null)
{
EndStrokePreviewBroadcast();
strokeCells.Clear();
return;
}
if (activeStrokeGroup == avatarEditorTargetGroup)
{
FinalizeAvatarEditorGroup(activeStrokeGroup);
}
else if (strokeCells.Count == 0)
{
EndStrokePreviewBroadcast();
groupManager.CancelStrokeGroup(activeStrokeGroup);
}
else
{
EndStrokePreviewBroadcast();
groupManager.FinalizeStrokeGroup(activeStrokeGroup);
}
activeStrokeGroup = null;
strokeCells.Clear();
}
private void CancelStroke()
{
drawingStroke = false;
if (activeStrokeGroup == avatarEditorTargetGroup)
{
FinalizeAvatarEditorGroup(activeStrokeGroup);
activeStrokeGroup = null;
}
else if (activeStrokeGroup != null && groupManager != null)
{
EndStrokePreviewBroadcast();
groupManager.CancelStrokeGroup(activeStrokeGroup);
activeStrokeGroup = null;
}
else
{
EndStrokePreviewBroadcast();
}
strokeCells.Clear();
}
private void BeginStrokePreviewBroadcast(Vector3 startPoint)
{
if (groupManager == null || activeStrokeGroup == null || activeStrokeGroup == avatarEditorTargetGroup)
{
activeStrokePreviewBroadcasting = false;
return;
}
activeStrokePreviewBroadcasting = true;
groupManager.BroadcastStrokePreviewBegin(activeStrokeVoxelValue, brushRadius, brushForwardOffset, startPoint);
}
private void UpdateStrokePreviewBroadcast(Vector3 point)
{
if (activeStrokePreviewBroadcasting && !(groupManager == null))
{
groupManager.BroadcastStrokePreviewUpdate(activeStrokeVoxelValue, brushRadius, brushForwardOffset, point);
}
}
private void EndStrokePreviewBroadcast()
{
if (activeStrokePreviewBroadcasting)
{
activeStrokePreviewBroadcasting = false;
groupManager?.BroadcastStrokePreviewEnd();
}
}
private void BeginErase(Vector3 startPoint)
{
VRGroupSelector instance = VRGroupSelector.Instance;
if (instance != null && instance.HasSelection)
{
instance.ClearSelectionForToolUse();
}
erasing = true;
activeEraseGroups.Clear();
activeErasePreviewBroadcasting = false;
lastEraseChangedTime = float.NegativeInfinity;
if (avatarEditorTargetGroup != null)
{
BeginAvatarEditUndoSession(avatarEditorTargetGroup);
activeEraseGroups.Add(avatarEditorTargetGroup);
avatarEditorTargetGroup.SetGreedyRenderMeshing(enabled: false);
}
else
{
groupManager.BeginEraseUndoSession();
BeginErasePreviewBroadcast(startPoint);
}
lastErasePoint = startPoint;
lastErasePointHadHit = useXRInput || lastDesktopBrushWasHit;
UpdateErase(startPoint, startPoint);
}
private void EndErase()
{
erasing = false;
EndErasePreviewBroadcast();
if (avatarEditorTargetGroup != null)
{
foreach (VoxelGroup activeEraseGroup in activeEraseGroups)
{
if (activeEraseGroup != null)
{
FinalizeAvatarEditorGroup(activeEraseGroup);
}
}
activeEraseGroups.Clear();
return;
}
if (groupManager == null)
{
activeEraseGroups.Clear();
return;
}
foreach (VoxelGroup activeEraseGroup2 in activeEraseGroups)
{
if (!(activeEraseGroup2 == null))
{
groupManager.FinalizeLiveEditedGroup(activeEraseGroup2, sendNetworkUpdate: true, rebuildCollider: true, playDestroyAnimationIfEmpty: false);
}
}
groupManager.CompleteEraseUndoSession();
activeEraseGroups.Clear();
}
private void BeginPaint(Vector3 startPoint)
{
if (!(groupManager == null))
{
VRGroupSelector instance = VRGroupSelector.Instance;
if (instance != null && instance.HasSelection)
{
instance.ClearSelectionForToolUse();
}
NodeGraphManager.Instance?.ClearSelectionForToolUse();
painting = true;
activePaintGroups.Clear();
lastPaintChangedTime = float.NegativeInfinity;
if (avatarEditorTargetGroup != null)
{
BeginAvatarEditUndoSession(avatarEditorTargetGroup);
activePaintGroups.Add(avatarEditorTargetGroup);
avatarEditorTargetGroup.SetGreedyRenderMeshing(enabled: false);
}
else
{
groupManager.BeginPaintUndoSession();
}
lastPaintPoint = startPoint;
lastPaintPointHadHit = useXRInput || lastDesktopBrushWasHit;
UpdatePaint(startPoint, startPoint);
}
}
private void EndPaint()
{
painting = false;
if (avatarEditorTargetGroup != null)
{
foreach (VoxelGroup activePaintGroup in activePaintGroups)
{
if (activePaintGroup != null)
{
FinalizeAvatarEditorGroup(activePaintGroup);
}
}
activePaintGroups.Clear();
return;
}
if (groupManager == null)
{
activePaintGroups.Clear();
return;
}
foreach (VoxelGroup activePaintGroup2 in activePaintGroups)
{
if (!(activePaintGroup2 == null))
{
groupManager.FinalizeLiveEditedGroup(activePaintGroup2, sendNetworkUpdate: true, rebuildCollider: false);
}
}
groupManager.CompletePaintUndoSession();
activePaintGroups.Clear();
}
private void UpdatePaint(Vector3 start, Vector3 end)
{
if (groupManager == null)
{
return;
}
if (avatarEditorTargetGroup != null)
{
UpdateAvatarEditorPaint(start, end);
return;
}
byte currentBrushVoxelValue = GetCurrentBrushVoxelValue();
float num = Mathf.Max(groupManager.VoxelSize * 0.5f, brushRadius * 0.5f);
float num2 = Vector3.Distance(start, end);
int num3 = Mathf.Max(1, Mathf.CeilToInt(num2 / num));
for (int i = 0; i <= num3; i++)
{
float t = ((num3 == 0) ? 0f : ((float)i / (float)num3));
Vector3 worldCenter = Vector3.Lerp(start, end, t);
if (groupManager.PaintSphereRealtime(worldCenter, brushRadius, currentBrushVoxelValue, activePaintGroups))
{
lastPaintChangedTime = Time.unscaledTime;
}
}
}
private void UpdateErase(Vector3 start, Vector3 end)
{
if (groupManager == null)
{
return;
}
if (avatarEditorTargetGroup != null)
{
UpdateAvatarEditorErase(start, end);
return;
}
float voxelSize = groupManager.VoxelSize;
float num = brushRadius;
float num2 = Mathf.Max(voxelSize * 0.5f, num * 0.5f);
float num3 = Vector3.Distance(start, end);
int num4 = Mathf.Max(1, Mathf.CeilToInt(num3 / num2));
for (int i = 0; i <= num4; i++)
{
float t = ((num4 == 0) ? 0f : ((float)i / (float)num4));
Vector3 worldCenter = Vector3.Lerp(start, end, t);
if (groupManager.EraseSphereRealtime(worldCenter, num, activeEraseGroups))
{
lastEraseChangedTime = Time.unscaledTime;
}
NodeGraphManager.Instance?.DeleteNodesWithinSphere(worldCenter, num, broadcast: true);
}
UpdateErasePreviewBroadcast(end);
}
private void BeginErasePreviewBroadcast(Vector3 startPoint)
{
if (groupManager == null || avatarEditorTargetGroup != null)
{
activeErasePreviewBroadcasting = false;
return;
}
activeErasePreviewBroadcasting = true;
groupManager.BroadcastErasePreviewBegin(brushRadius, brushForwardOffset, startPoint);
}
private void UpdateErasePreviewBroadcast(Vector3 point)
{
if (activeErasePreviewBroadcasting && !(groupManager == null))
{
groupManager.BroadcastErasePreviewUpdate(brushRadius, brushForwardOffset, point);
}
}
private void EndErasePreviewBroadcast()
{
if (activeErasePreviewBroadcasting)
{
activeErasePreviewBroadcasting = false;
groupManager?.BroadcastErasePreviewEnd();
}
}
private void UpdateToolHaptics()
{
if (useXRInput && !(Time.unscaledTime < nextToolHapticTime))
{
if (drawingStroke)
{
VRHaptics.Pulse(rightHand, 0.32f, 0.055f);
nextToolHapticTime = Time.unscaledTime + 0.05f;
}
else if (erasing && Time.unscaledTime - lastEraseChangedTime <= 0.2f)
{
VRHaptics.Pulse(rightHand, 0.32f, 0.055f);
nextToolHapticTime = Time.unscaledTime + 0.05f;
}
else if (painting && Time.unscaledTime - lastPaintChangedTime <= 0.2f)
{
VRHaptics.Pulse(rightHand, 0.32f, 0.055f);
nextToolHapticTime = Time.unscaledTime + 0.05f;
}
}
}
private void HandleColorPickerTool()
{
EnsureColorPickIndicator();
if (!creatorMode || groupManager == null)
{
colorPickerActive = false;
SetColorPickIndicatorVisible(visible: false);
colorPickerHeldPrevious = false;
return;
}
bool flag = false;
Vector3 worldPosition = Vector3.zero;
bool flag2 = false;
Quaternion worldRotation;
if (useXRInput)
{
bool num = ReadGripHeld(leftHand);
bool flag3 = ReadFloat(leftHand, CommonUsages.trigger) >= triggerThreshold;
flag = num && !flag3;
flag2 = TryGetBrushPose(leftHand, XRNode.LeftHand, leftHandAnchor, out worldPosition, out worldRotation);
}
else
{
flag = Input.GetKey(KeyCode.Z);
flag2 = TryGetActiveBrushPose(out worldPosition, out worldRotation);
}
if (flag && flag2)
{
if (!colorPickerHeldPrevious)
{
NodeGraphManager.Instance?.ClearSelectionForToolUse();
}
colorPickerActive = true;
float b = ((avatarEditorTargetGroup != null) ? avatarEditorTargetGroup.CurrentVoxelSize : groupManager.VoxelSize);
colorPickIndicator.position = worldPosition;
colorPickIndicator.rotation = Quaternion.identity;
colorPickIndicator.localScale = Vector3.one * Mathf.Max(0.001f, b);
if (colorPickIndicatorMaterial != null)
{
ApplyIndicatorMaterialColor(colorPickIndicatorMaterial, ColorPickIndicatorColor);
}
SetColorPickIndicatorVisible(visible: true);
}
else
{
SetColorPickIndicatorVisible(visible: false);
}
if (!flag && colorPickerHeldPrevious && colorPickerActive && flag2)
{
if (TryPickColorFromWorld(worldPosition, out var pickedVoxelValue))
{
ApplyPickedVoxelValueToPalette(pickedVoxelValue);
if (useXRInput)
{
VRHaptics.Pulse(leftHand, 0.18f, 0.055f);
}
}
colorPickerActive = false;
}
colorPickerHeldPrevious = flag;
}
private bool TryPickColorFromWorld(Vector3 worldPoint, out byte pickedVoxelValue)
{
pickedVoxelValue = 0;
if (avatarEditorTargetGroup != null)
{
if (!avatarEditorTargetGroup.IntersectsSphere(worldPoint, 0.2f))
{
return false;
}
Vector3 pickedWorldCenter;
float pickedDistanceSquared;
return avatarEditorTargetGroup.TryPickNearestVoxelValue(worldPoint, 0.2f, out pickedVoxelValue, out pickedWorldCenter, out pickedDistanceSquared);
}
if (groupManager != null)
{
return groupManager.TryPickNearestVoxelValue(worldPoint, 0.2f, out pickedVoxelValue);
}
return false;
}
private void ApplyPickedVoxelValueToPalette(byte voxelValue)
{
if (!PackedVoxel.IsAir(voxelValue))
{
selectedColorIndex = PackedVoxel.GetColorIndex(voxelValue);
selectedMaterial = PackedVoxel.GetMaterial(voxelValue);
SyncPaletteCursorToSelectedColor();
UpdatePaletteSelectionVisuals();
}
}
private void EnsureBrushIndicator()
{
if (!(brushIndicator != null))
{
GameObject gameObject = GameObject.CreatePrimitive(PrimitiveType.Sphere);
gameObject.name = "BrushRadiusIndicator";
gameObject.transform.SetParent(base.transform, worldPositionStays: false);
gameObject.layer = base.gameObject.layer;
Collider component = gameObject.GetComponent<Collider>();
if (component != null)
{
component.enabled = false;
}
brushIndicator = gameObject.transform;
brushIndicatorRenderer = gameObject.GetComponent<MeshRenderer>();
brushIndicatorRenderer.shadowCastingMode = ShadowCastingMode.Off;
brushIndicatorRenderer.receiveShadows = false;
brushIndicatorRenderer.sharedMaterial = GetOrCreateBrushIndicatorMaterial();
SetBrushIndicatorVisible(visible: false);
}
}
private void EnsureColorPickIndicator()
{
if (!(colorPickIndicator != null))
{
GameObject gameObject = GameObject.CreatePrimitive(PrimitiveType.Sphere);
gameObject.name = "ColorPickIndicator";
gameObject.transform.SetParent(base.transform, worldPositionStays: false);
gameObject.layer = base.gameObject.layer;
Collider component = gameObject.GetComponent<Collider>();
if (component != null)
{
component.enabled = false;
}
colorPickIndicator = gameObject.transform;
colorPickIndicatorRenderer = gameObject.GetComponent<MeshRenderer>();
colorPickIndicatorRenderer.shadowCastingMode = ShadowCastingMode.Off;
colorPickIndicatorRenderer.receiveShadows = false;
Material orCreateBrushIndicatorMaterial = GetOrCreateBrushIndicatorMaterial();
if (orCreateBrushIndicatorMaterial != null)
{
colorPickIndicatorMaterial = Object.Instantiate(orCreateBrushIndicatorMaterial);
colorPickIndicatorMaterial.name = "ColorPickIndicatorMaterial";
colorPickIndicatorRenderer.sharedMaterial = colorPickIndicatorMaterial;
}
SetColorPickIndicatorVisible(visible: false);
}
}
private void SetColorPickIndicatorVisible(bool visible)
{
if (colorPickIndicatorRenderer != null)
{
colorPickIndicatorRenderer.enabled = visible;
}
}
private void EnsurePaletteUi()
{
if (paletteRoot != null)
{
return;
}
paletteRoot = new GameObject("LeftPaletteUI").transform;
paletteRoot.SetParent(base.transform, worldPositionStays: false);
for (int i = 0; i < 64; i++)
{
GameObject obj = GameObject.CreatePrimitive(PrimitiveType.Cube);
obj.name = $"PaletteCell_{i:D2}";
obj.transform.SetParent(paletteRoot, worldPositionStays: false);
obj.transform.localRotation = Quaternion.identity;
obj.transform.localScale = Vector3.one * 0.03f;
Collider component = obj.GetComponent<Collider>();
if (component != null)
{
component.enabled = false;
}
MeshRenderer component2 = obj.GetComponent<MeshRenderer>();
component2.shadowCastingMode = ShadowCastingMode.Off;
component2.receiveShadows = false;
component2.sharedMaterial = GetOrCreatePaletteCellMaterial();
paletteCellRenderers[i] = component2;
paletteCellBlocks[i] = new MaterialPropertyBlock();
}
GameObject gameObject = new GameObject("PaletteCursor");
gameObject.transform.SetParent(paletteRoot, worldPositionStays: false);
paletteCursorRenderer = gameObject.AddComponent<LineRenderer>();
paletteCursorRenderer.useWorldSpace = false;
paletteCursorRenderer.loop = true;
paletteCursorRenderer.positionCount = 4;
paletteCursorRenderer.alignment = LineAlignment.View;
paletteCursorRenderer.widthMultiplier = 0.0035f;
paletteCursorRenderer.numCapVertices = 0;
paletteCursorRenderer.numCornerVertices = 0;
paletteCursorRenderer.shadowCastingMode = ShadowCastingMode.Off;
paletteCursorRenderer.receiveShadows = false;
paletteCursorRenderer.sharedMaterial = GetOrCreatePaletteCursorMaterial();
paletteCursorRenderer.enabled = false;
UpdatePaletteSelectionVisuals();
}
private void UpdateBrushIndicator(bool hasBrushPose, Vector3 brushPoint)
{
EnsureBrushIndicator();
if (brushIndicator == null || brushIndicatorRenderer == null)
{
return;
}
if (!creatorMode)
{
SetBrushIndicatorVisible(visible: false);
return;
}
VRGroupSelector instance = VRGroupSelector.Instance;
Vector3 worldPosition = brushPoint;
bool flag = instance != null && instance.IsSelecting && instance.TryGetSelectionCenter(out worldPosition);
if (flag)
{
hasBrushPose = true;
brushPoint = worldPosition;
}
if (!hasBrushPose)
{
SetBrushIndicatorVisible(visible: false);
return;
}
brushIndicator.position = brushPoint;
brushIndicator.rotation = Quaternion.identity;
float num = (flag ? instance.SelectionRadius : brushRadius);
float num2 = Mathf.Max((groupManager != null) ? groupManager.VoxelSize : 0.125f, num * 2f);
brushIndicator.localScale = Vector3.one * num2;
Color32 brushIndicatorColor = GetBrushIndicatorColor();
ApplyBrushIndicatorColor(brushIndicatorColor);
SetBrushIndicatorVisible(brushIndicatorColor.a > 0);
}
private Color32 GetBrushIndicatorColor()
{
if (erasing)
{
return ErasingIndicatorColor;
}
if (painting)
{
return PaintingIndicatorColor;
}
if (drawingStroke)
{
return DrawingIndicatorColor;
}
VRGroupSelector instance = VRGroupSelector.Instance;
if (instance != null && instance.IsSelecting)
{
return SelectingIndicatorColor;
}
return IdleIndicatorColor;
}
private Material GetOrCreateBrushIndicatorMaterial()
{
if (brushIndicatorMaterial != null)
{
return brushIndicatorMaterial;
}
Shader shader = Shader.Find("Universal Render Pipeline/Particles/Unlit") ?? Shader.Find("Universal Render Pipeline/Unlit") ?? Shader.Find("Sprites/Default") ?? Shader.Find("Standard");
brushIndicatorMaterial = new Material(shader)
{
name = "BlockSpace_BrushIndicator"
};
if (brushIndicatorMaterial.HasProperty("_Surface"))
{
brushIndicatorMaterial.SetFloat("_Surface", 1f);
}
if (brushIndicatorMaterial.HasProperty("_Blend"))
{
brushIndicatorMaterial.SetFloat("_Blend", 0f);
}
if (brushIndicatorMaterial.HasProperty("_Cull"))
{
brushIndicatorMaterial.SetFloat("_Cull", 2f);
}
if (brushIndicatorMaterial.HasProperty("_SrcBlend"))
{
brushIndicatorMaterial.SetFloat("_SrcBlend", 5f);
}
if (brushIndicatorMaterial.HasProperty("_DstBlend"))
{
brushIndicatorMaterial.SetFloat("_DstBlend", 10f);
}
if (brushIndicatorMaterial.HasProperty("_SrcBlendAlpha"))
{
brushIndicatorMaterial.SetFloat("_SrcBlendAlpha", 1f);
}
if (brushIndicatorMaterial.HasProperty("_DstBlendAlpha"))
{
brushIndicatorMaterial.SetFloat("_DstBlendAlpha", 10f);
}
if (brushIndicatorMaterial.HasProperty("_ZWrite"))
{
brushIndicatorMaterial.SetFloat("_ZWrite", 0f);
}
brushIndicatorMaterial.renderQueue = 3000;
ApplyBrushIndicatorColor(IdleIndicatorColor);
return brushIndicatorMaterial;
}
private Material GetOrCreatePaletteCellMaterial()
{
if (paletteCellMaterial != null)
{
return paletteCellMaterial;
}
Shader paletteCellShader = GetPaletteCellShader(selectedMaterial == VoxelMaterial.Lit);
paletteCellMaterial = new Material(paletteCellShader)
{
name = "BlockSpace_PaletteCell"
};
if (paletteCellMaterial.HasProperty("_Surface"))
{
paletteCellMaterial.SetFloat("_Surface", 0f);
}
if (paletteCellMaterial.HasProperty("_Cull"))
{
paletteCellMaterial.SetFloat("_Cull", 0f);
}
if (paletteCellMaterial.HasProperty("_ZWrite"))
{
paletteCellMaterial.SetFloat("_ZWrite", 1f);
}
return paletteCellMaterial;
}
private void ConfigurePaletteCellMaterial(Material material)
{
if (!(material == null))
{
Shader paletteCellShader = GetPaletteCellShader(selectedMaterial == VoxelMaterial.Lit);
if (paletteCellShader != null && material.shader != paletteCellShader)
{
material.shader = paletteCellShader;
}
bool flag = selectedMaterial == VoxelMaterial.Transparent || selectedMaterial == VoxelMaterial.Invisible;
if (material.HasProperty("_Surface"))
{
material.SetFloat("_Surface", flag ? 1f : 0f);
}
if (material.HasProperty("_Mode"))
{
material.SetFloat("_Mode", flag ? 3f : 0f);
}
if (material.HasProperty("_Blend"))
{
material.SetFloat("_Blend", 0f);
}
if (material.HasProperty("_Cull"))
{
material.SetFloat("_Cull", 2f);
}
if (material.HasProperty("_SrcBlend"))
{
material.SetFloat("_SrcBlend", flag ? 5f : 1f);
}
if (material.HasProperty("_DstBlend"))
{
material.SetFloat("_DstBlend", flag ? 10f : 0f);
}
if (material.HasProperty("_SrcBlendAlpha"))
{
material.SetFloat("_SrcBlendAlpha", 1f);
}
if (material.HasProperty("_DstBlendAlpha"))
{
material.SetFloat("_DstBlendAlpha", flag ? 10f : 0f);
}
if (material.HasProperty("_ZWrite"))
{
material.SetFloat("_ZWrite", flag ? 0f : 1f);
}
if (material.HasProperty("_Smoothness"))
{
material.SetFloat("_Smoothness", (selectedMaterial == VoxelMaterial.Transparent) ? 0.9f : 0.08f);
}
if (material.HasProperty("_Metallic"))
{
material.SetFloat("_Metallic", 0f);
}
material.renderQueue = (flag ? 3000 : 2000);
material.SetOverrideTag("RenderType", flag ? "Transparent" : "Opaque");
}
}
private static Shader GetPaletteCellShader(bool useLitShader)
{
if (useLitShader)
{
return Shader.Find("Universal Render Pipeline/Particles/Lit") ?? Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard");
}
return Shader.Find("Universal Render Pipeline/Particles/Unlit") ?? Shader.Find("Universal Render Pipeline/Unlit") ?? Shader.Find("Sprites/Default") ?? Shader.Find("Standard");
}
private Color GetPalettePreviewColor(byte colorIndex)
{
return Palette.GetMaterialPreviewColor(colorIndex, selectedMaterial);
}
private Color GetPalettePreviewEmission(Color previewColor)
{
return Color.black;
}
private Material GetOrCreatePaletteCursorMaterial()
{
if (paletteCursorMaterial != null)
{
return paletteCursorMaterial;
}
Shader shader = Shader.Find("Universal Render Pipeline/Unlit") ?? Shader.Find("Universal Render Pipeline/Particles/Unlit") ?? Shader.Find("Sprites/Default") ?? Shader.Find("Standard");
paletteCursorMaterial = new Material(shader)
{
name = "BlockSpace_PaletteCursor"
};
if (paletteCursorMaterial.HasProperty("_Surface"))
{
paletteCursorMaterial.SetFloat("_Surface", 0f);
}
if (paletteCursorMaterial.HasProperty("_Cull"))
{
paletteCursorMaterial.SetFloat("_Cull", 0f);
}
return paletteCursorMaterial;
}
private void EnsureGroupSelector()
{
VRGroupSelector vRGroupSelector = GetComponent<VRGroupSelector>();
if (vRGroupSelector == null)
{
vRGroupSelector = base.gameObject.AddComponent<VRGroupSelector>();
}
vRGroupSelector.Configure(groupManager, trackingOrigin, rightHandAnchor);
vRGroupSelector.SetSelectionRadius(brushRadius);
}
private void EnsureNodeGraph()
{
NodeGraphManager nodeGraphManager = GetComponent<NodeGraphManager>();
if (nodeGraphManager == null)
{
nodeGraphManager = base.gameObject.AddComponent<NodeGraphManager>();
}
nodeGraphManager.Configure(groupManager, this, trackingOrigin, leftHandAnchor, rightHandAnchor);
if (GetComponent<NodeGraphPhotonSync>() == null)
{
base.gameObject.AddComponent<NodeGraphPhotonSync>();
}
}
private void EnsureDesktopRigController()
{
GameObject gameObject = base.gameObject;
DesktopRigController desktopRigController = gameObject.GetComponent<DesktopRigController>();
if (desktopRigController == null)
{
desktopRigController = gameObject.AddComponent<DesktopRigController>();
}
desktopRigController.Configure(base.transform, (Camera.main != null) ? Camera.main.transform : null, leftHandAnchor, rightHandAnchor);
}
private void EnsureAvatarCustomizer()
{
GameObject gameObject = GameObject.Find("Avatar Customizer");
if (!(gameObject == null))
{
AvatarCustomizerController avatarCustomizerController = gameObject.GetComponent<AvatarCustomizerController>();
if (avatarCustomizerController == null)
{
avatarCustomizerController = gameObject.AddComponent<AvatarCustomizerController>();
}
avatarCustomizerController.Configure(groupManager, this);
InventoryController inventoryController = gameObject.GetComponent<InventoryController>();
if (inventoryController == null)
{
inventoryController = gameObject.AddComponent<InventoryController>();
}
inventoryController.Configure(groupManager, this);
}
}
private void ApplyBrushIndicatorColor(Color32 color)
{
Material orCreateBrushIndicatorMaterial = GetOrCreateBrushIndicatorMaterial();
if (orCreateBrushIndicatorMaterial.HasProperty("_BaseColor"))
{
orCreateBrushIndicatorMaterial.SetColor("_BaseColor", color);
}
if (orCreateBrushIndicatorMaterial.HasProperty("_Color"))
{
orCreateBrushIndicatorMaterial.SetColor("_Color", color);
}
}
private static void ApplyIndicatorMaterialColor(Material material, Color32 color)
{
if (!(material == null))
{
if (material.HasProperty("_BaseColor"))
{
material.SetColor("_BaseColor", color);
}
if (material.HasProperty("_Color"))
{
material.SetColor("_Color", color);
}
}
}
private void SetBrushIndicatorVisible(bool visible)
{
if (brushIndicatorRenderer != null)
{
brushIndicatorRenderer.enabled = visible;
}
}
private void SetPaletteVisible(bool visible)
{
if (paletteRoot != null)
{
paletteRoot.gameObject.SetActive(visible);
}
}
private void HandleCreatorToggle()
{
if (WorldLoadingScreenController.Instance != null && WorldLoadingScreenController.Instance.IsLoading)
{
return;
}
if (!useXRInput)
{
if (!Input.GetKeyDown(KeyCode.LeftAlt))
{
return;
}
creatorMode = !creatorMode;
groupManager.SetCreatorMode(creatorMode);
creatorMode = groupManager.CreatorMode;
if (!creatorMode)
{
if (paletteOpen)
{
paletteOpen = false;
leftPaletteAxisLatched = false;
ApplyPaletteLocomotionGate(disableMovement: false);
SetPaletteVisible(visible: false);
}
ApplySelectionLocomotionGate(disableMovement: false);
CancelStroke();
if (erasing)
{
EndErase();
}
if (painting)
{
EndPaint();
}
VRGroupSelector instance = VRGroupSelector.Instance;
if (instance != null && instance.HasSelection)
{
instance.ClearSelectionForToolUse();
}
NodeGraphManager instance2 = NodeGraphManager.Instance;
if (instance2 != null)
{
instance2.CancelEditingInteractions(clearSelection: true);
}
}
return;
}
bool flag = ReadGripHeld(leftHand);
bool flag2 = ReadFloat(leftHand, CommonUsages.trigger) >= triggerThreshold;
if (flag && !leftGripHeldPrevious)
{
lastLeftGripPressTime = Time.unscaledTime;
}
if (flag2 && !leftTriggerHeldPrevious)
{
lastLeftTriggerPressTime = Time.unscaledTime;
}
if (!leftCreatorChordConsumed && flag && flag2)
{
float num = Mathf.Max(lastLeftGripPressTime, lastLeftTriggerPressTime);
if (num > float.NegativeInfinity && Mathf.Abs(lastLeftGripPressTime - lastLeftTriggerPressTime) <= creatorToggleChordWindow && Time.unscaledTime - num <= creatorToggleChordWindow)
{
creatorMode = !creatorMode;
groupManager.SetCreatorMode(creatorMode);
creatorMode = groupManager.CreatorMode;
if (!creatorMode)
{
if (paletteOpen)
{
paletteOpen = false;
leftPaletteAxisLatched = false;
ApplyPaletteLocomotionGate(disableMovement: false);
SetPaletteVisible(visible: false);
}
ApplySelectionLocomotionGate(disableMovement: false);
CancelStroke();
if (erasing)
{
EndErase();
}
VRGroupSelector instance3 = VRGroupSelector.Instance;
if (instance3 != null && instance3.HasSelection)
{
instance3.ClearSelectionForToolUse();
}
NodeGraphManager instance4 = NodeGraphManager.Instance;
if (instance4 != null)
{
instance4.CancelEditingInteractions(clearSelection: true);
}
}
leftCreatorChordConsumed = true;
}
}
if (!flag && !flag2)
{
leftCreatorChordConsumed = false;
}
leftGripHeldPrevious = flag;
leftTriggerHeldPrevious = flag2;
}
private void HandlePaletteToggleAndNavigation()
{
bool flag = (useXRInput ? ReadBool(leftHand, CommonUsages.secondaryButton) : Input.GetKeyDown(KeyCode.Tab));
if (flag && !leftPrimaryPrevious)
{
paletteOpen = !paletteOpen;
leftPaletteAxisLatched = false;
ApplyPaletteLocomotionGate(paletteOpen);
if (paletteOpen)
{
SyncPaletteCursorToSelectedColor();
UpdatePaletteSelectionVisuals();
}
else
{
SetPaletteVisible(visible: false);
}
leftPrimaryPrevious = flag;
return;
}
leftPrimaryPrevious = flag;
if (!paletteOpen)
{
SetPaletteVisible(visible: false);
return;
}
if (!useXRInput)
{
bool flag2 = false;
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
paletteColumn = WrapPaletteIndex(paletteColumn - 1, 8);
flag2 = true;
}
else if (Input.GetKeyDown(KeyCode.RightArrow))
{
paletteColumn = WrapPaletteIndex(paletteColumn + 1, 8);
flag2 = true;
}
else if (Input.GetKeyDown(KeyCode.UpArrow))
{
paletteRow = WrapPaletteIndex(paletteRow - 1, 8);
flag2 = true;
}
else if (Input.GetKeyDown(KeyCode.DownArrow))
{
paletteRow = WrapPaletteIndex(paletteRow + 1, 8);
flag2 = true;
}
if (flag2)
{
selectedColorIndex = (byte)(paletteRow * 8 + paletteColumn);
UpdatePaletteSelectionVisuals();
}
return;
}
Vector2 vector = ReadVector2(leftHand, CommonUsages.primary2DAxis);
if (Mathf.Abs(vector.x) < thumbstickDeadZone && Mathf.Abs(vector.y) < thumbstickDeadZone)
{
leftPaletteAxisLatched = false;
}
else if (!leftPaletteAxisLatched)
{
leftPaletteAxisLatched = true;
if (Mathf.Abs(vector.x) >= Mathf.Abs(vector.y))
{
paletteColumn = WrapPaletteIndex(paletteColumn + ((!(vector.x > 0f)) ? 1 : (-1)), 8);
}
else
{
paletteRow = WrapPaletteIndex(paletteRow + ((!(vector.y > 0f)) ? 1 : (-1)), 8);
}
selectedColorIndex = (byte)(paletteRow * 8 + paletteColumn);
UpdatePaletteSelectionVisuals();
}
}
private void HandleMaterialCycle()
{
bool flag = (useXRInput ? ReadBool(leftHand, CommonUsages.primary2DAxisClick) : Input.GetKeyDown(KeyCode.E));
if (flag && !leftThumbstickClickPrevious)
{
selectedMaterial = (selectedMaterial + 1) & VoxelMaterial.Invisible;
UpdatePaletteSelectionVisuals();
}
leftThumbstickClickPrevious = flag;
}
private void ApplyBrushRadiusLimits()
{
float num = ((groupManager != null) ? groupManager.VoxelSize : 0.125f);
if (avatarEditorTargetGroup != null)
{
num *= 0.5f;
}
minBrushRadius = num * 0.5f;
maxBrushRadius = num * 5f;
brushRadiusStep = num * 0.5f;
brushRadius = Mathf.Clamp(brushRadius, minBrushRadius, maxBrushRadius);
brushDistance = Mathf.Clamp(brushDistance, minBrushDistance, maxBrushDistance);
}
private Vector3 AdjustBrushPointForAvatarEditing(Vector3 worldPoint)
{
if (avatarEditorTargetGroup == null)
{
return worldPoint;
}
Vector3 position = ((avatarEditorTargetGroup.transform.parent != null) ? avatarEditorTargetGroup.transform.parent : avatarEditorTargetGroup.transform).position;
return position + (worldPoint - position) * 2f;
}
private void HandleBrushRadius()
{
if (!creatorMode || Time.unscaledTime < nextRadiusChangeTime)
{
return;
}
if (!useXRInput)
{
float y = Input.mouseScrollDelta.y;
if (!(Mathf.Abs(y) < 0.01f))
{
float num = Mathf.Sign(y);
if (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl))
{
brushDistance = Mathf.Clamp(brushDistance + num * brushDistanceStep, minBrushDistance, maxBrushDistance);
}
else
{
brushRadius = Mathf.Clamp(brushRadius + num * brushRadiusStep, minBrushRadius, maxBrushRadius);
}
nextRadiusChangeTime = Time.unscaledTime + radiusRepeatDelay;
}
}
else
{
Vector2 vector = ReadVector2(rightHand, CommonUsages.primary2DAxis);
if (vector.y >= thumbstickDeadZone)
{
brushRadius = Mathf.Min(maxBrushRadius, brushRadius + brushRadiusStep);
nextRadiusChangeTime = Time.unscaledTime + radiusRepeatDelay;
}
else if (vector.y <= 0f - thumbstickDeadZone)
{
brushRadius = Mathf.Max(minBrushRadius, brushRadius - brushRadiusStep);
nextRadiusChangeTime = Time.unscaledTime + radiusRepeatDelay;
}
}
}
private void SyncSelectionRadius()
{
VRGroupSelector instance = VRGroupSelector.Instance;
if (instance != null)
{
instance.SetSelectionRadius(brushRadius);
}
}
private void UpdatePaletteUi()
{
EnsurePaletteUi();
if (!paletteOpen)
{
SetPaletteVisible(visible: false);
return;
}
if (!TryGetPalettePose(out var worldPosition, out var worldRotation))
{
SetPaletteVisible(visible: false);
return;
}
SetPaletteVisible(visible: true);
paletteRoot.SetPositionAndRotation(worldPosition, worldRotation);
}
private void SyncPaletteCursorToSelectedColor()
{
int num = Mathf.Clamp(selectedColorIndex, 0, 63);
paletteRow = num / 8;
paletteColumn = num % 8;
selectedColorIndex = (byte)num;
}
private void UpdatePaletteSelectionVisuals()
{
if (paletteRoot == null)
{
return;
}
Material orCreatePaletteCellMaterial = GetOrCreatePaletteCellMaterial();
ConfigurePaletteCellMaterial(orCreatePaletteCellMaterial);
for (int i = 0; i < 64; i++)
{
MeshRenderer meshRenderer = paletteCellRenderers[i];
MaterialPropertyBlock materialPropertyBlock = paletteCellBlocks[i];
if (meshRenderer == null || materialPropertyBlock == null)
{
continue;
}
int num = i / 8;
int num2 = i % 8;
bool flag = num == paletteRow && num2 == paletteColumn;
Transform obj = meshRenderer.transform;
Vector3 paletteCellLocalPosition = GetPaletteCellLocalPosition(num, num2);
paletteCellLocalPosition.z = (flag ? 0.01f : 0f);
obj.localPosition = paletteCellLocalPosition;
obj.localScale = Vector3.one * (flag ? 0.05f : 0.03f);
materialPropertyBlock.Clear();
Color palettePreviewColor = GetPalettePreviewColor((byte)i);
Color palettePreviewEmission = GetPalettePreviewEmission(palettePreviewColor);
if (meshRenderer.sharedMaterial != null)
{
if (meshRenderer.sharedMaterial.HasProperty("_BaseColor"))
{
materialPropertyBlock.SetColor("_BaseColor", palettePreviewColor);
}
if (meshRenderer.sharedMaterial.HasProperty("_Color"))
{
materialPropertyBlock.SetColor("_Color", palettePreviewColor);
}
if (meshRenderer.sharedMaterial.HasProperty("_EmissionColor"))
{
materialPropertyBlock.SetColor("_EmissionColor", palettePreviewEmission);
}
if (meshRenderer.sharedMaterial.HasProperty("_EmissiveColor"))
{
materialPropertyBlock.SetColor("_EmissiveColor", palettePreviewEmission);
}
}
meshRenderer.SetPropertyBlock(materialPropertyBlock);
}
UpdatePaletteCursorVisual();
}
private void UpdatePaletteCursorVisual()
{
if (!(paletteCursorRenderer == null))
{
paletteCursorRenderer.enabled = false;
float num = 0.025f;
Vector3 vector = GetPaletteCellLocalPosition(paletteRow, paletteColumn) + new Vector3(0f, 0f, 0.02f);
paletteCursorRenderer.SetPosition(0, vector + new Vector3(0f - num, 0f - num, 0f));
paletteCursorRenderer.SetPosition(1, vector + new Vector3(0f - num, num, 0f));
paletteCursorRenderer.SetPosition(2, vector + new Vector3(num, num, 0f));
paletteCursorRenderer.SetPosition(3, vector + new Vector3(num, 0f - num, 0f));
Color32 color = Palette.GetColor(selectedColorIndex);
Color32 color2 = (((0.2126f * (float)(int)color.r + 0.7152f * (float)(int)color.g + 0.0722f * (float)(int)color.b) / 255f > 0.55f) ? PaletteCursorDarkColor : PaletteCursorLightColor);
paletteCursorRenderer.startColor = color2;
paletteCursorRenderer.endColor = color2;
}
}
private Vector3 GetPaletteCellLocalPosition(int row, int column)
{
float num = 0.03857143f;
float x = -0.135f + (float)column * num;
float y = 0.135f - (float)row * num;
return new Vector3(x, y, 0f);
}
private float GetPaletteCellSize()
{
return 0.03f;
}
private void RasterizeSegment(Vector3 start, Vector3 end, float radius)
{
if (activeStrokeGroup == null)
{
return;
}
if (activeStrokeGroup == avatarEditorTargetGroup)
{
RasterizeAvatarEditorSegment(start, end, radius);
return;
}
float voxelSize = groupManager.VoxelSize;
float num = Mathf.Max(voxelSize * 0.5f, radius * 0.5f);
float num2 = Vector3.Distance(start, end);
int num3 = Mathf.Max(1, Mathf.CeilToInt(num2 / num));
bool flag = false;
for (int i = 0; i <= num3; i++)
{
float t = ((num3 == 0) ? 0f : ((float)i / (float)num3));
Vector3 worldCenter = Vector3.Lerp(start, end, t);
flag |= AddSphere(worldCenter, radius, voxelSize);
}
if (flag)
{
groupManager.RefreshStrokeGroup(activeStrokeGroup);
UpdateStrokePreviewBroadcast(end);
}
}
private bool AddSphere(Vector3 worldCenter, float radius, float voxelSize)
{
float num = radius * radius;
int x = Mathf.RoundToInt(worldCenter.x / voxelSize - 0.5f);
int y = Mathf.RoundToInt(worldCenter.y / voxelSize - 0.5f);
int z = Mathf.RoundToInt(worldCenter.z / voxelSize - 0.5f);
Vector3Int vector3Int = new Vector3Int(x, y, z);
bool flag = false;
if (strokeCells.Add(vector3Int))
{
flag |= groupManager.AddVoxelToStrokeGroup(activeStrokeGroup, vector3Int, activeStrokeVoxelValue);
}
int num2 = Mathf.FloorToInt((worldCenter.x - radius) / voxelSize);
int num3 = Mathf.FloorToInt((worldCenter.y - radius) / voxelSize);
int num4 = Mathf.FloorToInt((worldCenter.z - radius) / voxelSize);
int num5 = Mathf.FloorToInt((worldCenter.x + radius) / voxelSize);
int num6 = Mathf.FloorToInt((worldCenter.y + radius) / voxelSize);
int num7 = Mathf.FloorToInt((worldCenter.z + radius) / voxelSize);
for (int i = num4; i <= num7; i++)
{
for (int j = num3; j <= num6; j++)
{
for (int k = num2; k <= num5; k++)
{
if (!((new Vector3(((float)k + 0.5f) * voxelSize, ((float)j + 0.5f) * voxelSize, ((float)i + 0.5f) * voxelSize) - worldCenter).sqrMagnitude > num))
{
Vector3Int vector3Int2 = new Vector3Int(k, j, i);
if (strokeCells.Add(vector3Int2))
{
flag |= groupManager.AddVoxelToStrokeGroup(activeStrokeGroup, vector3Int2, activeStrokeVoxelValue);
}
}
}
}
}
return flag;
}
private void RasterizeAvatarEditorSegment(Vector3 start, Vector3 end, float radius)
{
if (!(avatarEditorTargetGroup == null) && !(groupManager == null))
{
float voxelSize = groupManager.VoxelSize;
float num = Mathf.Max(voxelSize * 0.5f, radius * 0.5f);
float num2 = Vector3.Distance(start, end);
int num3 = Mathf.Max(1, Mathf.CeilToInt(num2 / num));
bool flag = false;
for (int i = 0; i <= num3; i++)
{
float t = ((num3 == 0) ? 0f : ((float)i / (float)num3));
Vector3 worldCenter = Vector3.Lerp(start, end, t);
flag |= AddSphereToAvatarGroup(avatarEditorTargetGroup, worldCenter, radius, voxelSize, activeStrokeVoxelValue);
}
if (flag)
{
avatarEditUndoSessionChanged = true;
avatarEditorTargetGroup.RebuildMesh();
DisableAvatarGroupCollider(avatarEditorTargetGroup);
}
}
}
private bool AddSphereToAvatarGroup(VoxelGroup group, Vector3 worldCenter, float radius, float voxelSize, byte voxelValue)
{
if (group == null)
{
return false;
}
Transform transform = ((group.UsesLocalGridTransform && group.transform.parent != null) ? group.transform.parent : null);
Vector3 vector = ((transform != null) ? transform.InverseTransformPoint(worldCenter) : worldCenter) / voxelSize;
float num = radius * radius;
float num2 = radius / voxelSize;
int x = Mathf.RoundToInt(vector.x - 0.5f);
int y = Mathf.RoundToInt(vector.y - 0.5f);
int z = Mathf.RoundToInt(vector.z - 0.5f);
bool flag = group.SetStoredVoxel(new Vector3Int(x, y, z), voxelValue, markMeshDirty: false, markColliderDirty: false);
int num3 = Mathf.FloorToInt(vector.x - num2);
int num4 = Mathf.FloorToInt(vector.y - num2);
int num5 = Mathf.FloorToInt(vector.z - num2);
int num6 = Mathf.FloorToInt(vector.x + num2);
int num7 = Mathf.FloorToInt(vector.y + num2);
int num8 = Mathf.FloorToInt(vector.z + num2);
for (int i = num5; i <= num8; i++)
{
for (int j = num4; j <= num7; j++)
{
for (int k = num3; k <= num6; k++)
{
Vector3 vector2 = new Vector3(((float)k + 0.5f) * voxelSize, ((float)j + 0.5f) * voxelSize, ((float)i + 0.5f) * voxelSize);
if (!((((transform != null) ? transform.TransformPoint(vector2) : vector2) - worldCenter).sqrMagnitude > num))
{
flag |= group.SetStoredVoxel(new Vector3Int(k, j, i), voxelValue, markMeshDirty: false, markColliderDirty: false);
}
}
}
}
return flag;
}
private void UpdateAvatarEditorErase(Vector3 start, Vector3 end)
{
if (!(avatarEditorTargetGroup == null) && !(groupManager == null))
{
float num = Mathf.Max(groupManager.VoxelSize * 0.5f, brushRadius * 0.5f);
float num2 = Vector3.Distance(start, end);
int num3 = Mathf.Max(1, Mathf.CeilToInt(num2 / num));
bool flag = false;
for (int i = 0; i <= num3; i++)
{
float t = ((num3 == 0) ? 0f : ((float)i / (float)num3));
Vector3 worldCenter = Vector3.Lerp(start, end, t);
flag |= avatarEditorTargetGroup.EraseSphere(worldCenter, brushRadius, markMeshDirty: false, markColliderDirty: false);
}
if (flag)
{
avatarEditUndoSessionChanged = true;
avatarEditorTargetGroup.RebuildMesh();
DisableAvatarGroupCollider(avatarEditorTargetGroup);
}
}
}
private void UpdateAvatarEditorPaint(Vector3 start, Vector3 end)
{
if (!(avatarEditorTargetGroup == null) && !(groupManager == null))
{
byte currentBrushVoxelValue = GetCurrentBrushVoxelValue();
float num = Mathf.Max(groupManager.VoxelSize * 0.5f, brushRadius * 0.5f);
float num2 = Vector3.Distance(start, end);
int num3 = Mathf.Max(1, Mathf.CeilToInt(num2 / num));
bool flag = false;
for (int i = 0; i <= num3; i++)
{
float t = ((num3 == 0) ? 0f : ((float)i / (float)num3));
Vector3 worldCenter = Vector3.Lerp(start, end, t);
flag |= avatarEditorTargetGroup.PaintSphere(worldCenter, brushRadius, currentBrushVoxelValue, markMeshDirty: false, markColliderDirty: false);
}
if (flag)
{
avatarEditUndoSessionChanged = true;
avatarEditorTargetGroup.RebuildMesh();
DisableAvatarGroupCollider(avatarEditorTargetGroup);
}
}
}
private void FinishActiveAvatarEditSessions()
{
if (drawingStroke && activeStrokeGroup == avatarEditorTargetGroup)
{
FinalizeStroke();
}
if (erasing)
{
EndErase();
}
if (painting)
{
EndPaint();
}
}
private bool HandleAvatarEditUndo(bool triggerHeld, bool gripHeld)
{
avatarUndoChordWindow = Mathf.Max(0.01f, avatarUndoChordWindow);
if (avatarEditorTargetGroup == null || !creatorMode)
{
if (!gripHeld && !triggerHeld)
{
avatarUndoChordActive = false;
suppressAvatarUndoUntilNeutral = false;
}
rightGripHeldPrevious = gripHeld;
rightTriggerHeldPrevious = triggerHeld;
return false;
}
if (gripHeld && !rightGripHeldPrevious)
{
lastRightGripPressTime = Time.unscaledTime;
}
if (triggerHeld && !rightTriggerHeldPrevious)
{
lastRightTriggerPressTime = Time.unscaledTime;
}
if (!avatarUndoChordActive && !drawingStroke && !erasing && !painting && gripHeld && triggerHeld)
{
float num = Mathf.Max(lastRightGripPressTime, lastRightTriggerPressTime);
if (num > float.NegativeInfinity && Mathf.Abs(lastRightGripPressTime - lastRightTriggerPressTime) <= avatarUndoChordWindow && Time.unscaledTime - num <= avatarUndoChordWindow)
{
avatarUndoChordActive = true;
suppressAvatarUndoUntilNeutral = true;
UndoAvatarEditorAction();
}
}
if (!gripHeld && !triggerHeld)
{
avatarUndoChordActive = false;
suppressAvatarUndoUntilNeutral = false;
}
rightGripHeldPrevious = gripHeld;
rightTriggerHeldPrevious = triggerHeld;
if (!avatarUndoChordActive)
{
return suppressAvatarUndoUntilNeutral;
}
return true;
}
private bool HandleDesktopUndoShortcut()
{
if (useXRInput)
{
return false;
}
bool num = Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl);
bool flag = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);
if (!num)
{
return false;
}
NodeGraphManager instance = NodeGraphManager.Instance;
if (instance != null)
{
if ((Input.GetKeyDown(KeyCode.Y) || (flag && Input.GetKeyDown(KeyCode.Z))) && instance.RedoLastCircuitEdit())
{
return true;
}
if (Input.GetKeyDown(KeyCode.Z) && instance.UndoLastCircuitEdit())
{
return true;
}
}
if (!Input.GetKeyDown(KeyCode.Z))
{
return false;
}
if (avatarEditorTargetGroup != null)
{
return UndoAvatarEditorAction();
}
if (groupManager != null)
{
return groupManager.UndoLastOperation();
}
return false;
}
private void BeginAvatarEditUndoSession(VoxelGroup group)
{
if (!(group == null) && (!avatarEditUndoSessionActive || avatarEditUndoBeforeSnapshot == null || !(avatarEditUndoBeforeSnapshot.group == group)))
{
avatarEditUndoBeforeSnapshot = CaptureAvatarEditSnapshot(group);
avatarEditUndoSessionActive = avatarEditUndoBeforeSnapshot != null;
avatarEditUndoSessionChanged = false;
}
}
private void CompleteAvatarEditUndoSession(VoxelGroup group)
{
if (!avatarEditUndoSessionActive || avatarEditUndoBeforeSnapshot == null)
{
return;
}
AvatarEditSnapshot avatarEditSnapshot = avatarEditUndoBeforeSnapshot;
avatarEditUndoBeforeSnapshot = null;
avatarEditUndoSessionActive = false;
if (!avatarEditUndoSessionChanged || avatarEditSnapshot.group != group)
{
avatarEditUndoSessionChanged = false;
return;
}
AvatarEditSnapshot avatarEditSnapshot2 = CaptureAvatarEditSnapshot(group);
avatarEditUndoSessionChanged = false;
if (avatarEditSnapshot2 != null && !AvatarSnapshotsMatch(avatarEditSnapshot, avatarEditSnapshot2))
{
avatarUndoStack.Push(new AvatarEditUndoRecord
{
before = avatarEditSnapshot,
after = avatarEditSnapshot2
});
}
}
private static AvatarEditSnapshot CaptureAvatarEditSnapshot(VoxelGroup group)
{
if (group == null)
{
return null;
}
byte[] voxels = ((group.voxels != null && group.voxels.Length != 0) ? ((byte[])group.voxels.Clone()) : new byte[0]);
return new AvatarEditSnapshot
{
group = group,
position = group.position,
packedRotation = group.packedRotation,
size = group.size,
voxels = voxels
};
}
private void RestoreAvatarEditSnapshot(AvatarEditSnapshot snapshot)
{
if (snapshot != null && !(snapshot.group == null))
{
snapshot.group.OverwriteData(snapshot.position, snapshot.packedRotation, snapshot.size, (snapshot.voxels != null) ? ((byte[])snapshot.voxels.Clone()) : new byte[0], queueRebuild: false);
snapshot.group.SetGreedyRenderMeshing(enabled: true);
snapshot.group.RebuildMesh();
snapshot.group.RebuildCollider();
DisableAvatarGroupCollider(snapshot.group);
}
}
private static bool AvatarSnapshotsMatch(AvatarEditSnapshot before, AvatarEditSnapshot after)
{
if (before == null || after == null)
{
return false;
}
if (before.group != after.group || before.position != after.position || before.packedRotation != after.packedRotation || before.size != after.size)
{
return false;
}
int num = ((before.voxels != null) ? before.voxels.Length : 0);
int num2 = ((after.voxels != null) ? after.voxels.Length : 0);
if (num != num2)
{
return false;
}
for (int i = 0; i < num; i++)
{
if (before.voxels[i] != after.voxels[i])
{
return false;
}
}
return true;
}
private void FinalizeAvatarEditorGroup(VoxelGroup group)
{
if (!(group == null))
{
if (!group.TrimToContents())
{
group.OverwriteData(Vector3Int.zero, 0, Vector3Int.zero, new byte[0], queueRebuild: false);
}
group.SetGreedyRenderMeshing(enabled: true);
group.RebuildMesh();
group.RebuildCollider();
DisableAvatarGroupCollider(group);
CompleteAvatarEditUndoSession(group);
}
}
private static void DisableAvatarGroupCollider(VoxelGroup group)
{
if (!(group == null) && !(group.meshCollider == null))
{
group.meshCollider.enabled = false;
}
}
private void EnsureDevices()
{
if (!rightHand.isValid || !leftHand.isValid)
{
AcquireDevices();
}
}
private void AcquireDevices()
{
rightHand = InputDevices.GetDeviceAtXRNode(XRNode.RightHand);
leftHand = InputDevices.GetDeviceAtXRNode(XRNode.LeftHand);
}
private void RefreshMoveProviders()
{
moveProviders.Clear();
moveProviderEnabledStates.Clear();
AddMoveProvidersFrom(base.gameObject.GetComponentsInParent<ContinuousMoveProvider>(includeInactive: true));
AddMoveProvidersFrom(base.gameObject.GetComponentsInChildren<ContinuousMoveProvider>(includeInactive: true));
AddMoveProvidersFrom(Object.FindObjectsByType<ContinuousMoveProvider>(FindObjectsInactive.Include, FindObjectsSortMode.None));
}
private void RefreshSelectionLocomotionProviders()
{
selectionLocomotionProviders.Clear();
selectionLocomotionStates.Clear();
AddSelectionLocomotionProvidersFrom(Object.FindObjectsByType<LocomotionProvider>(FindObjectsInactive.Include, FindObjectsSortMode.None));
}
private void AddMoveProvidersFrom(ContinuousMoveProvider[] providers)
{
if (providers == null)
{
return;
}
foreach (ContinuousMoveProvider continuousMoveProvider in providers)
{
if (!(continuousMoveProvider == null) && !moveProviders.Contains(continuousMoveProvider))
{
moveProviders.Add(continuousMoveProvider);
}
}
}
private void AddSelectionLocomotionProvidersFrom(LocomotionProvider[] providers)
{
if (providers == null)
{
return;
}
foreach (LocomotionProvider locomotionProvider in providers)
{
if (!(locomotionProvider == null) && !(locomotionProvider is ContinuousMoveProvider) && !selectionLocomotionProviders.Contains(locomotionProvider))
{
selectionLocomotionProviders.Add(locomotionProvider);
}
}
}
private void ApplyPaletteLocomotionGate(bool disableMovement)
{
if (useXRInput || !disableMovement)
{
ApplyPaletteMoveObjectGate(disableMovement);
}
if (disableMovement)
{
RefreshMoveProviders();
}
else if (moveProviders.Count == 0)
{
RefreshMoveProviders();
}
for (int num = moveProviders.Count - 1; num >= 0; num--)
{
ContinuousMoveProvider continuousMoveProvider = moveProviders[num];
bool value;
if (continuousMoveProvider == null)
{
moveProviders.RemoveAt(num);
}
else if (disableMovement)
{
if (!moveProviderEnabledStates.ContainsKey(continuousMoveProvider))
{
moveProviderEnabledStates.Add(continuousMoveProvider, continuousMoveProvider.enabled);
}
continuousMoveProvider.enabled = false;
}
else if (moveProviderEnabledStates.TryGetValue(continuousMoveProvider, out value))
{
continuousMoveProvider.enabled = value;
}
else
{
continuousMoveProvider.enabled = true;
}
}
if (!disableMovement)
{
moveProviderEnabledStates.Clear();
}
}
private void ApplyPaletteMoveObjectGate(bool disableMovement)
{
if (disableMovement)
{
RefreshPaletteMoveObjects();
}
for (int num = paletteMoveObjects.Count - 1; num >= 0; num--)
{
GameObject gameObject = paletteMoveObjects[num];
bool value;
if (gameObject == null)
{
paletteMoveObjects.RemoveAt(num);
}
else if (disableMovement)
{
if (!paletteMoveObjectStates.ContainsKey(gameObject))
{
paletteMoveObjectStates.Add(gameObject, gameObject.activeSelf);
}
gameObject.SetActive(value: false);
}
else if (paletteMoveObjectStates.TryGetValue(gameObject, out value))
{
gameObject.SetActive(value);
}
}
if (!disableMovement)
{
paletteMoveObjectStates.Clear();
}
}
private void RefreshPaletteMoveObjects()
{
paletteMoveObjects.Clear();
Transform transform = ResolveVrPlayerRoot();
if (transform != null)
{
AddPaletteMoveObjectFrom(transform);
}
Transform[] array = Object.FindObjectsByType<Transform>(FindObjectsInactive.Include, FindObjectsSortMode.None);
foreach (Transform transform2 in array)
{
if (!(transform2 == null) && !(transform2.name != "Move") && !(transform2.parent == null) && !(transform2.parent.name != "Locomotion") && !paletteMoveObjects.Contains(transform2.gameObject))
{
paletteMoveObjects.Add(transform2.gameObject);
}
}
}
private void AddPaletteMoveObjectFrom(Transform root)
{
Transform transform = root.Find("Locomotion/Move");
if (transform != null && !paletteMoveObjects.Contains(transform.gameObject))
{
paletteMoveObjects.Add(transform.gameObject);
}
}
private Transform ResolveVrPlayerRoot()
{
if (PhotonVRManager.Manager != null)
{
if (PhotonVRManager.Manager.LocalPlayer != null)
{
Transform transform = PhotonVRManager.Manager.LocalPlayer.transform;
Transform transform2 = FindAncestorNamed(transform, "VR Player");
if (!(transform2 != null))
{
return transform.root;
}
return transform2;
}
if (PhotonVRManager.Manager.Head != null)
{
Transform head = PhotonVRManager.Manager.Head;
Transform transform3 = FindAncestorNamed(head, "VR Player");
if (!(transform3 != null))
{
return head.root;
}
return transform3;
}
}
return null;
}
private static Transform FindAncestorNamed(Transform start, string name)
{
Transform transform = start;
while (transform != null)
{
if (transform.name == name)
{
return transform;
}
transform = transform.parent;
}
return null;
}
private void ApplySelectionLocomotionGate(bool disableMovement)
{
if (disableMovement == selectionLocomotionBlocked)
{
return;
}
if (disableMovement)
{
RefreshSelectionLocomotionProviders();
}
for (int num = selectionLocomotionProviders.Count - 1; num >= 0; num--)
{
LocomotionProvider locomotionProvider = selectionLocomotionProviders[num];
bool value;
if (locomotionProvider == null)
{
selectionLocomotionProviders.RemoveAt(num);
}
else if (disableMovement)
{
if (!selectionLocomotionStates.ContainsKey(locomotionProvider))
{
selectionLocomotionStates.Add(locomotionProvider, locomotionProvider.enabled);
}
locomotionProvider.enabled = false;
}
else if (selectionLocomotionStates.TryGetValue(locomotionProvider, out value))
{
locomotionProvider.enabled = value;
}
else
{
locomotionProvider.enabled = true;
}
}
selectionLocomotionBlocked = disableMovement;
if (!disableMovement)
{
selectionLocomotionStates.Clear();
}
}
private byte GetCurrentBrushVoxelValue()
{
selectedColorIndex = (byte)GetPaletteCursorIndex();
return PackedVoxel.Create(selectedColorIndex, selectedMaterial);
}
public byte GetSelectedVoxelValue()
{
return GetCurrentBrushVoxelValue();
}
public bool TryGetDesktopSelectionPoint(out Vector3 worldPosition)
{
worldPosition = Vector3.zero;
if (useXRInput)
{
return false;
}
Quaternion worldRotation;
return TryGetDesktopBrushPose(out worldPosition, out worldRotation);
}
public bool TryGetSpawnGridPosition(out Vector3Int gridPosition)
{
gridPosition = Vector3Int.zero;
if (groupManager == null)
{
return false;
}
EnsureDevices();
if (!TryGetActiveBrushPose(out var worldPosition, out var _))
{
return false;
}
float voxelSize = groupManager.VoxelSize;
gridPosition = new Vector3Int(Mathf.FloorToInt(worldPosition.x / voxelSize), Mathf.FloorToInt(worldPosition.y / voxelSize), Mathf.FloorToInt(worldPosition.z / voxelSize));
return true;
}
private bool TryGetActiveBrushPose(out Vector3 worldPosition, out Quaternion worldRotation)
{
if (!useXRInput)
{
return TryGetDesktopBrushPose(out worldPosition, out worldRotation);
}
return TryGetBrushPose(rightHand, XRNode.RightHand, rightHandAnchor, out worldPosition, out worldRotation);
}
private int GetPaletteCursorIndex()
{
return Mathf.Clamp(paletteRow * 8 + paletteColumn, 0, 63);
}
private static bool ReadGripHeld(InputDevice device)
{
if (!device.isValid)
{
return false;
}
bool value;
bool num = device.TryGetFeatureValue(CommonUsages.gripButton, out value) && value;
float value2;
bool flag = device.TryGetFeatureValue(CommonUsages.grip, out value2) && value2 >= 0.75f;
return num || flag;
}
private bool TryGetBrushPose(InputDevice device, XRNode node, Transform anchor, out Vector3 worldPosition, out Quaternion worldRotation)
{
if (!TryGetControllerPose(device, node, anchor, out worldPosition, out worldRotation))
{
worldPosition = Vector3.zero;
worldRotation = Quaternion.identity;
return false;
}
worldPosition += worldRotation * Vector3.forward * brushForwardOffset;
return true;
}
private bool TryGetDesktopBrushPose(out Vector3 worldPosition, out Quaternion worldRotation)
{
if (!TryGetDesktopViewCamera(out var viewCamera))
{
worldPosition = Vector3.zero;
worldRotation = Quaternion.identity;
return false;
}
Transform transform = viewCamera.transform;
worldRotation = transform.rotation;
if (Physics.Raycast(transform.position, transform.forward, out var hitInfo, brushDistance, GetDesktopRaycastMask(), QueryTriggerInteraction.Ignore))
{
worldPosition = hitInfo.point + hitInfo.normal * desktopSurfaceOffset;
lastDesktopBrushWasHit = true;
}
else
{
worldPosition = transform.position + transform.forward * brushDistance;
lastDesktopBrushWasHit = false;
}
lastDesktopBrushWasHitValid = true;
worldPosition = SnapToVoxelCenter(worldPosition);
return true;
}
private bool HandleAvatarClearChord()
{
if (avatarEditorTargetGroup == null || !creatorMode)
{
avatarClearChordStartTime = -1f;
suppressAvatarClearUntilNeutral = false;
desktopAvatarClearStartTime = -1f;
return false;
}
if (!useXRInput)
{
if (suppressAvatarClearUntilNeutral)
{
if (!Input.GetKey(KeyCode.O))
{
suppressAvatarClearUntilNeutral = false;
}
return true;
}
if (!Input.GetKey(KeyCode.O))
{
desktopAvatarClearStartTime = -1f;
return false;
}
if (desktopAvatarClearStartTime < 0f)
{
desktopAvatarClearStartTime = Time.unscaledTime;
return true;
}
if (Time.unscaledTime - desktopAvatarClearStartTime >= 5f)
{
ClearAvatarEditorGroupUndoable();
suppressAvatarClearUntilNeutral = true;
desktopAvatarClearStartTime = -1f;
}
return true;
}
bool flag = ReadBool(leftHand, CommonUsages.primaryButton);
bool flag2 = ReadBool(leftHand, CommonUsages.secondaryButton);
bool flag3 = ReadBool(rightHand, CommonUsages.primaryButton);
bool flag4 = ReadBool(rightHand, CommonUsages.secondaryButton);
bool flag5 = flag && flag2 && flag3 && flag4;
if (suppressAvatarClearUntilNeutral)
{
if (!flag && !flag2 && !flag3 && !flag4)
{
suppressAvatarClearUntilNeutral = false;
}
return true;
}
if (!flag5)
{
avatarClearChordStartTime = -1f;
return false;
}
if (avatarClearChordStartTime < 0f)
{
avatarClearChordStartTime = Time.unscaledTime;
return true;
}
if (Time.unscaledTime - avatarClearChordStartTime >= 5f)
{
ClearAvatarEditorGroupUndoable();
suppressAvatarClearUntilNeutral = true;
avatarClearChordStartTime = -1f;
}
return true;
}
private void ClearAvatarEditorGroupUndoable()
{
if (avatarEditorTargetGroup == null)
{
return;
}
AvatarCustomizerController avatarCustomizerController = Object.FindObjectOfType<AvatarCustomizerController>();
if (avatarCustomizerController != null && avatarCustomizerController.TryGetEditorGroups(out var headBody, out var left, out var right))
{
ClearSingleAvatarEditorGroupUndoable(headBody);
ClearSingleAvatarEditorGroupUndoable(left);
ClearSingleAvatarEditorGroupUndoable(right);
AvatarVoxelPayload payload = AvatarVoxelStorage.CapturePayload(headBody, left, right);
AvatarVoxelStorage.SaveLocal(payload);
PhotonVoxelAvatar localOwnedInstance = PhotonVoxelAvatar.LocalOwnedInstance;
if (localOwnedInstance != null)
{
localOwnedInstance.ApplyAndBroadcastAvatar(payload);
}
}
else
{
ClearSingleAvatarEditorGroupUndoable(avatarEditorTargetGroup);
}
}
private void ClearSingleAvatarEditorGroupUndoable(VoxelGroup group)
{
if (!(group == null))
{
BeginAvatarEditUndoSession(group);
group.OverwriteData(Vector3Int.zero, 0, Vector3Int.zero, new byte[0], queueRebuild: false);
avatarEditUndoSessionChanged = true;
FinalizeAvatarEditorGroup(group);
}
}
private bool ShouldBreakContinuousEdit(Vector3 previous, Vector3 current, bool previousHadHit, bool currentHadHit)
{
if (previousHadHit != currentHadHit)
{
return true;
}
if (groupManager == null)
{
return false;
}
float num = Mathf.Max(groupManager.VoxelSize * 3f, brushRadius * 2f);
return Vector3.Distance(previous, current) > num;
}
private int GetDesktopRaycastMask()
{
return desktopRaycastMask.value & -5;
}
private bool TryGetPalettePose(out Vector3 worldPosition, out Quaternion worldRotation)
{
if (!useXRInput)
{
if (!TryGetDesktopViewCamera(out var viewCamera))
{
worldPosition = Vector3.zero;
worldRotation = Quaternion.identity;
return false;
}
Transform transform = viewCamera.transform;
worldPosition = transform.position + transform.forward * 0.55f + -transform.right * 0.22f + transform.up * 0.08f;
worldRotation = Quaternion.LookRotation(transform.forward, Vector3.up);
return true;
}
if (!TryGetControllerPose(leftHand, XRNode.LeftHand, leftHandAnchor, out var worldPosition2, out var worldRotation2))
{
worldPosition = Vector3.zero;
worldRotation = Quaternion.identity;
return false;
}
worldPosition = worldPosition2 + worldRotation2 * Vector3.up * 0.2f + worldRotation2 * Vector3.forward * 0.14f;
Transform transform2 = ((Camera.main != null) ? Camera.main.transform : trackingOrigin);
Vector3 vector = ((transform2 != null) ? (transform2.position - worldPosition) : (-(worldRotation2 * Vector3.forward)));
if (vector.sqrMagnitude < 0.0001f)
{
vector = Vector3.back;
}
worldRotation = Quaternion.LookRotation(vector.normalized, Vector3.up);
return true;
}
private bool TryGetControllerPose(InputDevice device, XRNode node, Transform anchor, out Vector3 worldPosition, out Quaternion worldRotation)
{
if (anchor != null)
{
worldPosition = anchor.position;
worldRotation = anchor.rotation;
return true;
}
if (!device.isValid)
{
device = InputDevices.GetDeviceAtXRNode(node);
}
if (device.isValid && device.TryGetFeatureValue(CommonUsages.devicePosition, out var value) && device.TryGetFeatureValue(CommonUsages.deviceRotation, out var value2))
{
if (trackingOrigin != null)
{
worldPosition = trackingOrigin.TransformPoint(value);
worldRotation = trackingOrigin.rotation * value2;
}
else
{
worldPosition = value;
worldRotation = value2;
}
return true;
}
worldPosition = Vector3.zero;
worldRotation = Quaternion.identity;
return false;
}
private bool TryGetDesktopViewCamera(out Camera viewCamera)
{
viewCamera = Camera.main;
if (viewCamera != null)
{
return true;
}
Transform transform = ((PhotonVRManager.Manager != null) ? PhotonVRManager.Manager.Head : null);
if (transform != null)
{
viewCamera = transform.GetComponent<Camera>();
}
return viewCamera != null;
}
private Vector3 SnapToVoxelCenter(Vector3 worldPoint)
{
float num = ((groupManager != null) ? groupManager.VoxelSize : 0.125f);
if (avatarEditorTargetGroup != null)
{
num *= 0.5f;
}
return new Vector3((Mathf.Round(worldPoint.x / num - 0.5f) + 0.5f) * num, (Mathf.Round(worldPoint.y / num - 0.5f) + 0.5f) * num, (Mathf.Round(worldPoint.z / num - 0.5f) + 0.5f) * num);
}
private bool DetectXRInputActive()
{
if (!InputDevices.GetDeviceAtXRNode(XRNode.Head).isValid && !InputDevices.GetDeviceAtXRNode(XRNode.LeftHand).isValid)
{
return InputDevices.GetDeviceAtXRNode(XRNode.RightHand).isValid;
}
return true;
}
private static int WrapPaletteIndex(int value, int length)
{
if (length <= 0)
{
return 0;
}
value %= length;
if (value >= 0)
{
return value;
}
return value + length;
}
private static bool ReadBool(InputDevice device, InputFeatureUsage<bool> usage)
{
bool value = default(bool);
return device.isValid && device.TryGetFeatureValue(usage, out value) && value;
}
private static float ReadFloat(InputDevice device, InputFeatureUsage<float> usage)
{
if (!device.isValid || !device.TryGetFeatureValue(usage, out var value))
{
return 0f;
}
return value;
}
private static Vector2 ReadVector2(InputDevice device, InputFeatureUsage<Vector2> usage)
{
if (!device.isValid || !device.TryGetFeatureValue(usage, out var value))
{
return Vector2.zero;
}
return value;
}
}
}