This commit is contained in:
Laurenth 2019-11-29 14:18:48 +01:00
Родитель 39c5a892c5
Коммит 056c3fc5ff
805 изменённых файлов: 26086 добавлений и 413 удалений

Просмотреть файл

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: cee0b306a665f174998de09b82121deb
folderAsset: yes
timeCreated: 1492708210
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:dbf0f4f237a0b5e7cbd0b84acd1f5fa3372df2d05308997444d82413f08851fd
size 7147

Просмотреть файл

@ -0,0 +1,103 @@
fileFormatVersion: 2
guid: 8ef34d7d3b3b45b4d923405b38d36f35
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 10
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: -1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 1
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 1
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,70 @@
using UnityEngine;
using UnityEditor;
namespace LightingTools.LightProbesVolumes
{
[CustomEditor(typeof(LightProbesVolumeSettings))]
public class LightProbesVolumeEditor : Editor
{
SerializedProperty horizontalSpacing;
SerializedProperty verticalSpacing;
SerializedProperty offsetFromFloor;
SerializedProperty numberOfLayers;
SerializedProperty fillVolume;
SerializedProperty followFloor;
SerializedProperty discardInsideGeometry;
SerializedProperty drawDebug;
void OnEnable()
{
horizontalSpacing = serializedObject.FindProperty("horizontalSpacing");
verticalSpacing = serializedObject.FindProperty("verticalSpacing");
offsetFromFloor = serializedObject.FindProperty("offsetFromFloor");
numberOfLayers = serializedObject.FindProperty("numberOfLayers");
fillVolume = serializedObject.FindProperty("fillVolume");
followFloor = serializedObject.FindProperty("followFloor");
discardInsideGeometry = serializedObject.FindProperty("discardInsideGeometry");
drawDebug = serializedObject.FindProperty("drawDebug");
}
public override void OnInspectorGUI()
{
var volume = (LightProbesVolumeSettings)target;
serializedObject.Update();
EditorGUILayout.DelayedFloatField(horizontalSpacing);
EditorGUILayout.DelayedFloatField(verticalSpacing);
EditorGUILayout.PropertyField(offsetFromFloor);
EditorGUILayout.PropertyField(fillVolume);
serializedObject.ApplyModifiedProperties();
EditorGUI.BeginDisabledGroup(fillVolume.boolValue);
EditorGUILayout.PropertyField(numberOfLayers);
EditorGUI.EndDisabledGroup();
EditorGUILayout.PropertyField(followFloor);
EditorGUILayout.PropertyField(discardInsideGeometry);
EditorGUILayout.PropertyField(drawDebug);
if (GUILayout.Button("Create Light Probes in Selected Volume"))
{
volume.Populate();
}
serializedObject.ApplyModifiedProperties();
}
[MenuItem("GameObject/Light/Lightprobes Volume", false, 10)]
static void CreateCustomGameObject(MenuCommand menuCommand)
{
// Create a custom game object
GameObject volume = new GameObject("LightprobeVolume");
// Ensure it gets reparented if this was a context click (otherwise does nothing)
GameObjectUtility.SetParentAndAlign(volume, menuCommand.context as GameObject);
// Register the creation in the undo system
Undo.RegisterCreatedObjectUndo(volume, "Create " + volume.name);
Selection.activeObject = volume;
volume.AddComponent<LightProbesVolumeSettings>();
volume.GetComponent<BoxCollider>().size = new Vector3(5, 2, 5);
volume.GetComponent<BoxCollider>().isTrigger = true;
}
}
}

Просмотреть файл

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: f046a008730fb8f40aca66fe59632d95
timeCreated: 1490885515
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,16 @@
{
"name": "LightingTools.LightProbesVolumes.Editor",
"references": [
"LightingTools.LightProbesVolumes"
],
"optionalUnityReferences": [],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": []
}

Просмотреть файл

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 087ff6b4289583947b41b0c03d628d1f
timeCreated: 1546438390
licenseType: Pro
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,18 @@
using UnityEngine;
using UnityEditor;
namespace LightingTools.LightProbesVolumes
{
public class RefreshLightProbesVolumes
{
[MenuItem("Lighting/Refresh lightprobes volumes")]
static void Refresh()
{
var volumes = GameObject.FindObjectsOfType<LightProbesVolumeSettings>();
foreach (var volume in volumes)
{
volume.Populate();
}
}
}
}

Просмотреть файл

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 69d120c0b1360954680fd20bf7e055e2
timeCreated: 1490885515
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,40 @@
# LightingTools.LightProbesVolumes
Light probes volumes
Requires Unity 2018.1 or above.
# Setup instructions :
- In your project folder create a "LocalPackages" folder next to your "Assets" folder
- In the LocalPackages folder extract this repo under a "LightingTools.LightProbesVolumes" folder
- In the "Packages" folder open the "manifest.json" in a text editing software
- in "manifest.json" under "dependencies" add the line :
"li.lightingtools.core": "file:../LocalPackages/LightingTools.LightProbesVolumes" (you need to add a "," if this is not the last dependency)
- open the project and profit !
# How to use it :
- In the hierarchy view click : Create / Light / Lightprobe Volume
- Set the size of the box collider to the size of the area you want to place lightprobes in ( if you have a ceiling it is recommended to set the vertical bounds lower to the ceiling, or it will spawn probes on top of it).
- Set the " Light probe volume settings" :
- vertical and horizontal spacing ( one probe every X meters )
- offset from floor is at which vertical distance from the collision you want to spawn the first layer of probes
- number of layers is the number of probes that will be placed vertically above the hit collider
- follow floor : when enabled the script performs raycast in order to place lightprobes above existing static geometry that has a collider. When disabled the lightprobes are just placed above the lower face of the volume.
- fill volume enabled will fill the whole height of the volume instead of just doing X number of layer. When this is enabled the number of layers is ignored.
- discard inside geometry will test if your probe is inside an object with collisions. This will only work if the top face of your volume is not itself inside an object with collisions. In order to check this enable "draw Debug" and fill the volume : the green cross at the top has to be located in the air and not inside a geometry.
- Click the button !
- When you have several volumes setup in your scene and you want to refresh them all :
- Go to lighting / Refresh lightprobes volumes. This will place again the probes in all the volumes in the scene.
# Improvements I would like to do :
- Replace the raycast to colliders by raycast to meshrenderers
# Troubleshoot :
- if the script doesn't place any lightprobe, make sure your geometric is marked as static, and that it has a collider. Using colliders isn't ideal but I haven't found a good solution that would work without them.
# Contributions :
This was originally based on the script shared by ghostmantis games : http://ghostmantis.com/?p=332

Просмотреть файл

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 0e68ecda44ce2814bb8206e78e262818
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 814405171c7b05741a1b7aa8a09674eb
folderAsset: yes
timeCreated: 1546438065
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,194 @@
using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace LightingTools.LightProbesVolumes
{
public static class LightProbesPlacement
{
#if UNITY_EDITOR
public static void Populate (GameObject gameObject, float horizontalSpacing, float verticalSpacing, float offsetFromFloor, int numberOfLayers, bool drawDebug, bool fillVolume, bool discardInsideGeometry, bool followFloor)
{
BoxCollider boxCollider = gameObject.GetComponent<BoxCollider>();
if (boxCollider == null)
{
Debug.LogWarning("Box collider not found on " + gameObject.name);
return;
}
//Make sure collider is a trigger
boxCollider.isTrigger = true;
//avoid division by 0
horizontalSpacing = Mathf.Max(horizontalSpacing, 0.01f);
verticalSpacing = Mathf.Max(verticalSpacing, 0.01f);
//Check if there is already a lightprobegroup component
// if there is destroy it
LightProbeGroup oldLightprobes = gameObject.GetComponent<LightProbeGroup>();
//Calculate Start Points at the top of the collider
Vector3[] startPositions = StartPoints(boxCollider.size, boxCollider.center, boxCollider.transform, horizontalSpacing);
float minY = boxCollider.bounds.min.y;
float maxY = boxCollider.bounds.max.y;
float sizeY = boxCollider.size.y;
int ycount = Mathf.FloorToInt((sizeY-offsetFromFloor) / verticalSpacing) + 1;
List<Vector3> VertPositions = new List<Vector3>();
int currentTrace = 0;
//if followFloor we raycast from top to down in order to follow the static geometry (with colliders)
if(followFloor)
{
foreach (Vector3 startPos in startPositions)
{
//RaycastHit hit;
RaycastHit[] hits;
Ray ray = new Ray();
ray.origin = startPos;
ray.direction = -Vector3.up;
hits = Physics.RaycastAll(ray, sizeY + 1, -1, QueryTriggerInteraction.Ignore);
//Validate hits
foreach (var hit in hits)
{
if (!hit.collider.gameObject.isStatic)
break;
if (hit.point.y + offsetFromFloor < maxY && hit.point.y + offsetFromFloor > minY)
VertPositions.Add(hit.point + new Vector3(0, offsetFromFloor, 0));
int maxLayer = fillVolume ? ycount : numberOfLayers;
for (int i = 1; i < maxLayer; i++)
{
if (hit.point.y + offsetFromFloor + i * verticalSpacing < maxY && hit.point.y + offsetFromFloor + verticalSpacing > minY)
VertPositions.Add(hit.point + new Vector3(0, offsetFromFloor + i * verticalSpacing, 0));
}
}
EditorUtility.DisplayProgressBar("Tracing floor collisions", currentTrace.ToString() + "/" + startPositions.Length.ToString(), (float)currentTrace / (float)startPositions.Length);
currentTrace++;
}
EditorUtility.ClearProgressBar();
}
else
{
int maxLayer = fillVolume ? ycount : numberOfLayers;
for (int i = 0; i< maxLayer; i++)
{
foreach(Vector3 position in startPositions)
{
VertPositions.Add(position + Vector3.up * verticalSpacing * i - Vector3.up*sizeY + Vector3.up * offsetFromFloor);
}
}
}
if(drawDebug)
{
foreach(Vector3 position in VertPositions)
{
Debug.DrawLine(position, position + Vector3.up * 0.5f,Color.red,3);
}
}
List<Vector3> validVertPositions = new List<Vector3>();
//Inside Geometry test : take an arbitrary position in space and trace from that position to the probe position and back from the probe position to the arbitrary position. If the number of hits is different for both raycasts the probe is considered to be inside an object.
//When using Draw Debug the arbitrary position is the Green cross in the air.
if (discardInsideGeometry)
{
int j = 0;
Vector3 insideTestPosition = gameObject.transform.position + gameObject.GetComponent<BoxCollider>().center + new Vector3(0, maxY / 2, 0);
if (drawDebug)
{
Debug.DrawLine(insideTestPosition + Vector3.up, insideTestPosition - Vector3.up, Color.green, 5);
Debug.DrawLine(insideTestPosition + Vector3.right, insideTestPosition - Vector3.right, Color.green, 5);
Debug.DrawLine(insideTestPosition + Vector3.forward, insideTestPosition - Vector3.forward, Color.green, 5);
}
foreach (Vector3 positionCandidate in VertPositions)
{
EditorUtility.DisplayProgressBar("Checking probes inside geometry", j.ToString() + "/" + VertPositions.Count, (float)j / (float)VertPositions.Count);
Ray forwardRay = new Ray(insideTestPosition, Vector3.Normalize(positionCandidate - insideTestPosition));
Ray backwardRay = new Ray(positionCandidate, Vector3.Normalize(insideTestPosition - positionCandidate));
RaycastHit[] hitsForward;
RaycastHit[] hitsBackward;
hitsForward = Physics.RaycastAll(forwardRay, Vector3.Distance(positionCandidate, insideTestPosition), -1, QueryTriggerInteraction.Ignore);
hitsBackward = Physics.RaycastAll(backwardRay, Vector3.Distance(positionCandidate, insideTestPosition), -1, QueryTriggerInteraction.Ignore);
if (hitsForward.Length == hitsBackward.Length) validVertPositions.Add(positionCandidate);
else if (drawDebug)
Debug.DrawRay(backwardRay.origin, backwardRay.direction * Vector3.Distance(positionCandidate, insideTestPosition), Color.cyan, 5);
j++;
}
EditorUtility.ClearProgressBar();
}
else
validVertPositions = VertPositions;
// Check if we have any hits
if (validVertPositions.Count < 1)
{
Debug.Log("no valid hit for " + gameObject.name);
return;
}
LightProbeGroup LPGroup = oldLightprobes != null ? oldLightprobes : gameObject.AddComponent<LightProbeGroup>();
// Feed lightprobe positions
Vector3[] ProbePos = new Vector3[validVertPositions.Count];
for (int i = 0; i < validVertPositions.Count; i++)
{
ProbePos[i] = gameObject.transform.InverseTransformPoint(validVertPositions[i]);
}
LPGroup.probePositions = ProbePos;
//Finish
Debug.Log("Finished placing " + ProbePos.Length + " probes for " + gameObject.name);
}
static Vector3[] StartPoints(Vector3 size, Vector3 offset, Transform transform, float horizontalSpacing)
{
// Calculate count and start offset
int xCount = Mathf.FloorToInt(size.x / horizontalSpacing) + 1;
int zCount = Mathf.FloorToInt(size.z / horizontalSpacing) + 1;
float startxoffset = (size.x - (xCount-1) * horizontalSpacing)/2;
float startzoffset = (size.z - (zCount-1) * horizontalSpacing)/2;
//if lightprobe count fits exactly in bounds, I know the probes at the maximum bounds will be rejected, so add offset
if (startxoffset == 0)
startxoffset = horizontalSpacing / 2;
if (startzoffset == 0)
startzoffset = horizontalSpacing / 2;
Vector3[] vertPositions = new Vector3[ xCount * zCount ];
int vertexnumber = 0;
for (int i = 0; i < xCount; i++)
{
for (int j = 0; j < zCount; j++ )
{
Vector3 position = new Vector3
{
y = size.y / 2,
x = startxoffset + (i * horizontalSpacing) - (size.x / 2),
z = startzoffset + (j * horizontalSpacing) - (size.z / 2)
};
vertPositions[vertexnumber] = transform.TransformPoint(position + offset);
vertexnumber++;
}
}
return vertPositions;
}
#endif
}
}

Просмотреть файл

@ -1,6 +1,6 @@
fileFormatVersion: 2
guid: 3bfe7209b5cff4f49b13217ed25f16dd
timeCreated: 1504691534
guid: 82da266145fa8e8449852cf58020c13d
timeCreated: 1546423551
licenseType: Pro
MonoImporter:
externalObjects: {}

Просмотреть файл

@ -0,0 +1,31 @@
using UnityEngine;
namespace LightingTools.LightProbesVolumes
{
[ExecuteInEditMode]
[RequireComponent(typeof(BoxCollider))]
public class LightProbesVolumeSettings : MonoBehaviour
{
public float horizontalSpacing = 2.0f;
public float verticalSpacing = 2.0f;
public float offsetFromFloor = 0.5f;
public int numberOfLayers = 2;
public bool fillVolume = false;
public bool followFloor = true;
public bool discardInsideGeometry;
public bool drawDebug = false;
private void OnEnable()
{
var boxCollider = GetComponent<BoxCollider>();
boxCollider.isTrigger = true;
}
#if UNITY_EDITOR
public void Populate()
{
LightProbesPlacement.Populate(gameObject,horizontalSpacing,verticalSpacing,offsetFromFloor,numberOfLayers,drawDebug,fillVolume,discardInsideGeometry, followFloor);
}
#endif
}
}

Просмотреть файл

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: fc7eebf330e67854398f83add3b50749
timeCreated: 1490885515
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 8ef34d7d3b3b45b4d923405b38d36f35, type: 3}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,8 @@
{
"name": "LightingTools.LightProbesVolumes",
"references": [],
"optionalUnityReferences": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false
}

Просмотреть файл

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 636c3e62138bf8548a29334166578537
timeCreated: 1546438430
licenseType: Pro
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,7 @@
{
"name": "li.lightingtools.lightprobesvolumes",
"displayName": "Light Probes Volumes",
"version": "0.0.1",
"unity": "2018.3",
"description": "Lighting tools test."
}

Просмотреть файл

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 1d6b995f4d143ea40a626591e25d164e
timeCreated: 1546438320
licenseType: Pro
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,11 @@
# Changelog
All notable changes to this package will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## [0.1.0] - 2017-MM-DD
### This is the first release of *Unity Package \<Your package name\>*.
*Short description of this release*

Просмотреть файл

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 73d00c311b68c0b43b290792f9229142
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,9 @@
# Contributing
## If you are interested in contributing, here are some ground rules:
* ... Define guidelines & rules for what contributors need to know to successfully make Pull requests against your repo ...
## All contributions are subject to the [Unity Contribution Agreement(UCA)](https://unity3d.com/legal/licenses/Unity_Contribution_Agreement)
By making a pull request, you are confirming agreement to the terms and conditions of the UCA, including that your Contributions are your original creation and that you have complete right and authority to make your Contributions.
## Once you have a change ready following these ground rules. Simply make a pull request

Просмотреть файл

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 12e422220e727d14aba019c24b31c69c
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: b1ebd9449aa245a42b8cf1842f144df3
folderAsset: yes
timeCreated: 1479375522
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,126 @@
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEditor;
using UnityEditor.SceneManagement;
using System.Collections;
using Unity.EditorCoroutines.Editor;
[CustomEditor(typeof(LevelLightmapData))]
public class LevelLightmapDataEditor : Editor
{
public SerializedProperty lightingScenariosScenes;
public SerializedProperty lightingScenesNames;
public SerializedProperty allowLoadingLightingScenes;
GUIContent allowLoading = new GUIContent("Allow loading Lighting Scenes", "Allow the Level Lightmap Data script to load a lighting scene additively at runtime if the lighting scenario contains realtime lights.");
public void OnEnable()
{
lightingScenariosScenes = serializedObject.FindProperty("lightingScenariosScenes");
lightingScenesNames = serializedObject.FindProperty("lightingScenesNames");
allowLoadingLightingScenes = serializedObject.FindProperty("allowLoadingLightingScenes");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
LevelLightmapData lightmapData = (LevelLightmapData)target;
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(lightingScenariosScenes, new GUIContent("Lighting Scenarios Scenes"), includeChildren:true);
if (EditorGUI.EndChangeCheck())
{
serializedObject.ApplyModifiedProperties();
lightingScenesNames.arraySize = lightingScenariosScenes.arraySize;
for (int i=0; i<lightingScenariosScenes.arraySize; i++)
{
lightingScenesNames.GetArrayElementAtIndex(i).stringValue = lightingScenariosScenes.GetArrayElementAtIndex(i).objectReferenceValue == null ? "" : lightingScenariosScenes.GetArrayElementAtIndex(i).objectReferenceValue.name;
}
serializedObject.ApplyModifiedProperties();
}
EditorGUILayout.PropertyField(allowLoadingLightingScenes, allowLoading);
serializedObject.ApplyModifiedProperties();
EditorGUILayout.Space();
for (int i = 0; i < lightmapData.lightingScenariosScenes.Count; i++)
{
EditorGUILayout.BeginHorizontal();
if ( lightmapData.lightingScenariosScenes[i] != null )
{
EditorGUILayout.LabelField(lightmapData.lightingScenariosScenes[i].name.ToString(), EditorStyles.boldLabel);
if (GUILayout.Button("Build "))
{
if(UnityEditor.Lightmapping.giWorkflowMode != UnityEditor.Lightmapping.GIWorkflowMode.OnDemand)
{
Debug.LogError("ExtractLightmapData requires that you have baked you lightmaps and Auto mode is disabled.");
}
else
BuildLightingScenario(i, lightmapData);
}
if (GUILayout.Button("Store "))
{
lightmapData.StoreLightmapInfos(i);
}
}
EditorGUILayout.EndHorizontal();
}
}
public void BuildLightingScenario(int ScenarioID, LevelLightmapData levelLightmapData)
{
//Remove reference to LightingDataAsset so that Unity doesn't delete the previous bake
Lightmapping.lightingDataAsset = null;
string currentBuildScenename = lightingScenariosScenes.GetArrayElementAtIndex(ScenarioID).objectReferenceValue.name;
Debug.Log("Loading " + currentBuildScenename);
string lightingSceneGUID = AssetDatabase.FindAssets(currentBuildScenename)[0];
string lightingScenePath = AssetDatabase.GUIDToAssetPath(lightingSceneGUID);
if (!lightingScenePath.EndsWith(".unity"))
lightingScenePath = lightingScenePath + ".unity";
EditorSceneManager.OpenScene(lightingScenePath, OpenSceneMode.Additive);
Scene lightingScene = SceneManager.GetSceneByName(currentBuildScenename);
EditorSceneManager.SetActiveScene(lightingScene);
SearchLightsNeededRealtime(levelLightmapData);
Debug.Log("Start baking");
EditorCoroutineUtility.StartCoroutine(BuildLightingAsync(lightingScene), this);
}
private IEnumerator BuildLightingAsync(Scene lightingScene)
{
var newLightmapMode = new LightmapsMode();
newLightmapMode = LightmapSettings.lightmapsMode;
Lightmapping.BakeAsync();
while (Lightmapping.isRunning) { yield return null; }
//Lightmapping.lightingDataAsset = null;
EditorSceneManager.SaveScene(lightingScene);
EditorSceneManager.CloseScene(lightingScene, true);
LightmapSettings.lightmapsMode = newLightmapMode;
}
public void SearchLightsNeededRealtime(LevelLightmapData levelLightmapData)
{
bool latestBuildHasRealtimeLights = false;
var lights = FindObjectsOfType<Light>();
var reflectionProbes = FindObjectsOfType<ReflectionProbe>();
foreach (Light light in lights)
{
if (light.lightmapBakeType == LightmapBakeType.Mixed || light.lightmapBakeType == LightmapBakeType.Realtime)
latestBuildHasRealtimeLights = true;
}
if (reflectionProbes.Length > 0)
latestBuildHasRealtimeLights = true;
levelLightmapData.latestBuildHasReltimeLights = latestBuildHasRealtimeLights;
}
}

Просмотреть файл

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 0f3a223fa901e8b4e96df48bf5dd78ad
timeCreated: 1479375604
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,18 @@
{
"name": "LightingTools.LightmapSwitcher.Editor",
"references": [
"LightingTools.LightmapSwitcher",
"Unity.EditorCoroutines.Editor"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

Просмотреть файл

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 73cd762c1d4bdaf4891d2710c1f58ae2
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1656bfbc25c2cc43d6a2cc683fd240120c03b5f06803dbe91c28c8e48e02b67b
size 3715

Просмотреть файл

@ -0,0 +1,103 @@
fileFormatVersion: 2
guid: 4021dabdeeef1824b871b34d975991b8
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 10
mipmaps:
mipMapMode: 1
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 0
aniso: 1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: -1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 0
alphaUsage: 0
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 1
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 1
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,5 @@
[MyPackageName] copyright © [YEAR] Unity Technologies ApS
Licensed under the Unity Companion License for Unity-dependent projects--see [Unity Companion License](http://www.unity3d.com/legal/licenses/Unity_Companion_License).
Unless expressly provided otherwise, the Software under this license is made available strictly on an “AS IS” BASIS WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. Please review the license for details on these and other terms and conditions.

Просмотреть файл

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: e85d55989cd833f4ea31cdc5fb0189d3
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,514 @@
# UPM Package Starter Kit
The purpose of this package starter kit is to provide the data structure and development guidelines for new packages meant for the **Unity Package Manager (UPM)**.
This is the first of many steps towards an automated package publishing experience within Unity. This package starter kit is merely a fraction of the creation, edition, validation, and publishing tools that we will end up with.
We hope you enjoy your experience. You can use **#devs-packman** on Slack to provide feedback or ask questions regarding your package development efforts.
## Are you ready to become a package?
The Package Manager is a work-in-progress for Unity and, in that sense, there are a few criteria that must be met for your package to be considered on the package list at this time:
- **Your code accesses public Unity C# APIs only.** If you have a native code component, it will need to ship with an official editor release. Internal API access might eventually be possible for Unity made packages, but not at this time.
- **Your code doesn't require security, obfuscation, or conditional access control.** Anyone should be able to download your package and access the source code.
## Package structure
```none
<root>
├── package.json
├── README.md
├── CHANGELOG.md
├── LICENSE.md
├── Third Party Notices.md
├── QAReport.md
├── Editor
│ ├── Unity.[YourPackageName].Editor.asmdef
│ └── EditorExample.cs
├── Runtime
│ ├── Unity.[YourPackageName].asmdef
│ └── RuntimeExample.cs
├── Tests
│ ├── .tests.json
│ ├── Editor
│ │ ├── Unity.[YourPackageName].Editor.Tests.asmdef
│ │ └── EditorExampleTest.cs
│ └── Runtime
│ ├── Unity.[YourPackageName].Tests.asmdef
│ └── RuntimeExampleTest.cs
├── Samples
│ └── Example
│ ├── .sample.json
│ └── SampleExample.cs
└── Documentation~
├── your-package-name.md
└── Images
```
## Develop your package
Package development works best within the Unity Editor. Here's how to set that up:
1. Clone the Package Starter Kit repository locally.
- In a console (or terminal) application, choose a place to clone the repository and enter the following:
```
git clone git@github.cds.internal.unity3d.com:unity/com.unity.package-starter-kit.git
```
1. Create a new repository for your package and clone to your desktop.
- On Github.cds create a new repository with the name of your package (Example: `"com.unity.terrain-builder"`).
- In a console (or terminal) application, choose a place to clone the repository and perform the following:
```
git clone git@github.cds.internal.unity3d.com:unity/com.unity.[your-package-name]
```
1. Copy the contents of the Package Starter Kit folder to your new package. Be careful not to copy the Package Starter Kit *.git* folder over.
1. **Fill in your package information.**
Follow the instructions for [filling out your package manifest](#fill-out-your-package-manifest) (*package.json*).
Then update the `"createSeparatePackage"` field in the *Tests/.tests.json* file to set up testing for Continuous Integration (CI):
* Set it to false if you want the tests to remain part of the published package. This is the default value.
* Set it to true if you want the CI to create a separate package for these tests, and add the metadata at publish time to link the packages together. This allows you to have a large number of tests, or assets, etc. that you don't want to include in your main package, while making it easy to test your package with those tests & fixtures.
1. Start **Unity**, create a local empty project and import your package into the project.
1. In a console (or terminal) application, push the package starter kit files you copied in your new package repository to its remote.
- Add them to your repository's list to version
```git add .```
- Commit to your new package's remote master
```git commit```
- Push to your new package's remote master
```git push```
1. Restart **Unity**. This forces the Package Manager to rescan your project so that it can find the new package that you just embedded. For more information on embedded packages see [Confluence](https://confluence.hq.unity3d.com/display/PAK/How+to+embed+a+package+in+your+project).
1. **Update the *README.md* file.**
It should contain all pertinent information for developers using your package, such as:
* Prerequistes
* External tools or development libraries
* Required installed Software
* Command line examples to build, test, and run your package.
1. **Rename and update your documentation file(s).**
Use the samples included in this starter kit to create preliminary, high-level documentation. Your documentation should introduce users to the features and sample files included in your package. For more information, see [Document your package](#document-your-package).
1. **Rename and update assembly definition files.**
Choose a name schema to ensure that the name of the assembly built from the assembly definition file (_.asmdef_) will follow the .Net [Framework Design Guidelines](https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/index). For more information, see [Name your assembly definition files](#name-your-assembly-definition-files).
1. **Add samples to your package (code & assets).**
The Package Manager recognizes the *Samples* directory in a package but does not import samples into Unity when the package is added to a project by default. Users can import samples into their */Assets* directory by clicking the **Import in project** button from the [Details view](https://docs.unity3d.com/Manual/upm-ui-details.html) of your package in the Package Manager window.
If your package contains a sample:
* Rename the *Samples/Example* folder, and update the *.sample.json* file in it.
* If your package contains multiple samples, make a copy of the *Samples/Example* folder for each sample, and update each *.sample.json* file accordingly.
Delete the *Samples* folder altogether if your package does not need samples.
1. **Validate your package using the Validation Suite.**
Before you publish your package, you need to make sure that it passes all the necessary validation checks by using the [Package Validation Suite](https://github.cds.internal.unity3d.com/unity/com.unity.package-validation-suite) extension. This is *required*.
For more information, see [Validate your package](#validate-your-package).
1. **Follow our design guidelines**
Follow these design guidelines when creating your package:
* The [package design standards](https://confluence.hq.unity3d.com/display/UX/Packages) on Confluence.
* The [design checklist](https://unitytech.github.io/unityeditor-hig/topics/checklist.html) from Unity's Human Interface Guidelines.
* The namespace for code in the asmdef *must* match the asmdef name, except the initial `Unity`, which should be replaced with `UnityEngine` or `UnityEditor`.
* For **Runtime code**, only use the `Unity` namespace for code that has no dependency on anything in `UnityEngine` or `UnityEditor` and instead uses `ECS` and other `Unity`-namespace systems.
1. **Add tests to your package.**
For **Editor tests**:
* Write all your Editor Tests in *Tests/Editor*
* If your tests require access to internal methods, add an *AssemblyInfo.cs* file to your Editor code and use `[assembly: InternalsVisibleTo("Unity.[YourPackageName].Editor.Tests")]`.
For **Playmode Tests**:
* Write all your Playmode Tests in *Tests/Runtime*.
* If your tests require access to internal methods, add an *AssemblyInfo.cs* file to your Runtime code and use `[assembly: InternalsVisibleTo("Unity.[YourPackageName].Tests")]`.
1. **Setup your package CI.**
Make sure your package continues to work against trunk or any other branch by setting up automated testing on every commit. See the [Confluence page](https://confluence.hq.unity3d.com/display/PAK/Setting+up+your+package+CI) that explains how to set up your package CI.
This starter kit contains the minimum recommended workflow for package CI, which provides the barebones to: `pack`, `test` and `publish` your packages. It also contains the required configuration to `promote` your **preview** packages to production.
1. **Update *CHANGELOG.md*.**
Every new feature or bug fix should have a trace in this file. For more details on the chosen changelog format, see [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
### Fill out your package manifest
1. Update the following required fields in file *package.json* (see [Confluence](https://confluence.hq.unity3d.com/pages/viewpage.action?pageId=39065257) for more information):
| **Attribute name** | **Description** |
|:---|:---|
| `"name"` | Set the package name, following this naming convention: `"com.unity.[your-package-name]"`, without capital letters. For example, `"com.unity.2d.animation"`. |
| `"displayName"` | Set the package's user-friendly display name. For example, `"Terrain Builder SDK"`. <br><br>__Note:__ Use a display name that will help users understand what your package is intended for. |
| `"version"` | Set the package version in `"X.Y.Z"` format, following these [Semantic Versioning](http://semver.org/spec/v2.0.0.html) guidelines:<br>- To introduce a breaking API change, increment the major version (**X**.Y.Z).<br>- To introduce a new feature, increment the minor version (X.**Y**.Z).<br>- To introduce a bug fix, increment the patch version (X.Y.**Z**) |
| `"unity"` | Set the Unity version your package is compatible with. For example: `"2018.1"`. |
| `"unityRelease"` | Specify the Unity patch release your package is compatible with. For example: `"0a8"`.<br/><br/>__Note:__ This field is only required when the specific Unity version has a patch release. |
| `"description"` | This description appears in the Package Manager window when the user selects this package from the list. For best results, use this text to summarize what the package does and how it can benefit the user.<br><br>Special formatting characters are supported, including line breaks (`\n`) and unicode characters such as bullets (`\u25AA`). For more information, see the [Writing Package docs](https://confluence.hq.unity3d.com/display/DOCS/Writing+Package+docs) page on Confluence. |
1. Update the following recommended fields in file **package.json**:
| **Attribute name** | **Description** |
|:---|:---|
| `"dependencies"` | List of packages this package depends on. All dependencies will also be downloaded and loaded in a project with your package. Here's an example:<br/><br/>`dependencies: {`<br/>&nbsp;&nbsp;&nbsp;&nbsp;`"com.unity.ads": "1.0.0",`<br/>&nbsp;&nbsp;&nbsp;&nbsp;`"com.unity.analytics": "2.0.0"`<br/>`}` |
| `"keywords"` | An array of keywords related to the package. This field is currently purely informational. |
| `"type"` | The type of your package. This is used to determine the visibility of your package in the Project Browser and the visibility of its Assets in the Object Picker. The `"tool"` and `"library"` types are used to set your package and its Assets as hidden by default. If not present or set to another value, your package and its Assets are visible by default. |
| `"hideInEditor"` | A boolean value that overrides the package visibility set by the package type. If set to `false`, the default value, your package and its Assets are **always** visible by default; if set to `true`, your package and its Assets are **always** hidden by default. |
**Notes**:
- For packages in development, neither `"type"` nor `"hideInEditor"` are used. The package is **always** visible in the Project Browser and its Assets are **always** visible in the Object Picker.
- The user is **always** able to toggle the package visibility in the Project Browser, as well as their Assets visibility in the Object Picker.
### Document your package
You need to document your public APIs and provide task-oriented documentation for your features:
1. Document all of [your public APIs](#document-your-public-apis) and [your features](#document-your-features).
2. [Test your documentation locally](#test-your-documentation-locally).
3. [Get your documentation published](#get-your-documentation-published).
Your package should include the documentation source in your package, but not the generated HTML.
The page in the user manual that links to package documentation is [Packages documentation](http://docs.hq.unity3d.com/Documentation/Manual/PackagesList.html).
#### Document your public APIs
API documentation is generated from any [XmlDoc tagged comments](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/xmldoc/xml-documentation-comments) found in the *.cs* files included in the package.
You can use Visual Studio to autogenerate the correct tags by entering the documentation comments (`///`) in the empty line above your code. Visual Studio automatically detects which tags your code needs and inserts them. For example, if you write a method with two parameters that returns a value, Visual Studio gives you the **summary** tag (for the method description), two **param** tags, and one **returns** tag:
```c#
/// <summary>
///
/// </summary>
/// <param name="One"></param>
/// <param name="Two"></param>
/// <returns></returns>
public bool TestingXmlDoc(int One, int Two)
{
}
```
See the [Editor/EditorExample.cs](Editor/EditorExample.cs) file in this package for examples of how to document classes, methods, properties, and enums.
You need to document all public APIs. If you don't need an API to be accessed by clients, mark it as internal instead:
1. Add a custom *filter.yml* file to the package *Documentation~* folder.
2. Add these rules to your custom *filter.yml* file. These rules make the DocFX configuration consistent with packages that don't have a custom filter:
```yaml
apiRules:
- exclude:
# inherited Object methods
uidRegex: ^System\.Object\..*$
type: Method
- exclude:
# mentioning types from System.* namespace
uidRegex: ^System\..*$
type: Type
- exclude:
hasAttribute:
uid: System.ObsoleteAttribute
type: Member
- exclude:
hasAttribute:
uid: System.ObsoleteAttribute
type: Type
```
3. Specify classes to exclude by UID or by specifying regular expressions. For information about the rules for the filters, see the [DocFX guide](https://dotnet.github.io/docfx/tutorial/howto_filter_out_unwanted_apis_attributes.html).
#### Document your features
Write the Manual documentation using [GitHub-flavored Markdown](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) in *.md* files stored under the *Documentation~* folder. The *Documentation~* folder is suffixed with `~` to prevent its contents from being loaded in the Editor (recommended). Alternatively, you could use *.Documentation* for the folder name.
This preliminary, high-level documentation should introduce users to the features and sample files included in your package.
All packages that expose UI in editor or runtime features should use one of the appropriate documentation example guides under the *Documentation~* folder:
* [tools-package-guide.md](Documentation~/tools-package-guide.md) for a package that includes features that augment the Unity Editor or Runtime (modules, tools, and libraries)
* [sample-package-guide.md](Documentation~/sample-package-guide.md) for a package that includes sample files
* [test-package-guide.md](Documentation~/test-package-guide.md) for a package that provides tests
For instructions, see the [documentation guidelines](Documentation~/index.md).
#### Test your documentation locally
As you are developing your documentation, you can see what your documentation will look like by using the DocTools package: **com.unity.package-manager-doctools** (optional).
Once the DocTools package is installed, it displays a **Generate Documentation** button in the Package Manager window's Details view for any installed or embedded packages. To install the extension, see [Installing the DocTools package](https://confluence.hq.unity3d.com/display/DOCS/Package+documentation+with+Git#PackagedocumentationwithGit-InstallingDocTools) on Confluence.
The DocTools extension is still in preview, if you come across arguable results, please discuss them on **#docs-packman**.
#### Get your documentation published
When the documentation is complete, notify the technical writer assigned to your team or project. If you don't know which technical writer is assigned, fill out the [Package Docs Questions](https://docs.google.com/document/d/1vI0zbNX9OausEwYhg_kl9CIDNf4taExjON0fyp2cHS0) form, [log a JIRA DOC ticket](https://unity3d.atlassian.net/secure/CreateIssue!default.jspa?selectedProjectId=12200&issuetype=3) and attach the form to that ticket.
You can also ask for help or clarification on **#devs-documentation**.
> **Note:** The package will remain in **preview** mode until the final documentation is completed. Users will have access to the developer-generated documentation only in preview packages.
After the technical writer reviews the documentation, they will create a pull request in the package git repository. The package's development team will then need to submit a new package version with the updated docs.
### Name your assembly definition files
If your package contains Editor code, rename and modify [Editor/Unity.YourPackageName.Editor.asmdef](Editor/Unity.YourPackageName.Editor.asmdef). Otherwise, delete the *Editor* directory.
* Name **must** match your package name, suffixed by `.Editor` (for example, `Unity.[YourPackageName].Editor`).
* Assembly **must** reference `Unity.[YourPackageName]` (if you have any runtime code).
* Platforms **must** include `"Editor"`.
If your package contains code that needs to be included in Unity runtime builds, rename and modify [Runtime/Unity.YourPackageName.asmdef](Runtime/Unity.YourPackageName.asmdef). Otherwise, delete the *Runtime* directory.
* Name **must** match your package name (for example,`Unity.[YourPackageName]`)
If your package has Editor code, you **must** have Editor Tests. In that case, rename and modify [Tests/Editor/Unity.YourPackageName.Editor.Tests.asmdef](Tests/Editor/Unity.YourPackageName.Editor.Tests.asmdef).
* Name **must** match your package name, suffixed by `.Editor.Tests` (for example, `Unity.[YourPackageName].Editor.Tests`)
* Assembly **must** reference `Unity.[YourPackageName].Editor` and `Unity.[YourPackageName]` (if you have any Runtime code).
* Platforms **must** include `"Editor"`.
* Optional Unity references **must** include `"TestAssemblies"` to allow your Editor Tests to show up in the Test Runner or run on Katana when your package is listed in the project manifest's `testables` field.
If your package has Runtime code, you **must** have Playmode Tests. In that case, rename and modify [Tests/Runtime/Unity.YourPackageName.Tests.asmdef](Tests/Runtime/Unity.YourPackageName.Tests.asmdef).
* Name **must** match your package name, suffixed by `.Tests` (for example, `Unity.[YourPackageName].Tests`)
* Assembly **must** reference `Unity.[YourPackageName]`.
* Optional Unity references **must** include `"TestAssemblies"` to allow your Playmode Tests to show up in the Test Runner or run on Katana when your package is listed in the project manifest's `testables` field.
### Validate your package
To install the extension, follow these steps:
1. Make sure you have `Package Manager UI v1.9.6` or above.
2. Make sure your project manifest points to the Candidates registry, which you can do by changing the **registry** line to:
```json
"registry": "https://artifactory.prd.cds.internal.unity3d.com/artifactory/api/npm/upm-candidates"
```
3. From the Package Manager window, install the latest version of the **Package Validation Suite** with the scope set to **All Packages**. If you don't see it in the list, make sure **Advanced** &gt; **Show preview packages** is enabled.
Once the Validation Suite package is installed, a **Validate** button appears in the details pane when you select your installed package from the Package Manager window.
To run the tests:
1. Click the **Validate** button to run a series of tests. A **See Results** button appears after the test run.
2. Click the **See Results** button for additional explanation:
* If it succeeds, a green bar displays a **Success** message.
* If it fails, a red bar displays a **Failed** message.
The validation suite is still in preview, so if you come across arguable results, please discuss them on **#devs-packman**.
## Create a Pre-Release Package
Pre-Release Packages are a great way of getting your features in front of Unity Developers in order to get early feedback on functionality and UI designs. Pre-Release packages need to go through the publishing to production flow, as would any other package, but with diminished requirements:
* Expected Package structure respected
* Package loads in Unity Editor without errors
* License file present - With third party notices file if necessary
* Test coverage is good - Optional but preferred
* Public APIs documented, minimal feature docs exists- Optional but preferred
The only supported Pre-Release tag is **preview** which you suffix to the version number of the package in the *package.json* manifest file. For example:
```json
"version" : "1.2.0-preview"
```
## Register your package
If you think you are working on a feature that is a good package candidate, please take a minute to tell Release Management about it in the **#devs-pkg-promotion** channel.
Working with the board of dev directors and with product management, we will schedule the entry of the candidates in the ecosystem, based on technical challenges and on our feature roadmap.
Dont hesitate to reach out and join us on **#devs-packman** on Slack.
## Share your package
If you want to share your project with other developers, the steps are similar to what's presented above. On the other developer's machine:
1. Start **Unity** and create a local empty project.
1. Launch the console (or terminal) application, navigate to the newly created project folder, and then clone your repository in the `Packages` directory:
```shell
cd <YourProjectPath>/Packages
git clone https://github.cdsinternal.unity3d.com/unity/[your-package-name].git com.unity.[sub-group].[your-package-name]
```
> __Note:__ Your directory name must be the name of your package (Example: `"com.unity.terrain-builder"`).
## Make sure your package meets all legal requirements
All packages must COMPLETE AND SUBMIT [THIS FORM](https://docs.google.com/forms/d/e/1FAIpQLSe3H6PARLPIkWVjdB_zMvuIuIVtrqNiGlEt1yshkMCmCMirvA/viewform) to receive approval. It is a simple, streamlined form that tells legal if there are any potential issues that need to be addressed prior to publication.
If your package has third-party elements and its licenses are approved, then all the licenses must be added to the **Third Party Notices.md** file. If you have more than one license, duplicate the `Component Name/License Type/Provide License Details` section for each additional license.
> **Note:** A URL can work as long as it actually points to the reproduced license and the copyright information _(if applicable)_.
If your package does not have third party elements, you can remove the *Third Party Notices.md* file from your package.
## Preparing your package for the Candidates registry
Before publishing your package to production, you must send your package on the Package Manager's internal **candidates** repository. The candidates repository is monitored by QA and release management, and is where package validation will take place before it is accepted in production.
1. Publishing your changes to the Package Manager's **Candidates** registry happens from Github.cds. To do so, set up your project's Continuous integration (CI), which will be triggered by "Tags" on your branches.
For information see [the Confluence page](https://confluence.hq.unity3d.com/display/PAK/Setting+up+your+package+CI) that describes how to set up CI for your package.
1. Test your package locally. Once your package is published on the **Candidates** registry, you can test your package in the editor by creating a new project, and editing the project's *manifest.json* file to point to your candidate package:
```json
dependencies: {
"com.unity.[sub-group].[your-package-name]": "0.1.0"
},
"registry": "https://artifactory.prd.cds.internal.unity3d.com/artifactory/api/npm/upm-candidates"
```
## Get your package published to Production
Packages are promoted to the **Production** registry from the **Candidates** registry, as described above. Your package must meet [certain criteria](https://docs.google.com/document/d/1TSnlSKJ6_h0C-CYO2LvV0fyGxJvH6OxC2-heyN8o-Gw/edit#heading=h.xxfb5jk2jda2) before you can submit a request to promote a package to production.
Once you feel comfortable that your package meets the list of Release Management Criteria, ask to be promoted from candidates to production by going to **#devs-pkg-promotion**.
Also, once you have a package in production for a few versions and it was used by real users, you can ask to be whitelisted to appear in the Package Manager window. Your package will not be visible in the Package Manager window until it is published AND whitelisted by Release Management.
**_Release management will validate your package content, and check that the editor/playmode tests pass before promoting the package to production._**
### Verified status and bundled packages
If your package is meant to ship with a release of the editor (**Verified Packages** and **Bundled Packages**), follow these steps:
1. To be marked as verified, in trunk, modify the editor manifest (*[root]\External\PackageManager\Editor\manifest.json*) to include your package in the **verified** list.
1. If your package is not verified, but only bundled with the editor, submit one or more Test Project(s) in Ono, so that your new package can be tested in all ABVs moving forward.
The following steps will create a test project that will run in ABVs, load your package into the project, and run all the tests found in your package. The better your test coverage, the more confident you'll be that your package works with trunk.
* Create a branch in Ono, based on the latest branch this package must be compatible with (trunk, or release branch).
* If your package contains **Editor Tests**:
* In *[root]\Tests\Editor.Tests*, create a new EditorTest Project (for new packages use **YourPackageName**) or use an existing project (for new versions of existing package).
To get a bare package for an EditorTest Project, click [here](https://oc.unity3d.com/index.php/s/Cldvuy6NpxqYy8y).
* Modify the projects *manifest.json* file to include the production version of the package (`name@version`).
* Your project's *manifest.json* file should contain the following line:
```json
"testables" : [ "com.unity.[sub-group].[your-package-name]" ]
```
* If your package contains **PlaymodeTests**:
* In *[root]\Tests\PlaymodeTests*, create a new PlaymodeTest Project (for new packages use **YourPackageName**) or use an existing project (for new versions of existing package).
* Modify the projects *manifest.json* file to include the candidate version of the package (`name@version`).
* Your project's manifest.json file should contain the following line:
```json
"testables" : [ "com.unity.[sub-group].[your-package-name]" ]
```
* Commit your branch changes to Ono, and run all Windows & Mac Editor/PlayMode tests (not full ABV) in Katana.
1. Once the tests are green on Katana, create your PR, add both **Latest Release Manager** and **Trunk Merge Queue** as reviewers.
## FAQ
**Whats the difference between a preview package and a verified package?**
A preview package is a great way to develop and get feedback on new features and functionality. Preview package can be created against any version of Unity 2018.1+, and can be made discoverable through the Package Manager UI by issuing a request in #devs-packman. Quality and release schedule is up to the package owner, although minimum bars are set in place to ensure the package contains the right licenses, documentation, and a comprehensive set of tests.
Once a preview package has been in the field for 2-3 release cycles of the editor, that package can be considered for Verification. Verified packages are tested with a specific version of the editor, and offer our users a compatibility guarantee. Verified packages are the only packages that can be included in the set of templates we ship with the editor (Verified Templates). Code for these packages must follow core development guidelines, including code cutoff dates, and are tested in katana for continued compatibility.
**Whats the difference between a core package and a default package?**
A core package is a package that has its code included with the Editors core code. This is interesting for packages that plan to change enormously in parallel to editor APIs. By moving package code to the editors repo, both core API\functionality changes can be made along with required packages changes in the same PR.
https://docs.google.com/document/d/1CMoanjR3KAdew-6n39JdCFmHkTp1oshs3vkpejapf4Q/edit
A default package is a verified package that gets installed with every new project users create, regardless of the template they use. We should limit the number of default packages we support, as each default package adds to the project loading time. The list of default packages can be found in the editor manifest (https://ono.unity3d.com/unity/unity/files/de904b9ed9b44580ecd1e883f510daaa08182cc5/External/PackageManager/Editor/manifest.json).
**What are the requirement for me to publish a preview package?**
https://docs.google.com/document/d/1epGkAJRayJLN89_weA_-G5LFT_1uFifFZqBzAgvp_Zs/
**What are the requirements for me to get my package verified for a version of unity?**
https://docs.google.com/document/d/1oWC9XArVfkGMnqN9azR4hW4Pcd7-kQQw8Oy7ckP43JE/
**How is my verified package tested in Katana?**
https://docs.google.com/document/d/1jwTh71ZGtB2vF0SsHEwivt2FunaJWMGDdQJTpYRj3EE/edit
**How is my template tested in Katana?**
https://docs.google.com/document/d/1jwTh71ZGtB2vF0SsHEwivt2FunaJWMGDdQJTpYRj3EE/edit
**How do I add samples to my package?**
https://docs.google.com/document/d/1rmxGh6Z9gtbQlGUKCsVBaR0RyHvzq_gsWoYs6sttzYA/edit#heading=h.fg1e3sz56048
**How do I setup CI or publishing options for my package?**
https://confluence.hq.unity3d.com/display/PAK/Setting+up+your+package+CI
**How can I add tests to my package?**
Theres a “Tests” directory in the package starter kit. If you add editor and playmode tests in that directory, they will make up the list of tests for your package.
**The tests in my package bloat my package too much, what are my options?**
https://docs.google.com/document/d/19kKIGFetde5ES-gKXQp_P7bxQ9UgBnBUu58-y7c1rTA/edit
**Can I automate my package publishing yet?**
Not just yet, but were working on it. The first automated publishing we will enable is the push to production for preview packages. Basically, when your package passes validation (loads in the editor without error, the tests in the package pass, validation suite run success), the package will be pushed to production automatically. Other publishing flows will soon be available as well, heres the full list of internal package publishing flows Unity will support. https://docs.google.com/document/d/1zdMzAtfi-vgM8NMPmwL40yinBeL3YImwTO5gSfGNCgs/edit
**How do I get a template package started?**
Start with the Project Template Starter Kit (you can request access in **#devs-packman**).
https://github.cds.internal.unity3d.com/unity/com.unity.template-starter-kit
**How do I get my package included in a template?**
First and foremost, your package needs to be on the verified list of packages. Only verified packages can get added to templates we ship with the editor. Then reach out to the templates community in **#devs-template** to open discussions on adding your package to one or more of our existing templates.
**How can I test my package locally, as a user would?**
https://confluence.hq.unity3d.com/display/PAK/How+to+add+a+git+package+to+your+project
**What tests are included by the validation suite?**
https://docs.google.com/spreadsheets/d/1CdO7D0WSirbZhjnVsdJxJwOPK4UdUDxSRBIqwyjm70w/edit#gid=0

Просмотреть файл

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: fbde06cfbf0952043b92f05755959f4c
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 4187919837946ea479e9dd7d67ba328c
guid: 025606af85fbe2846b479c744861150a
folderAsset: yes
DefaultImporter:
externalObjects: {}

Просмотреть файл

@ -0,0 +1,383 @@
using UnityEngine;
using UnityEngine.SceneManagement;
using System;
using System.Collections.Generic;
using UnityEngine.Rendering;
using System.Collections;
#if UNITY_EDITOR
using UnityEditor;
#endif
[ExecuteInEditMode]
public class LevelLightmapData : MonoBehaviour
{
[System.Serializable]
public class SphericalHarmonics
{
public float[] coefficients = new float[27];
}
[System.Serializable]
public class RendererInfo
{
public Renderer renderer;
public int lightmapIndex;
public Vector4 lightmapOffsetScale;
}
[System.Serializable]
public class LightingScenarioData {
public RendererInfo[] rendererInfos;
public Texture2D[] lightmaps;
public Texture2D[] lightmapsDir;
public Texture2D[] shadowMasks;
public LightmapsMode lightmapsMode;
public SphericalHarmonics[] lightProbes;
public bool hasRealtimeLights;
}
public bool latestBuildHasReltimeLights;
public bool allowLoadingLightingScenes = true;
[SerializeField]
List<LightingScenarioData> lightingScenariosData;
#if UNITY_EDITOR
[SerializeField]
public List<SceneAsset> lightingScenariosScenes;
#endif
[SerializeField]
public String[] lightingScenesNames = new string[1];
public int currentLightingScenario = -1;
public int previousLightingScenario = -1;
private Coroutine m_SwitchSceneCoroutine;
[SerializeField]
public int lightingScenariosCount;
//TODO : enable logs only when verbose enabled
public bool verbose = false;
private List<SphericalHarmonicsL2[]> lightProbesRuntime = new List<SphericalHarmonicsL2[]>();
public void LoadLightingScenario(int index)
{
if(index != currentLightingScenario)
{
previousLightingScenario = currentLightingScenario == -1 ? index : currentLightingScenario;
currentLightingScenario = index;
LightmapSettings.lightmapsMode = lightingScenariosData[index].lightmapsMode;
if(allowLoadingLightingScenes)
m_SwitchSceneCoroutine = StartCoroutine(SwitchSceneCoroutine(lightingScenesNames[previousLightingScenario], lightingScenesNames[currentLightingScenario]));
var newLightmaps = LoadLightmaps(index);
ApplyRendererInfo(lightingScenariosData[index].rendererInfos);
LightmapSettings.lightmaps = newLightmaps;
LoadLightProbes(currentLightingScenario);
}
}
private void Start()
{
PrepareLightProbeArrays();
}
private void PrepareLightProbeArrays()
{
for (int x = 0; x < lightingScenariosCount; x++)
{
lightProbesRuntime.Add(DeserializeLightProbes(x));
}
}
private SphericalHarmonicsL2[] DeserializeLightProbes(int index)
{
var sphericalHarmonicsArray = new SphericalHarmonicsL2[lightingScenariosData[index].lightProbes.Length];
for (int i = 0; i < lightingScenariosData[index].lightProbes.Length; i++)
{
var sphericalHarmonics = new SphericalHarmonicsL2();
// j is coefficient
for (int j = 0; j < 3; j++)
{
//k is channel ( r g b )
for (int k = 0; k < 9; k++)
{
sphericalHarmonics[j, k] = lightingScenariosData[index].lightProbes[i].coefficients[j * 9 + k];
}
}
sphericalHarmonicsArray[i] = sphericalHarmonics;
}
return sphericalHarmonicsArray;
}
IEnumerator SwitchSceneCoroutine(string sceneToUnload, string sceneToLoad)
{
AsyncOperation unloadop = null;
AsyncOperation loadop = null;
if (sceneToUnload != null && sceneToUnload != string.Empty && sceneToUnload != sceneToLoad)
{
unloadop = SceneManager.UnloadSceneAsync(sceneToUnload);
while (!unloadop.isDone)
{
yield return new WaitForEndOfFrame();
}
}
if(sceneToLoad != null && sceneToLoad != string.Empty && sceneToLoad != "")
{
loadop = SceneManager.LoadSceneAsync(sceneToLoad, LoadSceneMode.Additive);
while ((!loadop.isDone || loadop == null))
{
yield return new WaitForEndOfFrame();
}
SceneManager.SetActiveScene(SceneManager.GetSceneByName(sceneToLoad));
}
LoadLightProbes(currentLightingScenario);
}
LightmapData[] LoadLightmaps(int index)
{
if (lightingScenariosData[index].lightmaps == null
|| lightingScenariosData[index].lightmaps.Length == 0)
{
Debug.LogWarning("No lightmaps stored in scenario " + index);
return null;
}
var newLightmaps = new LightmapData[lightingScenariosData[index].lightmaps.Length];
for (int i = 0; i < newLightmaps.Length; i++)
{
newLightmaps[i] = new LightmapData();
newLightmaps[i].lightmapColor = lightingScenariosData[index].lightmaps[i];
if (lightingScenariosData[index].lightmapsMode != LightmapsMode.NonDirectional)
{
newLightmaps[i].lightmapDir = lightingScenariosData[index].lightmapsDir[i];
}
if (lightingScenariosData[index].shadowMasks.Length > 0)
{
newLightmaps[i].shadowMask = lightingScenariosData[index].shadowMasks[i];
}
}
return newLightmaps;
}
public void ApplyRendererInfo(RendererInfo[] infos)
{
try
{
Terrain terrain = FindObjectOfType<Terrain>();
int i = 0;
if (terrain != null)
{
terrain.lightmapIndex = infos[i].lightmapIndex;
terrain.lightmapScaleOffset = infos[i].lightmapOffsetScale;
i++;
}
for (int j = i; j < infos.Length; j++)
{
RendererInfo info = infos[j];
//if (info.renderer == null)
//continue;
info.renderer.lightmapIndex = infos[j].lightmapIndex;
if (!info.renderer.isPartOfStaticBatch)
{
info.renderer.lightmapScaleOffset = infos[j].lightmapOffsetScale;
}
if (info.renderer.isPartOfStaticBatch && verbose == true && Application.isEditor)
{
Debug.Log("Object " + info.renderer.gameObject.name + " is part of static batch, skipping lightmap offset and scale.");
}
}
}
catch (Exception e)
{
Debug.LogError("Error in ApplyRendererInfo:" + e.GetType().ToString());
}
}
public void LoadLightProbes(int index)
{
if (Application.isEditor && !Application.isPlaying)
{
PrepareLightProbeArrays();
}
try
{
LightmapSettings.lightProbes.bakedProbes = lightProbesRuntime[index];
}
catch { Debug.LogWarning("Warning, error when trying to load lightprobes for scenario " + index); }
}
public void StoreLightmapInfos(int index)
{
var newLightingScenarioData = new LightingScenarioData ();
var newRendererInfos = new List<RendererInfo>();
var newLightmapsTextures = new List<Texture2D>();
var newLightmapsTexturesDir = new List<Texture2D>();
var newLightmapsMode = new LightmapsMode();
var newSphericalHarmonicsList = new List<SphericalHarmonics>();
var newLightmapsShadowMasks = new List<Texture2D>();
newLightmapsMode = LightmapSettings.lightmapsMode;
GenerateLightmapInfo(gameObject, newRendererInfos, newLightmapsTextures, newLightmapsTexturesDir, newLightmapsShadowMasks, newLightmapsMode);
newLightingScenarioData.lightmapsMode = newLightmapsMode;
newLightingScenarioData.lightmaps = newLightmapsTextures.ToArray();
if (newLightmapsMode != LightmapsMode.NonDirectional)
{
newLightingScenarioData.lightmapsDir = newLightmapsTexturesDir.ToArray();
}
//Mixed or realtime support
newLightingScenarioData.hasRealtimeLights = latestBuildHasReltimeLights;
newLightingScenarioData.shadowMasks = newLightmapsShadowMasks.ToArray();
newLightingScenarioData.rendererInfos = newRendererInfos.ToArray();
var scene_LightProbes = new SphericalHarmonicsL2[LightmapSettings.lightProbes.bakedProbes.Length];
scene_LightProbes = LightmapSettings.lightProbes.bakedProbes;
for (int i = 0; i < scene_LightProbes.Length; i++)
{
var SHCoeff = new SphericalHarmonics();
// j is coefficient
for (int j = 0; j < 3; j++)
{
//k is channel ( r g b )
for (int k = 0; k < 9; k++)
{
SHCoeff.coefficients[j*9+k] = scene_LightProbes[i][j, k];
}
}
newSphericalHarmonicsList.Add(SHCoeff);
}
newLightingScenarioData.lightProbes = newSphericalHarmonicsList.ToArray ();
if (lightingScenariosData.Count < index + 1)
{
lightingScenariosData.Insert(index, newLightingScenarioData);
}
else
{
lightingScenariosData[index] = newLightingScenarioData;
}
lightingScenariosCount = lightingScenariosData.Count;
if (lightingScenesNames == null || lightingScenesNames.Length< lightingScenariosCount)
{
lightingScenesNames = new string[lightingScenariosCount];
}
}
static void GenerateLightmapInfo(GameObject root, List<RendererInfo> newRendererInfos, List<Texture2D> newLightmapsLight, List<Texture2D> newLightmapsDir, List<Texture2D> newLightmapsShadow, LightmapsMode newLightmapsMode)
{
Terrain terrain = FindObjectOfType<Terrain>();
if (terrain != null && terrain.lightmapIndex != -1 && terrain.lightmapIndex != 65534)
{
RendererInfo terrainRendererInfo = new RendererInfo();
terrainRendererInfo.lightmapOffsetScale = terrain.lightmapScaleOffset;
Texture2D lightmaplight = LightmapSettings.lightmaps[terrain.lightmapIndex].lightmapColor;
terrainRendererInfo.lightmapIndex = newLightmapsLight.IndexOf(lightmaplight);
if (terrainRendererInfo.lightmapIndex == -1)
{
terrainRendererInfo.lightmapIndex = newLightmapsLight.Count;
newLightmapsLight.Add(lightmaplight);
}
if (newLightmapsMode != LightmapsMode.NonDirectional)
{
Texture2D lightmapdir = LightmapSettings.lightmaps[terrain.lightmapIndex].lightmapDir;
terrainRendererInfo.lightmapIndex = newLightmapsDir.IndexOf(lightmapdir);
if (terrainRendererInfo.lightmapIndex == -1)
{
terrainRendererInfo.lightmapIndex = newLightmapsDir.Count;
newLightmapsDir.Add(lightmapdir);
}
}
if (LightmapSettings.lightmaps[terrain.lightmapIndex].shadowMask != null)
{
Texture2D lightmapShadow = LightmapSettings.lightmaps[terrain.lightmapIndex].shadowMask;
terrainRendererInfo.lightmapIndex = newLightmapsShadow.IndexOf(lightmapShadow);
if (terrainRendererInfo.lightmapIndex == -1)
{
terrainRendererInfo.lightmapIndex = newLightmapsShadow.Count;
newLightmapsShadow.Add(lightmapShadow);
}
}
newRendererInfos.Add(terrainRendererInfo);
if (Application.isEditor)
Debug.Log("Terrain lightmap stored in" + terrainRendererInfo.lightmapIndex.ToString());
}
var renderers = FindObjectsOfType(typeof(Renderer));
if (Application.isEditor)
Debug.Log("stored info for " + renderers.Length + " meshrenderers");
foreach (Renderer renderer in renderers)
{
if (renderer.lightmapIndex != -1 && renderer.lightmapIndex != 65534)
{
RendererInfo info = new RendererInfo();
info.renderer = renderer;
info.lightmapOffsetScale = renderer.lightmapScaleOffset;
Texture2D lightmaplight = LightmapSettings.lightmaps[renderer.lightmapIndex].lightmapColor;
info.lightmapIndex = newLightmapsLight.IndexOf(lightmaplight);
if (info.lightmapIndex == -1)
{
info.lightmapIndex = newLightmapsLight.Count;
newLightmapsLight.Add(lightmaplight);
}
if (newLightmapsMode != LightmapsMode.NonDirectional)
{
Texture2D lightmapdir = LightmapSettings.lightmaps[renderer.lightmapIndex].lightmapDir;
info.lightmapIndex = newLightmapsDir.IndexOf(lightmapdir);
if (info.lightmapIndex == -1)
{
info.lightmapIndex = newLightmapsDir.Count;
newLightmapsDir.Add(lightmapdir);
}
}
if (LightmapSettings.lightmaps[renderer.lightmapIndex].shadowMask != null)
{
Texture2D lightmapShadow = LightmapSettings.lightmaps[renderer.lightmapIndex].shadowMask;
info.lightmapIndex = newLightmapsShadow.IndexOf(lightmapShadow);
if (info.lightmapIndex == -1)
{
info.lightmapIndex = newLightmapsShadow.Count;
newLightmapsShadow.Add(lightmapShadow);
}
}
newRendererInfos.Add(info);
}
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 311c76c9ffea5554c82aa90000c874ac
timeCreated: 1435326575
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 4021dabdeeef1824b871b34d975991b8, type: 3}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,6 @@
{
"name": "LightingTools.LightmapSwitcher",
"references": [],
"includePlatforms": [],
"excludePlatforms": []
}

Просмотреть файл

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 802596836aa83094ea9d1166a80d7e4e
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,10 @@
{
"name": "li.lightingtools.lightmapswitcher",
"displayName": "Lightmap Switcher",
"version": "0.1.0-preview",
"unity": "2019.1",
"description": "Allows you to switch lightmaps at runtime.",
"dependencies": {
"com.unity.editorcoroutines": "0.0.2-preview"
}
}

Просмотреть файл

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 243e8b565ec911f4dbcf88980a8510af
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,42 @@
# Changelog
All notable changes to this package will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## [7.1.6] - 2019-11-22
Version Updated
The version number for this package has increased due to a version update of a related graphics package.
## [7.1.5] - 2019-11-15
Version Updated
The version number for this package has increased due to a version update of a related graphics package.
## [7.1.4] - 2019-11-13
Version Updated
The version number for this package has increased due to a version update of a related graphics package.
## [7.1.3] - 2019-11-04
Version Updated
The version number for this package has increased due to a version update of a related graphics package.
## [7.1.2] - 2019-09-19
Version Updated
The version number for this package has increased due to a version update of a related graphics package.
## [7.1.1] - 2019-09-05
Version Updated
The version number for this package has increased due to a version update of a related graphics package.
## [7.0.1] - 2019-07-25
Version Updated
The version number for this package has increased due to a version update of a related graphics package.
Started Changelog

Просмотреть файл

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 0b3f7006c7834664ba28a1fa6b51f9fe
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,5 @@
Render Pipeline Core copyright © 2019 Unity Technologies ApS
Licensed under the Unity Companion License for Unity-dependent projects--see [Unity Companion License](http://www.unity3d.com/legal/licenses/Unity_Companion_License).
Unless expressly provided otherwise, the Software under this license is made available strictly on an “AS IS” BASIS WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. Please review the license for details on these and other terms and conditions.

Просмотреть файл

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: e797817a7447e1f42816cf2c2fa8765d
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5d299198a792a964e9d443aa47506e2c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,49 @@
//-----------------------------------------------------------------------------
// Configuration
//-----------------------------------------------------------------------------
namespace UnityEngine.Rendering.HighDefinition
{
[GenerateHLSL(PackingRules.Exact)]
public enum HDShadowFilteringQuality
{
Low = 0,
Medium = 1,
High = 2,
}
[GenerateHLSL(PackingRules.Exact)]
public enum ShaderOptions
{
CameraRelativeRendering = 1, // Rendering sets the origin of the world to the position of the primary (scene view) camera
PreExposition = 1,
PrecomputedAtmosphericAttenuation = 0, // Precomputes atmospheric attenuation for the directional light on the CPU, which makes it independent from the fragment's position, which is faster but wrong
#if ENABLE_RAYTRACING
Raytracing = 1,
#else
Raytracing = 0,
#endif
#if ENABLE_VR
XrMaxViews = 2, // Used for single-pass rendering (with fast path in vertex shader code when forced to 2)
#else
XrMaxViews = 1,
#endif
AreaLights = 0,
DeferredShadowFiltering = HDShadowFilteringQuality.Medium,
BarnDoor = 0
};
// Note: #define can't be use in include file in C# so we chose this way to configure both C# and hlsl
// Changing a value in this enum Config here require to regenerate the hlsl include and recompile C# and shaders
public class ShaderConfig
{
public static int s_CameraRelativeRendering = (int)ShaderOptions.CameraRelativeRendering;
public static int s_PreExposition = (int)ShaderOptions.PreExposition;
public static int s_XrMaxViews = (int)ShaderOptions.XrMaxViews;
public static int s_PrecomputedAtmosphericAttenuation = (int)ShaderOptions.PrecomputedAtmosphericAttenuation;
public static int s_AreaLights = (int)ShaderOptions.AreaLights;
public static int s_BarnDoor = (int)ShaderOptions.BarnDoor;
public static HDShadowFilteringQuality s_DeferredShadowFiltering = (HDShadowFilteringQuality)ShaderOptions.DeferredShadowFiltering;
}
}

Просмотреть файл

@ -0,0 +1,27 @@
//
// This file was automatically generated. Please don't edit by hand.
//
#ifndef SHADERCONFIG_CS_HLSL
#define SHADERCONFIG_CS_HLSL
//
// UnityEngine.Rendering.HighDefinition.HDShadowFilteringQuality: static fields
//
#define HDSHADOWFILTERINGQUALITY_LOW (0)
#define HDSHADOWFILTERINGQUALITY_MEDIUM (1)
#define HDSHADOWFILTERINGQUALITY_HIGH (2)
//
// UnityEngine.Rendering.HighDefinition.ShaderOptions: static fields
//
#define SHADEROPTIONS_CAMERA_RELATIVE_RENDERING (1)
#define SHADEROPTIONS_PRE_EXPOSITION (1)
#define SHADEROPTIONS_PRECOMPUTED_ATMOSPHERIC_ATTENUATION (0)
#define SHADEROPTIONS_RAYTRACING (0)
#define SHADEROPTIONS_XR_MAX_VIEWS (2)
#define SHADEROPTIONS_AREA_LIGHTS (1)
#define SHADEROPTIONS_DEFERRED_SHADOW_FILTERING (1)
#define SHADEROPTIONS_BARN_DOOR (0)
#endif

Просмотреть файл

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: bcb8aa9f314d49b4c97aa1f3f3511e7b
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 488b9213a64c77540bca3fe167edbe6c
timeCreated: 1475742183
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,14 @@
{
"name": "Unity.RenderPipelines.HighDefinition.Config.Runtime",
"references": [
"GUID:df380645f10b7bc4b97d4f5eb6303d95"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": true,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": []
}

Просмотреть файл

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: a075b55b404a34748ac14ea9b6039911
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,16 @@
{
"name": "com.unity.render-pipelines.high-definition-config",
"description": "Configuration files for the High Definition Render Pipeline.",
"version": "7.1.6",
"unity": "2019.3",
"unityRelease": "0b13",
"displayName": "High Definition RP Config",
"dependencies": {
"com.unity.render-pipelines.core": "7.1.6"
},
"repository": {
"type": "git",
"url": "git@github.com:Unity-Technologies/ScriptableRenderPipeline.git",
"revision": "462033f359f783f5d71dc578159bf5827abb41e2"
}
}

Просмотреть файл

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: af6e0e6bb9a468845bfb9c9381e3219b
PackageManifestImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,152 @@
# Changelog
## 2019.3.1
#### Changed
* **Messager** is now able to pass instigator Game Object through message broadcast.
* **OnMessageEvent** now passes the optional instigator instead of itself as instigator to the Calls. In order to pass itself use an intermediate **SetInstigatorLogic** that targets the OnMessageEvent owner to replicate the former behaviour.
* **SendMessageAction** now passes its instigator game object to the **Messager**
#### Added
* **Call Tree Explorer**: Added Category for Erroneous Calls
* Added **ToggleBehaviourAction** working the same as ToggleGameObjectAction, but for behaviour components instead.
* **SendMessageBehaviour** (Timeline Send Message Tracks/Clips) now displays an instigator game object field in the inspector to be attached to the sent message.
* Added **VFXSetPropertyAction**
* Added **VFXSendEventAction**
#### Fixed
* Fixed `OnValidate` for FirstPersonController leading to infinite import loop when displaying the inspector for a Prefab Asset.
* Fix for null Callables in Callable Tree Window.
## 2019.3.0
* Feature Release
* Requires Unity 2019.3.0 or newer
#### Added
* **Call Tree Explorer :** Using Window/Gameplay Ingredients/Call Tree Explorer , opens a window that lists the tree of Events, Logic and Actions, State Machines and Event Calling Actions
* **Folders:** In the Game Object creation Menu, Select folder to add a folder in the hierarchy. Automatically adds Static Game Objects with colored icon (Displayed using Advanced Hierarchy View)
* **Global Variables System**:
- Added Global Variables (Globals + Local Scope)
- Added Global Variable Debug Window (`Window/Gameplay Ingredients/Globals Debug`)
- Added Global Variable Set Action
- Added Global Variable Logic
- Added Global Variables Reset Action
* **Timers**:
* Added Timer Component
* Added TimerAction to control Timer
* Added TimerDisplayRig
* Added option in GameplayIngredientsSettings to disable visibility of Callable[] bound to Update Loops.
* Added OnUpdate Event : Perform calls every update
* Added OnColider Event : Perform calls upon collisions
* Added OnJoinBreak Event : Perform calls upon Rigid body joint break
* Added FlipFlop Logic : Two-state latch logic
* Added State Logic : Perform logic based on State Machine current state.
* Added Audio Mix Snapshot Action : Set Mixer Snapshots
* Added RigidBody Action : Perform actions on a rigidbody
* Added SetAnimatorParameterAction : Perform parameter setting on Animators
* Added Sacrifice Oldest option to Factory : When needing a new spawn but no slots left, sacrifices the first spawn of the list
* Added Context Menu in ToggleGameObjectAction to update entries based on current enabled state in scene.
#### Changed
- Improved **Find & Replace** window, with a selection-based criteria.
- Moved Menu Items in Window menu into a Gameplay Ingredients Subfolder
- GameManager Resets Global Variables Local Scope on Level Load
- Updated NaughtyAttributes to a more recent version
- Renamed the Add Game Object menu category from `'GameplayIngredients' to 'Gameplay Ingredients'` and adjusted its contents
#### Fixed
* Fixed LinkGameView not working in play mode when excluding VirtualCameraManager.
* Fixed Performance issue in GameplayIngredientsSettings when having a big list of Excluded managers.
* Fixed ApplicationExitAction : Exits play mode when in Editor.
## 2019.1.2
#### Changed
* **[Breaking Change]** Discover Assets now reference many Scenes/SceneSetups
* Action to take: have to re-reference scenes in Discover Asset
#### Added
* Added Screenshot Manager (Defaults to F11 to take screenshots)
* Added OnMouseDownEvent
* Added OnMouseHoverEvent
* Added OnVisibilityEvent
* Added SaveDataSwitchOnIntLogic
#### Fixed
* Fixed warning in CycleResolutionsAction
## 2019.1.1
#### Changed
#### Added
* Log Action
* Added Playable Director to objects in discover (to open atimeline at a give playable director)
* Added support of Game Save Value index for Factories (in order to select a blueprint object from a saved value)
#### Fixed
* Fixed Import Errors at first project load, including the way we load discover and GameplayIngredients project settings
* Secure checks in Gathering Manager classes from assembly (skips protected assemblies now)
## 2019.1.0
#### Changed
* Removed counts in OnTriggerEvent
* Callables can now be friendly-named (with default formatting)
* Updated Starter Packages
#### Added
- Added NTimesLogic (split from OnTriggerEvent)
- Added Replace Mode for Level Streaming Manager
- Added UIToggle Action and Property Drawer
- Added Audio Play Clip Action
- Added Platform Logic
- New Welcome Screen, with Wizard
- New optional GameplayIngredients Project Configuration asset
- Toggles for verbose callable logging
- Manager Exclusion List
- New Scene from Template Window + Config SceneTemplateLists Assets
- Helps creating new scenes from user-made templates
- New Discover Window System:
- Adds a new DiscoverAsset to reference Levels / Scene Setups
- Adds new Discover components in scenes
- Discover window helps navigate scenes while in editor and discover content.
- Added improved Game Manager
- Manages loading of main menu & levels directly instead of using LevelStreamingManager
- Manages Level Startup in sync after all scenes have started.
#### Fixed
* Fixed code to run on Unity 2019.1
* Fixed factory managed objects upon destroy
* Fixes in LinkGameView when application is not playing
* Fix in LevelStreamingManager incorrect computation of Scene Counts
* Fixes in VirtualCameraManager
* Fixes in Find/Replace window
* Fixes in Hierarchy View Hints for Unity 2019.3 new skin
## 2018.3.0
Initial Version

Просмотреть файл

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: a2d80afb13247c646b079b5f51dcb6ac
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: dedb43ed8dff48a4ea95d29002e41ca4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e78d538974cc9924792b2707919e382a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,43 @@
using UnityEngine;
using UnityEditor.Callbacks;
using UnityEditor.ProjectWindowCallback;
using System;
using System.IO;
using UnityEditor;
namespace GameplayIngredients.Editor
{
public class AssetFactory
{
public static void CreateAssetInProjectWindow<T>(string iconName, string fileName) where T: ScriptableObject
{
var icon = EditorGUIUtility.FindTexture(iconName);
var namingInstance = new DoCreateGenericAsset();
namingInstance.type = typeof(T);
ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0, namingInstance, fileName, icon, null);
}
public static ScriptableObject CreateAssetAtPath(string path, Type type)
{
Debug.Log("CreateAssetAtPath (" + type.Name + ")");
ScriptableObject asset = ScriptableObject.CreateInstance(type);
asset.name = Path.GetFileName(path);
AssetDatabase.CreateAsset(asset, path);
return asset;
}
class DoCreateGenericAsset : EndNameEditAction
{
public Type type;
public override void Action(int instanceId, string pathName, string resourceFile)
{
ScriptableObject asset = AssetFactory.CreateAssetAtPath(pathName, type);
ProjectWindowUtil.ShowCreatedAsset(asset);
}
}
}
}

Просмотреть файл

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 3e93b674f69eb054c8514bd7c501f0e3
guid: 4833ee2adf8a9cd4c96cbd6dac04fe42
MonoImporter:
externalObjects: {}
serializedVersion: 2

Просмотреть файл

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 37d3d697167f89145a81aa7bb6c0acc4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,562 @@
using System.Collections;
using System.Linq;
using System.Collections.Generic;
using System;
using System.Reflection;
using UnityEngine;
using UnityEditor;
using UnityEditor.IMGUI.Controls;
using UnityEditor.SceneManagement;
using GameplayIngredients.Events;
using GameplayIngredients.Logic;
using GameplayIngredients.Actions;
using GameplayIngredients.StateMachines;
using UnityEngine.SceneManagement;
namespace GameplayIngredients.Editor
{
public class CallTreeWindow : EditorWindow
{
CallTreeView m_TreeView;
[MenuItem("Window/Gameplay Ingredients/Callable Tree Explorer", priority = MenuItems.kWindowMenuPriority)]
static void OpenWindow()
{
s_Instance = GetWindow<CallTreeWindow>();
}
public static bool visible = false;
static CallTreeWindow s_Instance;
private void OnDisable()
{
visible = false;
s_Instance = null;
}
private void OnEnable()
{
nodeRoots = new Dictionary<string, List<CallTreeNode>>();
m_TreeView = new CallTreeView(nodeRoots);
titleContent = new GUIContent("Callable Tree Explorer", CallTreeView.Styles.Callable);
ReloadCallHierarchy();
EditorSceneManager.sceneOpened += Reload;
EditorSceneSetup.onSetupLoaded += ReloadSetup;
visible = true;
}
void Reload(Scene scene, OpenSceneMode mode)
{
ReloadCallHierarchy();
}
void ReloadSetup(EditorSceneSetup setup)
{
ReloadCallHierarchy();
}
public static void Refresh()
{
s_Instance.ReloadCallHierarchy();
s_Instance.Repaint();
}
private void OnGUI()
{
int tbHeight = 24;
using (new GUILayout.HorizontalScope(EditorStyles.toolbar, GUILayout.Height(tbHeight)))
{
if (GUILayout.Button("Reload", EditorStyles.toolbarButton))
{
ReloadCallHierarchy();
}
GUILayout.FlexibleSpace();
EditorGUI.BeginChangeCheck();
string filter = EditorGUILayout.DelayedTextField(m_TreeView.stringFilter, EditorStyles.toolbarSearchField);
if (EditorGUI.EndChangeCheck())
{
m_TreeView.SetStringFilter(filter);
}
Rect buttonRect = GUILayoutUtility.GetRect(52, 16);
if (GUI.Button(buttonRect, "Filter", EditorStyles.toolbarDropDown))
{
GenericMenu menu = new GenericMenu();
menu.AddItem(new GUIContent("Filter Selected"), false, () => {
m_TreeView.SetAutoFilter(false);
m_TreeView.SetObjectFilter(Selection.activeGameObject);
});
menu.AddItem(new GUIContent("Clear Filter"), false, () => {
m_TreeView.SetAutoFilter(false);
m_TreeView.SetObjectFilter(null);
m_TreeView.SetStringFilter(string.Empty);
});
menu.AddSeparator("");
menu.AddItem(new GUIContent("Automatic Filter"), m_TreeView.AutoFilter, () => {
m_TreeView.ToggleAutoFilter();
});
menu.DropDown(buttonRect);
}
}
Rect r = GUILayoutUtility.GetRect(position.width, position.height - tbHeight);
m_TreeView.OnGUI(r);
}
Dictionary<string, List<CallTreeNode>> nodeRoots;
List<MonoBehaviour> erroneous;
void ReloadCallHierarchy()
{
if (nodeRoots == null)
nodeRoots = new Dictionary<string, List<CallTreeNode>>();
else
nodeRoots.Clear();
erroneous = new List<MonoBehaviour>();
AddToCategory<EventBase>("Events");
AddToCategory<StateMachine>("State Machines");
AddToCategory<Factory>("Factories");
AddToCategory<SendMessageAction>("Messages");
CollectErroneousCallables();
m_TreeView.Reload();
}
void CollectErroneousCallables()
{
if (erroneous == null || erroneous.Count == 0)
return;
var root = new List<CallTreeNode>();
nodeRoots.Add("Erroneous Callables", root);
foreach(var callable in erroneous)
{
root.Add(new CallTreeNode(callable, CallTreeNodeType.Callable, callable.name));
}
}
void AddErroneous(MonoBehaviour bhv)
{
if (!erroneous.Contains(bhv))
erroneous.Add(bhv);
}
void AddToCategory<T>(string name) where T:MonoBehaviour
{
var list = Resources.FindObjectsOfTypeAll<T>().ToList();
if (list.Count > 0)
nodeRoots.Add(name, new List<CallTreeNode>());
else
return;
var listRoot = nodeRoots[name];
foreach (var item in list)
{
if (item.gameObject.scene == null || !item.gameObject.scene.isLoaded)
continue;
var stack = new Stack<object>();
if(typeof(T) == typeof(StateMachine))
{
listRoot.Add(GetStateMachineNode(item as StateMachine, stack));
}
else if(typeof(T) == typeof(SendMessageAction))
{
listRoot.Add(GetMessageNode(item as SendMessageAction, stack));
}
else
{
listRoot.Add(GetNode(item, stack));
}
}
}
CallTreeNode GetNode(MonoBehaviour bhv, Stack<object> stack)
{
if(!stack.Contains(bhv))
{
stack.Push(bhv);
var rootNode = new CallTreeNode(bhv, GetType(bhv), $"{bhv.gameObject.name} ({bhv.GetType().Name})");
var type = bhv.GetType();
foreach (var field in type.GetFields())
{
// Find Fields that are Callable[]
if (field.FieldType.IsAssignableFrom(typeof(Callable[])))
{
var node = new CallTreeNode(bhv, CallTreeNodeType.Callable, field.Name);
var value = (Callable[])field.GetValue(bhv);
if (value != null && value.Length > 0)
{
rootNode.Children.Add(node);
// Add Callables from this Callable[] array
foreach (var call in value)
{
if (call != null)
node.Children.Add(GetCallableNode(call, stack));
else
AddErroneous(node.Target);
}
}
}
}
return rootNode;
}
else
{
return new CallTreeNode(bhv, GetType(bhv), $"RECURSED : {bhv.gameObject.name} ({bhv.GetType().Name})");
}
}
CallTreeNode GetCallableNode(Callable c, Stack<object> stack)
{
if (!stack.Contains(c))
{
stack.Push(c);
var rootNode = new CallTreeNode(c, GetType(c), $"{c.Name} ({c.gameObject.name} : {c.GetType().Name})");
var type = c.GetType();
foreach (var field in type.GetFields())
{
// Find Fields that are Callable[]
if (field.FieldType.IsAssignableFrom(typeof(Callable[])))
{
var node = new CallTreeNode(c, CallTreeNodeType.Callable, field.Name);
var value = (Callable[])field.GetValue(c);
if (value != null && value.Length > 0)
{
rootNode.Children.Add(node);
// Add Callables from this Callable[] array
foreach (var call in value)
{
if (call != null)
node.Children.Add(GetCallableNode(call, stack));
else
AddErroneous(node.Target);
}
}
}
}
return rootNode;
}
else
{
return new CallTreeNode(c, GetType(c), $"RECURSED : {c.Name} ({c.gameObject.name} : {c.GetType().Name})");
}
}
CallTreeNode GetMessageNode(SendMessageAction msg, Stack<object> stack)
{
if (!stack.Contains(msg))
{
stack.Push(msg);
var rootNode = new CallTreeNode(msg, CallTreeNodeType.Message, $"{msg.MessageToSend} : ({msg.gameObject.name}.{msg.Name})");
var all = Resources.FindObjectsOfTypeAll<OnMessageEvent>().Where(o=> o.MessageName == msg.MessageToSend).ToList();
foreach(var evt in all)
{
rootNode.Children.Add(GetNode(evt, stack));
}
return rootNode;
}
else
{
return new CallTreeNode(msg, GetType(msg), $"RECURSED :{msg.MessageToSend} : ({msg.gameObject.name}.{msg.Name})");
}
}
CallTreeNode GetStateMachineNode(StateMachine sm, Stack<object> stack)
{
if (!stack.Contains(sm))
{
stack.Push(sm);
var rootNode = new CallTreeNode(sm, CallTreeNodeType.StateMachine, sm.gameObject.name);
var type = sm.GetType();
foreach (var field in type.GetFields())
{
// Find Fields that are State[]
if (field.FieldType.IsAssignableFrom(typeof(State[])))
{
// Add Callables from this Callable[] array
var value = (State[])field.GetValue(sm);
foreach (var state in value)
{
if (state != null)
rootNode.Children.Add(GetStateNode(state, stack));
else
AddErroneous(rootNode.Target);
}
}
}
return rootNode;
}
else
{
return new CallTreeNode(sm, GetType(sm), $"RECURSED :{sm.gameObject.name}");
}
}
CallTreeNode GetStateNode(State st, Stack<object> stack)
{
if (!stack.Contains(st))
{
stack.Push(st);
var rootNode = new CallTreeNode(st, CallTreeNodeType.State, st.gameObject.name);
var type = st.GetType();
foreach (var field in type.GetFields())
{
// Find Fields that are Callable[]
if (field.FieldType.IsAssignableFrom(typeof(Callable[])))
{
var node = new CallTreeNode(st, CallTreeNodeType.Callable, field.Name);
rootNode.Children.Add(node);
// Add Callables from this Callable[] array
var value = (Callable[])field.GetValue(st);
foreach (var call in value)
{
if (call != null)
node.Children.Add(GetNode(call, stack));
else
AddErroneous(rootNode.Target);
}
}
}
return rootNode;
}
else
{
return new CallTreeNode(st, GetType(st), $"RECURSED :{st.gameObject.name}");
}
}
CallTreeNodeType GetType(MonoBehaviour bhv)
{
if (bhv == null)
return CallTreeNodeType.Callable;
else if (bhv is EventBase)
return CallTreeNodeType.Event;
else if (bhv is LogicBase)
return CallTreeNodeType.Logic;
else if (bhv is ActionBase)
return CallTreeNodeType.Action;
else if (bhv is StateMachine)
return CallTreeNodeType.StateMachine;
else if (bhv is State)
return CallTreeNodeType.State;
else if (bhv is Factory)
return CallTreeNodeType.Factory;
else if (bhv is OnMessageEvent || bhv is SendMessageAction)
return CallTreeNodeType.Message;
else
return CallTreeNodeType.Callable;
}
class CallTreeNode
{
public string Name;
public MonoBehaviour Target;
public List<CallTreeNode> Children;
public CallTreeNodeType Type;
public CallTreeNode(MonoBehaviour target, CallTreeNodeType type, string name = "")
{
Name = string.IsNullOrEmpty(name) ? target.GetType().Name : name;
Target = target;
Type = type;
Children = new List<CallTreeNode>();
}
public bool Filter(GameObject go, string filter)
{
bool keep = (go == null || this.Target.gameObject == go)
&& (string.IsNullOrEmpty(filter) ? true : this.Name.Contains(filter));
if(!keep)
{
foreach (var node in Children)
keep = keep || node.Filter(go, filter);
}
return keep;
}
}
public enum CallTreeNodeType
{
Callable,
Event,
Logic,
Action,
Message,
StateMachine,
State,
Factory
}
class CallTreeView : TreeView
{
Dictionary<string, List<CallTreeNode>> m_Roots;
Dictionary<int, CallTreeNode> m_Bindings;
public CallTreeView(Dictionary<string, List<CallTreeNode>> roots) : base(new TreeViewState())
{
m_Roots = roots;
m_Bindings = new Dictionary<int, CallTreeNode>();
}
public string stringFilter { get { return m_StringFilter; } }
[SerializeField]
GameObject m_filter = null;
[SerializeField]
string m_StringFilter = "";
public bool AutoFilter { get; private set; }
public void ToggleAutoFilter()
{
SetAutoFilter(!AutoFilter);
}
public void SetAutoFilter(bool value)
{
AutoFilter = value;
if (AutoFilter)
{
Selection.selectionChanged += UpdateAutoFilter;
if(this.HasSelection())
{
SetObjectFilter(m_Bindings[this.GetSelection()[0]].Target.gameObject);
}
}
else
Selection.selectionChanged -= UpdateAutoFilter;
}
void UpdateAutoFilter()
{
if (Selection.activeGameObject != null)
SetObjectFilter(Selection.activeGameObject);
}
public void SetObjectFilter(GameObject filter = null)
{
m_filter = filter;
Reload();
}
public void SetStringFilter(string stringFilter)
{
m_StringFilter = stringFilter;
Reload();
}
protected override TreeViewItem BuildRoot()
{
int id = -1;
m_Bindings.Clear();
var treeRoot = new TreeViewItem(++id, -1, "~Root");
foreach(var kvp in m_Roots)
{
if (kvp.Value == null || kvp.Value.Count == 0)
continue;
var currentRoot = new TreeViewItem(++id, 0, kvp.Key);
treeRoot.AddChild(currentRoot);
foreach (var node in kvp.Value)
{
if (node.Filter(m_filter, m_StringFilter))
{
currentRoot.AddChild(GetNode(node, ref id, 1));
}
}
}
if (treeRoot.children == null)
{
treeRoot.AddChild(new TreeViewItem(1, 0, "(No Results)"));
}
return treeRoot;
}
TreeViewItem GetNode(CallTreeNode node, ref int id, int depth)
{
id++;
var item = new TreeViewItem(id, depth, $"{node.Name}");
item.icon = GetIcon(node.Target, node.Type);
m_Bindings.Add(id, node);
foreach(var child in node.Children)
{
item.AddChild(GetNode(child, ref id, depth + 1));
}
return item;
}
Texture2D GetIcon(MonoBehaviour bhv, CallTreeNodeType type)
{
if(bhv != null && type != CallTreeNodeType.Callable)
{
var texture = EditorGUIUtility.ObjectContent(bhv, bhv.GetType()).image;
if (texture != null)
return texture as Texture2D;
}
switch(type)
{
default:
case CallTreeNodeType.Callable:
return Styles.Callable;
case CallTreeNodeType.Action:
return Styles.Action;
case CallTreeNodeType.Logic:
return Styles.Logic;
case CallTreeNodeType.Event:
return Styles.Event;
case CallTreeNodeType.Message:
return Styles.Message;
case CallTreeNodeType.State:
return Styles.State;
case CallTreeNodeType.Factory:
return Styles.Factory;
case CallTreeNodeType.StateMachine:
return Styles.StateMachine;
}
}
protected override void SelectionChanged(IList<int> selectedIds)
{
if (AutoFilter)
return;
base.SelectionChanged(selectedIds);
if (selectedIds.Count > 0 && m_Bindings.ContainsKey(selectedIds[0]))
Selection.activeObject = m_Bindings[selectedIds[0]].Target;
}
public static class Styles
{
public static Texture2D Callable = Icon("Misc/ic-callable.png");
public static Texture2D Action = Icon("Actions/ic-action-generic.png");
public static Texture2D Logic = Icon("Logic/ic-generic-logic.png");
public static Texture2D Event = Icon("Events/ic-event-generic.png");
public static Texture2D Message = Icon("Events/ic-event-message .png");
public static Texture2D StateMachine = Icon("Misc/ic-StateMachine.png");
public static Texture2D State = Icon("Misc/ic-State.png");
public static Texture2D Factory = Icon("Misc/ic-Factory.png");
static Texture2D Icon(string path)
{
return AssetDatabase.LoadAssetAtPath<Texture2D>($"Packages/net.peeweek.gameplay-ingredients/Icons/{path}");
}
}
}
}
}

Просмотреть файл

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 446b3e7e2cf55584fa1555b54658d4ab
guid: 07aa515d40867f64686276ce5db0e51d
MonoImporter:
externalObjects: {}
serializedVersion: 2

Просмотреть файл

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b3467fc18385f3f41a4050759dc020e7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,46 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
namespace GameplayIngredients.Editor
{
[CustomEditor(typeof(Folder))]
public class FolderEditor : UnityEditor.Editor
{
[MenuItem("GameObject/Folder", false, 10)]
static void CreateFolder()
{
var go = new GameObject("Folder", typeof(Folder));
if(Selection.activeGameObject != null && Selection.activeGameObject.scene != null)
{
go.transform.parent = Selection.activeGameObject.transform;
}
}
SerializedProperty m_Color;
private void OnEnable()
{
m_Color = serializedObject.FindProperty("Color");
}
public override bool HasPreviewGUI()
{
return false;
}
public override void OnInspectorGUI()
{
EditorGUI.BeginChangeCheck();
var color = EditorGUILayout.ColorField("Folder Color", m_Color.colorValue);
if(EditorGUI.EndChangeCheck())
{
m_Color.colorValue = color;
serializedObject.ApplyModifiedProperties();
}
}
}
}

Просмотреть файл

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 483b9101733f40747b8c858a4e30c737
guid: 474b95a56281dc44483708a7186ba29d
MonoImporter:
externalObjects: {}
serializedVersion: 2

Просмотреть файл

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1654aa6a98f49614c87efd8f50c2785c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,68 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.Callbacks;
namespace GameplayIngredients.Editor
{
public class DiscoverAsset : ScriptableObject
{
[MenuItem("Assets/Create/Discover Asset", priority = 202)]
static void Create()
{
AssetFactory.CreateAssetInProjectWindow<DiscoverAsset>(null, "New DiscoverAsset.asset");
}
[OnOpenAsset]
static bool OpenAsset(int instanceID, int line)
{
var asset = EditorUtility.InstanceIDToObject(instanceID);
if (asset is DiscoverAsset)
{
DiscoverWindow.ShowDiscoverWindow(asset as DiscoverAsset);
return true;
}
else
return false;
}
[Header("General Properties")]
public string WindowTitle = "Discover";
public Texture2D HeaderTexture;
[Tooltip("Width of the Window, in pixels")]
public int WindowWidth = 640;
[Tooltip("Height of the Window, in pixels")]
public int WindowHeight = 520;
[Tooltip("Width of the Discover List, in pixels")]
public int DiscoverListWidth = 180;
[Header("Show At Startup")]
public bool EnableShowAtStartup = true;
[Tooltip("The name of the preference for auto showing at startup, will be ")]
public string PreferenceName = "Discover";
[Header("Content")]
public string Title = "Welcome!";
[Multiline]
public string Description = "This is a sample body for your discover window.";
[Header("Scenes")]
public DiscoverSceneInfo[] Scenes;
[Header("Debug")]
public bool Debug = false;
}
[System.Serializable]
public struct DiscoverSceneInfo
{
public string Title;
[Multiline]
public string Description;
public EditorSceneSetup[] SceneSetups;
public SceneAsset[] SingleScenes;
}
}

Просмотреть файл

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 99c49654b9bada340bfd165d70dc8296
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: e61da4d7fe9ddd647bd4fd18999ff0f0, type: 3}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,215 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEngine.Playables;
#if UNITY_2019_3_OR_NEWER
using UnityEngine.VFX;
#else
using UnityEngine.Experimental.VFX;
#endif
using UnityEngine.Timeline;
namespace GameplayIngredients.Editor
{
[CustomEditor(typeof(Discover))]
public class DiscoverEditor : UnityEditor.Editor
{
const string kEditPreferenceName = "GameplayIngredients.DiscoverEditor.Editing";
static bool editing
{
get { return EditorPrefs.GetBool(kEditPreferenceName, false); }
set { if (value != editing) EditorPrefs.SetBool(kEditPreferenceName, value); }
}
Discover m_Discover;
private void OnEnable()
{
m_Discover = serializedObject.targetObject as Discover;
if (m_Discover.transform.hideFlags != HideFlags.HideInInspector)
m_Discover.transform.hideFlags = HideFlags.HideInInspector;
}
public override void OnInspectorGUI()
{
using (new GUILayout.HorizontalScope())
{
if (GUILayout.Button("Align Discover to View"))
{
var transform = (serializedObject.targetObject as Discover).gameObject.transform;
var svTransform = SceneView.lastActiveSceneView.camera.transform;
transform.position = svTransform.position;
transform.rotation = svTransform.rotation;
transform.localScale = Vector3.one;
}
GUILayout.FlexibleSpace();
editing = GUILayout.Toggle(editing, "Edit", EditorStyles.miniButton, GUILayout.Width(48));
}
if (editing)
DrawDefaultInspector();
else
DrawDiscoverContentGUI(m_Discover);
}
public static void DrawDiscoverContentGUI(Discover discover)
{
if(!string.IsNullOrEmpty(discover.Category))
GUILayout.Label(discover.Category, DiscoverWindow.Styles.subHeader);
GUILayout.Label(discover.Name, DiscoverWindow.Styles.header);
using (new GUILayout.VerticalScope(DiscoverWindow.Styles.indent))
{
if (discover.Description != null && discover.Description != string.Empty)
{
GUILayout.Label(discover.Description, DiscoverWindow.Styles.body);
}
GUILayout.Space(8);
foreach (var section in discover.Sections)
{
SectionGUI(section);
GUILayout.Space(16);
}
}
}
public static void SectionGUI(DiscoverSection section)
{
using (new DiscoverWindow.GroupLabelScope(section.SectionName))
{
using (new GUILayout.VerticalScope(DiscoverWindow.Styles.slightIndent))
{
GUILayout.Label(section.SectionContent, DiscoverWindow.Styles.body);
if (section.Actions != null && section.Actions.Length > 0)
{
GUILayout.Space(8);
using (new GUILayout.VerticalScope(GUI.skin.box))
{
foreach (var action in section.Actions)
{
using (new GUILayout.HorizontalScope())
{
GUILayout.Label(action.Description);
GUILayout.FlexibleSpace();
using (new GUILayout.HorizontalScope(GUILayout.MinWidth(160), GUILayout.Height(22)))
{
ActionButtonGUI(action.Target);
}
}
}
}
}
}
}
}
static void ActionButtonGUI(UnityEngine.Object target)
{
if (target == null)
{
EditorGUI.BeginDisabledGroup(true);
GUILayout.Button("(No Object)");
EditorGUI.EndDisabledGroup();
return;
}
Type t = target.GetType();
if (t == typeof(GameObject))
{
GameObject go = target as GameObject;
if (GUILayout.Button(" Select ", DiscoverWindow.Styles.buttonLeft))
{
Selection.activeObject = go;
}
if(PrefabUtility.GetPrefabAssetType(go) == PrefabAssetType.NotAPrefab)
{
if (GUILayout.Button(" Go to ", DiscoverWindow.Styles.buttonRight))
{
Selection.activeObject = go;
SceneView.lastActiveSceneView.FrameSelected();
}
}
else
{
if (GUILayout.Button(" Open ", DiscoverWindow.Styles.buttonRight))
{
AssetDatabase.OpenAsset(go);
}
}
}
else if (t == typeof(Discover))
{
if (GUILayout.Button("Discover"))
{
var discover = target as Discover;
Selection.activeGameObject = discover.gameObject;
DiscoverWindow.SelectDiscover(discover);
}
}
else if (t == typeof(VisualEffectAsset))
{
if (GUILayout.Button("Open VFX Graph"))
{
VisualEffectAsset graph = target as VisualEffectAsset;
AssetDatabase.OpenAsset(graph);
}
}
else if (t == typeof(Animation))
{
if (GUILayout.Button("Open Animation"))
{
Animation animation = target as Animation;
AssetDatabase.OpenAsset(animation);
}
}
else if (t == typeof(TimelineAsset))
{
if (GUILayout.Button("Open Timeline"))
{
TimelineAsset timeline = target as TimelineAsset;
AssetDatabase.OpenAsset(timeline);
}
}
else if (t == typeof(PlayableDirector))
{
if (GUILayout.Button("Open Director"))
{
PlayableDirector director = target as PlayableDirector;
AssetDatabase.OpenAsset(director.playableAsset);
Selection.activeObject = director.gameObject;
}
}
else if (t == typeof(Shader))
{
if (GUILayout.Button("Open Shader"))
{
Shader shader = target as Shader;
AssetDatabase.OpenAsset(shader);
}
}
else
{
if (GUILayout.Button("Select"))
{
Selection.activeObject = target;
}
}
}
}
}

Просмотреть файл

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: ec5c4aa8c38a45743b935b39eceb9b44
guid: b1c258c43239c974080376d0bf372421
MonoImporter:
externalObjects: {}
serializedVersion: 2

Просмотреть файл

@ -0,0 +1,604 @@
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using System;
using UnityEngine.Experimental.VFX;
using UnityEngine.SceneManagement;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine.Timeline;
namespace GameplayIngredients.Editor
{
public class DiscoverWindow : EditorWindow
{
static List<DiscoverAsset> s_StartupDiscoverAssets;
static bool GetShowOnStartup(string name)
{
return EditorPrefs.GetBool($"{name}.ShowAtStartup", true);
}
static void SetShowOnStartup(string name, bool value)
{
if (value != GetShowOnStartup(name)) EditorPrefs.SetBool($"{name}.ShowAtStartup", value);
}
public static void SelectDiscover(Discover discover)
{
foreach(var window in s_Windows)
{
foreach(var categoryKvp in window.discoverObjects)
{
if (categoryKvp.Value.Contains(discover))
{
window.SetSelectedDiscover(discover);
break;
}
}
}
}
public static void Reload()
{
EditorApplication.update -= ShowAtStartup;
s_StartupDiscoverAssets = null;
InitShowAtStartup();
}
[InitializeOnLoadMethod]
static void InitShowAtStartup()
{
string[] guids = AssetDatabase.FindAssets("t:DiscoverAsset");
foreach (var guid in guids)
{
DiscoverAsset asset = AssetDatabase.LoadAssetAtPath<DiscoverAsset>(AssetDatabase.GUIDToAssetPath(guid));
if (asset.EnableShowAtStartup)
{
if (s_StartupDiscoverAssets == null)
s_StartupDiscoverAssets = new List<DiscoverAsset>();
s_StartupDiscoverAssets.Add(asset);
}
}
if (s_StartupDiscoverAssets != null && s_StartupDiscoverAssets.Count > 0)
EditorApplication.update += ShowAtStartup;
}
static void ShowAtStartup()
{
if (!Application.isPlaying && s_StartupDiscoverAssets != null)
{
foreach (var discoverAsset in s_StartupDiscoverAssets)
{
if (GetShowOnStartup(discoverAsset.PreferenceName))
ShowDiscoverWindow(discoverAsset);
}
}
EditorApplication.update -= ShowAtStartup;
}
static List<DiscoverWindow> s_Windows;
public static void ShowDiscoverWindow(DiscoverAsset discoverAsset)
{
if (discoverAsset != null)
{
var window = GetWindow<DiscoverWindow>(true);
window.SetDiscoverAsset(discoverAsset);
}
else
{
Debug.LogError("Could not open Discover Window : discoverAsset is null");
}
}
public DiscoverAsset discoverAsset { get; private set; }
Texture2D header;
bool forceGlobal;
void SetDiscoverAsset(DiscoverAsset discover)
{
discoverAsset = discover;
titleContent = new GUIContent(discoverAsset.WindowTitle);
minSize = new Vector2(discoverAsset.WindowWidth, discoverAsset.WindowHeight);
maxSize = new Vector2(discoverAsset.WindowWidth, discoverAsset.WindowHeight);
}
private void OnEnable()
{
UpdateDiscoverObjects();
EditorSceneManager.newSceneCreated += UpdateDiscoverObjectsOnCreate;
EditorSceneManager.sceneOpened += UpdateDiscoverObjectsOnLoad;
EditorSceneSetup.onSetupLoaded += UpdateDiscoverObjectsOnLoadSetup;
if (s_Windows == null)
s_Windows = new List<DiscoverWindow>();
if(!s_Windows.Contains(this))
s_Windows.Add(this);
}
private void OnDisable()
{
EditorSceneManager.newSceneCreated -= UpdateDiscoverObjectsOnCreate;
EditorSceneManager.sceneOpened -= UpdateDiscoverObjectsOnLoad;
EditorSceneSetup.onSetupLoaded -= UpdateDiscoverObjectsOnLoadSetup;
if (s_Windows.Contains(this))
s_Windows.Remove(this);
}
Dictionary<string, List<Discover>> discoverObjects = null;
void UpdateDiscoverObjectsOnLoadSetup(EditorSceneSetup setup)
{
forceGlobal = false;
UpdateDiscoverObjects();
}
void UpdateDiscoverObjectsOnCreate(Scene scene, NewSceneSetup setup, NewSceneMode mode)
{
forceGlobal = false;
UpdateDiscoverObjects();
}
void UpdateDiscoverObjectsOnLoad(Scene s, OpenSceneMode s2)
{
forceGlobal = false;
UpdateDiscoverObjects();
}
void UpdateDiscoverObjects(bool clear = false)
{
if (discoverObjects == null)
discoverObjects = new Dictionary<string, List<Discover>>();
if (clear)
discoverObjects.Clear();
Discover[] newOnes = FindObjectsOfType<Discover>();
// Add new ones
foreach (var item in newOnes)
{
if (!discoverObjects.ContainsKey(item.Category))
{
discoverObjects.Add(item.Category, new List<Discover>());
}
if (!discoverObjects[item.Category].Contains(item))
{
discoverObjects[item.Category].Add(item);
}
}
// Cleanup Empty Entries
Dictionary<string, List<Discover>> cleanedUpLists = new Dictionary<string, List<Discover>>();
foreach (var categoryKvp in discoverObjects)
{
cleanedUpLists.Add(categoryKvp.Key, categoryKvp.Value.Where((o) => o != null).ToList());
}
foreach (var categoryKvp in cleanedUpLists)
{
discoverObjects[categoryKvp.Key] = categoryKvp.Value;
}
// Cleanup Empty Categories
List<string> toDelete = new List<string>();
foreach (var categoryKvp in discoverObjects)
{
if (categoryKvp.Value == null || categoryKvp.Value.Count == 0)
toDelete.Add(categoryKvp.Key);
}
foreach (var category in toDelete)
{
discoverObjects.Remove(category);
}
// Finally, sort items in each category
foreach (var categoryKvp in discoverObjects)
{
discoverObjects[categoryKvp.Key].Sort((a, b) => { return Comparer<int>.Default.Compare(a.Priority, b.Priority); });
}
// Ensure something is selected is possible
if (selectedDiscover == null) // Try Fetching a default
{
foreach (var categoryKvp in discoverObjects)
{
selectedDiscover = categoryKvp.Value.FirstOrDefault(o => o.DefaultSelected == true);
if (selectedDiscover != null)
break;
}
}
if (selectedDiscover == null && discoverObjects != null && discoverObjects.Count > 0)
{
selectedDiscover = discoverObjects.First().Value.First();
}
Repaint();
}
private void OnGUI()
{
// Draw Header Image
if (discoverAsset.HeaderTexture != null)
{
if (header == null || header != discoverAsset.HeaderTexture)
header = discoverAsset.HeaderTexture;
Rect headerRect = GUILayoutUtility.GetRect(header.width, header.height);
GUI.DrawTexture(headerRect, header);
}
else
{
Rect headerRect = GUILayoutUtility.GetRect(discoverAsset.WindowWidth, 80);
EditorGUI.DrawRect(headerRect, new Color(0,0,0,0.2f));
headerRect.xMin += 16;
headerRect.yMin += 16;
GUI.Label(headerRect, discoverAsset.WindowTitle, Styles.header);
}
bool hasContent = discoverObjects != null && discoverObjects.Count > 0;
// Draw Navigation Bar
EditorGUI.BeginDisabledGroup(!hasContent);
using (new GUILayout.AreaScope(new Rect(discoverAsset.WindowWidth - 168, 8, 160, 20)))
{
using (new GUILayout.HorizontalScope(Styles.tabContainer))
{
bool value = forceGlobal;
EditorGUI.BeginChangeCheck();
value = GUILayout.Toggle(forceGlobal || !hasContent, "Levels", Styles.buttonLeft);
if (EditorGUI.EndChangeCheck())
{
forceGlobal = true;
}
EditorGUI.BeginChangeCheck();
value = GUILayout.Toggle(!forceGlobal && hasContent, "Discover", Styles.buttonRight);
if (EditorGUI.EndChangeCheck())
{
forceGlobal = false;
}
}
}
EditorGUI.EndDisabledGroup();
// Draw Content
if (!hasContent || forceGlobal)
GlobalContentGUI();
else
SceneContentGUI();
// Draw Footer
Rect line = GUILayoutUtility.GetRect(discoverAsset.WindowWidth, 1);
EditorGUI.DrawRect(line, Color.black);
using (new GUILayout.HorizontalScope())
{
if(discoverAsset.EnableShowAtStartup)
{
EditorGUI.BeginChangeCheck();
bool showOnStartup = GUILayout.Toggle(GetShowOnStartup(discoverAsset.PreferenceName), " Show this window on startup");
if (EditorGUI.EndChangeCheck())
{
SetShowOnStartup(discoverAsset.PreferenceName, showOnStartup);
}
}
GUILayout.FlexibleSpace();
if(discoverAsset.Debug)
{
if (GUILayout.Button("Select DiscoverAsset"))
Selection.activeObject = discoverAsset;
if (GUILayout.Button("Reload"))
UpdateDiscoverObjects(true);
}
if (GUILayout.Button("Close"))
{
Close();
}
}
}
Vector2 globalContentScroll;
void GlobalContentGUI()
{
globalContentScroll = GUILayout.BeginScrollView(globalContentScroll);
using (new GUILayout.VerticalScope(Styles.indent))
{
GUILayout.Label(discoverAsset.Title, Styles.header);
using (new GUILayout.VerticalScope(Styles.indent))
{
GUILayout.Label(discoverAsset.Description, Styles.body);
if(discoverAsset.Scenes != null)
{
foreach (var map in discoverAsset.Scenes)
{
using (new GroupLabelScope(map.Title))
{
GUILayout.Label(map.Description, Styles.body);
using (new GUILayout.HorizontalScope())
{
GUILayout.FlexibleSpace();
if (map.SceneSetups != null)
{
foreach(var sceneSetup in map.SceneSetups)
{
if (sceneSetup != null && GUILayout.Button($"Open {sceneSetup.name}"))
LoadSceneSetup(sceneSetup);
}
}
if(map.SingleScenes != null)
{
foreach(var singleScene in map.SingleScenes)
{
if (singleScene != null && GUILayout.Button($"Open {singleScene.name}"))
LoadSingleScene(singleScene);
}
}
}
}
}
}
}
}
GUILayout.FlexibleSpace();
GUILayout.EndScrollView();
}
Discover selectedDiscover;
Vector2 listScroll;
Vector2 contentScroll;
void SceneContentGUI()
{
using (new GUILayout.HorizontalScope())
{
using (new GUILayout.VerticalScope())
{
listScroll = GUILayout.BeginScrollView(listScroll, GUI.skin.box, GUILayout.Width(discoverAsset.DiscoverListWidth));
using (new GUILayout.VerticalScope(GUILayout.ExpandHeight(true)))
{
foreach (var category in discoverObjects.Keys.OrderBy((x) => x.ToString()))
{
if(!string.IsNullOrEmpty(category))
GUILayout.Label(category, EditorStyles.boldLabel);
foreach (var item in discoverObjects[category])
{
EditorGUI.BeginChangeCheck();
bool value = GUILayout.Toggle(item == selectedDiscover, item.Name, Styles.listItem);
if (value)
{
// Select the new one if not selected
if(selectedDiscover != item)
{
if (EditorGUI.EndChangeCheck())
{
if (discoverAsset.Debug)
Selection.activeObject = item;
SetSelectedDiscover(item);
}
}
Rect r = GUILayoutUtility.GetLastRect();
int c = EditorGUIUtility.isProSkin ? 1 : 0;
EditorGUI.DrawRect(r, new Color(c, c, c, 0.1f));
}
}
}
GUILayout.FlexibleSpace();
}
GUILayout.EndScrollView();
}
GUILayout.Space(4);
using (new GUILayout.VerticalScope(GUILayout.Width(440)))
{
contentScroll = GUILayout.BeginScrollView(contentScroll);
GUILayout.Space(8);
DiscoverEditor.DrawDiscoverContentGUI(selectedDiscover);
GUILayout.FlexibleSpace();
GUILayout.EndScrollView();
}
}
}
void SetSelectedDiscover(Discover newSelection)
{
if (SceneView.lastActiveSceneView != null && newSelection.AlignViewToTransform)
{
SceneView.lastActiveSceneView.AlignViewToObject(newSelection.transform);
}
if (selectedDiscover.ObjectsToToggle != null)
{
// Reverse Toggle previous GameObjects state
foreach (var go in selectedDiscover.ObjectsToToggle)
{
if (go.GameObject == null)
continue;
switch (go.State)
{
case Actions.ToggleGameObjectAction.GameObjectToggle.GameObjectToggleState.Disable:
go.GameObject.SetActive(true);
break;
case Actions.ToggleGameObjectAction.GameObjectToggle.GameObjectToggleState.Enable:
go.GameObject.SetActive(false);
break;
case Actions.ToggleGameObjectAction.GameObjectToggle.GameObjectToggleState.Toggle:
go.GameObject.SetActive(go.GameObject.activeSelf);
break;
}
}
}
// Set the new item
selectedDiscover = newSelection;
if (selectedDiscover.ObjectsToToggle != null)
{
// Toggle Next GameObjects State
foreach (var go in selectedDiscover.ObjectsToToggle)
{
if (go.GameObject == null)
continue;
switch (go.State)
{
case Actions.ToggleGameObjectAction.GameObjectToggle.GameObjectToggleState.Disable:
go.GameObject.SetActive(false);
break;
case Actions.ToggleGameObjectAction.GameObjectToggle.GameObjectToggleState.Enable:
go.GameObject.SetActive(true);
break;
case Actions.ToggleGameObjectAction.GameObjectToggle.GameObjectToggleState.Toggle:
go.GameObject.SetActive(go.GameObject.activeSelf);
break;
}
}
}
contentScroll = Vector2.zero;
}
void LoadSceneSetup(EditorSceneSetup setup)
{
try
{
EditorUtility.DisplayProgressBar("Discover", $"Opening {setup.name}...", 0.9f);
forceGlobal = false;
EditorSceneSetup.RestoreSetup(setup);
}
catch
{
Debug.LogError($"Could not load EditorSceneSetup : {setup.name}");
}
finally
{
EditorUtility.ClearProgressBar();
UpdateDiscoverObjects();
}
}
void LoadSingleScene(SceneAsset scene)
{
try
{
EditorUtility.DisplayProgressBar("Discover", $"Opening {scene.name}...", 0.9f);
forceGlobal = false;
EditorSceneManager.OpenScene(AssetDatabase.GetAssetPath(scene), OpenSceneMode.Single);
}
catch
{
Debug.LogError($"Could not load Scene : {scene.name}");
}
finally
{
EditorUtility.ClearProgressBar();
UpdateDiscoverObjects();
}
}
public class GroupLabelScope : GUILayout.VerticalScope
{
public GroupLabelScope(string name) : base(Styles.box)
{
if(!string.IsNullOrWhiteSpace(name))
{
GUIContent n = new GUIContent(name);
Rect r = GUILayoutUtility.GetRect(n, Styles.boxHeader, GUILayout.ExpandWidth(true));
GUI.Label(r, n, Styles.boxHeader);
}
}
}
public static class Styles
{
public static GUIStyle indent;
public static GUIStyle slightIndent;
public static GUIStyle header;
public static GUIStyle subHeader;
public static GUIStyle body;
public static GUIStyle box;
public static GUIStyle boxHeader;
public static GUIStyle listItem;
public static GUIStyle buttonLeft;
public static GUIStyle buttonMid;
public static GUIStyle buttonRight;
public static GUIStyle tabContainer;
static Styles()
{
header = new GUIStyle(EditorStyles.wordWrappedLabel);
header.fontSize = 24;
header.padding = new RectOffset(0, 0, -4, -4);
header.richText = true;
subHeader = new GUIStyle(EditorStyles.wordWrappedLabel);
subHeader.fontSize = 11;
subHeader.fontStyle = FontStyle.Italic;
body = new GUIStyle(EditorStyles.wordWrappedLabel);
body.fontSize = 11;
body.richText = true;
indent = new GUIStyle();
indent.padding = new RectOffset(12, 12, 12, 12);
slightIndent = new GUIStyle();
slightIndent.padding = new RectOffset(6, 6, 0, 6);
box = new GUIStyle(EditorStyles.helpBox);
boxHeader = new GUIStyle(GUI.skin.box);
boxHeader.normal.textColor = GUI.skin.label.normal.textColor;
boxHeader.fixedHeight = 20;
boxHeader.fontSize = 11;
boxHeader.fontStyle = FontStyle.Bold;
boxHeader.alignment = TextAnchor.UpperLeft;
boxHeader.margin = new RectOffset(0, 0, 0, 6);
listItem = new GUIStyle(EditorStyles.label);
listItem.padding = new RectOffset(12, 0, 2, 2);
buttonLeft = new GUIStyle(EditorStyles.miniButtonLeft);
buttonLeft.fontSize = 11;
buttonMid = new GUIStyle(EditorStyles.miniButtonMid);
buttonMid.fontSize = 11;
buttonRight = new GUIStyle(EditorStyles.miniButtonRight);
buttonRight.fontSize = 11;
tabContainer = new GUIStyle(EditorStyles.miniButton);
tabContainer.padding = new RectOffset(4, 4, 0, 0);
}
}
}
}

Просмотреть файл

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6206e16563e844a4f897a8cc92efc86a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: da253dff53554a5498211c4caae380cc
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,108 @@
using UnityEngine;
using UnityEditor;
using UnityEngine.SceneManagement;
using UnityEditor.SceneManagement;
using UnityEditor.Callbacks;
namespace GameplayIngredients.Editor
{
public class EditorSceneSetup : ScriptableObject
{
[MenuItem("File/Save Scene Setup As... #%&S", priority = 171)]
static void SaveSetup()
{
string path = EditorUtility.SaveFilePanelInProject("Save EditorSceneSetup", "New EditorSceneSetup", "asset", "Save EditorSceneSetup?");
if(path != string.Empty)
{
EditorSceneSetup setup = GetCurrentSetup();
AssetDatabase.CreateAsset(setup, path);
}
}
public delegate void EditorSceneSetupLoadedDelegate(EditorSceneSetup setup);
public static event EditorSceneSetupLoadedDelegate onSetupLoaded;
[OnOpenAsset]
static bool OnOpenAsset(int instanceID, int line)
{
var obj = EditorUtility.InstanceIDToObject(instanceID);
if(obj is EditorSceneSetup)
{
EditorSceneSetup setup = (EditorSceneSetup)obj;
int active = setup.ActiveScene;
try
{
EditorUtility.DisplayProgressBar("Loading Scenes", string.Format("Loading Scene Setup {0}....", setup.name), 1.0f);
RestoreSetup(setup);
}
finally
{
EditorUtility.ClearProgressBar();
}
return true;
}
return false;
}
[MenuItem("Assets/Create/Editor Scene Setup", priority = 200)]
static void CreateAsset()
{
AssetFactory.CreateAssetInProjectWindow<EditorSceneSetup>("SceneSet Icon", "New SceneSetup.asset");
}
public int ActiveScene;
public EditorScene[] LoadedScenes;
[System.Serializable]
public struct EditorScene
{
public SceneAsset Scene;
public bool Loaded;
}
public static EditorSceneSetup GetCurrentSetup()
{
var scenesetups = EditorSceneManager.GetSceneManagerSetup();
var editorSetup = CreateInstance<EditorSceneSetup>();
int i = 0;
editorSetup.LoadedScenes = new EditorScene[scenesetups.Length];
foreach(var setup in scenesetups)
{
if (setup.isActive)
editorSetup.ActiveScene = i;
editorSetup.LoadedScenes[i].Scene = AssetDatabase.LoadAssetAtPath<SceneAsset>(setup.path);
editorSetup.LoadedScenes[i].Loaded = setup.isLoaded;
i++;
}
return editorSetup;
}
public static void RestoreSetup(EditorSceneSetup editorSetup)
{
SceneSetup[] setups = new SceneSetup[editorSetup.LoadedScenes.Length];
for(int i = 0; i < setups.Length; i++)
{
setups[i] = new SceneSetup();
string path = AssetDatabase.GetAssetPath(editorSetup.LoadedScenes[i].Scene);
setups[i].path = path;
setups[i].isLoaded = editorSetup.LoadedScenes[i].Loaded;
setups[i].isActive = (editorSetup.ActiveScene == i);
}
EditorSceneManager.RestoreSceneManagerSetup(setups);
if(onSetupLoaded != null)
onSetupLoaded.Invoke(editorSetup);
}
}
}

Просмотреть файл

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8bf8857f1af056d4894bee553e091ceb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 5498606499726036565, guid: 0000000000000000d000000000000000, type: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,88 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
using System;
namespace GameplayIngredients.Editor
{
[CustomEditor(typeof(EditorSceneSetup))]
public class EditorSceneSetupEditor : UnityEditor.Editor
{
ReorderableList m_List;
SerializedProperty m_LoadedScenes;
SerializedProperty m_ActiveScene;
private void OnEnable()
{
m_ActiveScene = serializedObject.FindProperty("ActiveScene");
m_LoadedScenes = serializedObject.FindProperty("LoadedScenes");
m_List = new ReorderableList(serializedObject, m_LoadedScenes, true, true, true, true);
m_List.drawElementCallback = OnDrawElement;
m_List.drawHeaderCallback = OnDrawHeader;
}
private void OnDrawHeader(Rect rect)
{
GUI.Label(rect, "Scene List");
}
private void OnDrawElement(Rect rect, int index, bool isActive, bool isFocused)
{
var toggleRect = rect;
toggleRect.width = 16;
toggleRect.yMin += 2;
var sceneRect = rect;
sceneRect.xMin += 24;
sceneRect.xMax -= 80;
sceneRect.yMin += 2;
sceneRect.height = 16;
var loadedRect = rect;
loadedRect.xMin = rect.xMax - 80;
loadedRect.yMin += 2;
bool active = m_ActiveScene.intValue == index;
bool newActive = GUI.Toggle(toggleRect, active, GUIContent.none);
if(GUI.changed && newActive != active)
{
m_ActiveScene.intValue = index;
}
var sceneAsset = (SceneAsset)EditorGUI.ObjectField(sceneRect, m_LoadedScenes.GetArrayElementAtIndex(index).FindPropertyRelative("Scene").objectReferenceValue, typeof(SceneAsset), false);
if (GUI.changed)
{
m_LoadedScenes.GetArrayElementAtIndex(index).FindPropertyRelative("Scene").objectReferenceValue = sceneAsset;
}
EditorGUI.BeginDisabledGroup(index == 0);
int visible = m_LoadedScenes.GetArrayElementAtIndex(index).FindPropertyRelative("Loaded").boolValue ? 1 : 0;
visible = EditorGUI.IntPopup(loadedRect, visible, kLoadedItems, kLoadedIndices);
if(GUI.changed)
{
m_LoadedScenes.GetArrayElementAtIndex(index).FindPropertyRelative("Loaded").boolValue = visible == 1 ? true : false;
} else if(index == 0)
{
m_LoadedScenes.GetArrayElementAtIndex(index).FindPropertyRelative("Loaded").boolValue = true;
}
EditorGUI.EndDisabledGroup();
serializedObject.ApplyModifiedProperties();
}
static readonly int[] kLoadedIndices = new int[2] { 0, 1 };
static readonly GUIContent[] kLoadedItems = new GUIContent[2] { new GUIContent("Not Loaded"), new GUIContent("Loaded") };
public override void OnInspectorGUI()
{
m_List.DoLayoutList();
}
}
}

Просмотреть файл

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a0875758aceaa3a4b96c65bf4fb85f50
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 869fd8f9cbfa0cd468609db02f580990
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,462 @@
using System.Reflection;
using System;
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEditor;
using UnityEditor.IMGUI.Controls;
namespace GameplayIngredients.Editor
{
public class FindAndReplaceWindow : EditorWindow
{
[MenuItem("Edit/Find And Replace... %&#F", priority = 144)]
static void OpenWindow()
{
GetWindow<FindAndReplaceWindow>();
}
static readonly Dictionary<string, Type> s_assemblyTypes = GetTypes();
private static Dictionary<string, Type> GetTypes()
{
Dictionary<string, Type> all = new Dictionary<string, Type>();
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (Type t in assembly.GetTypes())
{
if (typeof(Component).IsAssignableFrom(t) && !all.ContainsKey(t.Name))
all.Add(t.Name, t);
}
}
return all;
}
public enum SearchBy
{
Name,
ComponentType,
Tag,
Layer,
Mesh,
Material,
Selection
}
private void OnEnable()
{
titleContent = Contents.title;
minSize = new Vector2(640, 280);
}
private void OnGUI()
{
using (new GUILayout.HorizontalScope())
{
using (new GUILayout.VerticalScope(GUILayout.Width(320)))
{
SearchControlsGUI();
}
using (new GUILayout.VerticalScope(GUILayout.Width(4)))
{
GUILayout.FlexibleSpace();
Rect r = GUILayoutUtility.GetLastRect();
EditorGUI.DrawRect(r, Color.black);
}
using (new GUILayout.VerticalScope())
{
SearchResultsGUI();
}
}
}
[SerializeField]
GameObject prefabReplacement;
[SerializeField]
SearchBy searchBy;
[SerializeField]
string nameSearch = "GameObject";
[SerializeField]
string tagSearch = "Player";
[SerializeField]
string layerSearch = "PostProcessing";
[SerializeField]
string componentSearch = "Light";
[SerializeField]
Mesh meshSearch;
[SerializeField]
Material materialSearch;
[SerializeField]
bool selectionRecurse = false;
[SerializeField]
bool keepPosition = true;
[SerializeField]
bool keepRotation = true;
[SerializeField]
bool keepScale = false;
[SerializeField]
bool keepParenting = true;
[SerializeField]
bool keepName = true;
[SerializeField]
bool keepTag = false;
[SerializeField]
bool keepLayer = true;
[SerializeField]
bool keepStatic = false;
[SerializeField]
bool unpackPrefab = false;
enum SearchOp
{
Find,
Add,
Refine
}
void SearchControlsGUI()
{
EditorGUIUtility.labelWidth = 120;
GUILayout.Space(4);
GUILayout.Label("Search Scene Objects", Styles.boldLabel);
searchBy = (SearchBy)EditorGUILayout.EnumPopup(Contents.criteria, searchBy);
switch (searchBy)
{
case SearchBy.Name:
nameSearch = EditorGUILayout.TextField(Contents.nameSearch, nameSearch);
SearchButtonsGUI(searchBy, nameSearch);
break;
case SearchBy.Tag:
tagSearch = EditorGUILayout.TextField(Contents.tagSearch, tagSearch);
SearchButtonsGUI(searchBy, tagSearch);
break;
case SearchBy.Layer:
layerSearch = EditorGUILayout.TextField(Contents.layerSearch, layerSearch);
SearchButtonsGUI(searchBy, layerSearch);
break;
case SearchBy.ComponentType:
componentSearch = EditorGUILayout.TextField(Contents.componentSearch, componentSearch);
SearchButtonsGUI(searchBy, componentSearch);
break;
case SearchBy.Mesh:
meshSearch = (Mesh)EditorGUILayout.ObjectField(Contents.meshSearch, meshSearch, typeof(Mesh), true);
SearchButtonsGUI(searchBy, meshSearch);
break;
case SearchBy.Material:
materialSearch = (Material)EditorGUILayout.ObjectField(Contents.materialSearch, materialSearch, typeof(Material), true);
SearchButtonsGUI(searchBy, materialSearch);
break;
case SearchBy.Selection:
selectionRecurse = EditorGUILayout.Toggle(Contents.selectionRecurse, selectionRecurse);
SearchButtonsGUI(searchBy, selectionRecurse);
break;
}
GUILayout.FlexibleSpace();
GUILayout.Label("Replace Results", Styles.boldLabel);
prefabReplacement = (GameObject)EditorGUILayout.ObjectField(Contents.prefabReplacement, prefabReplacement, typeof(GameObject), true);
if (prefabReplacement != null)
{
PrefabAssetType type = PrefabUtility.GetPrefabAssetType(prefabReplacement);
bool isAPrefab = type == PrefabAssetType.Model || type == PrefabAssetType.Regular || type == PrefabAssetType.Variant;
if(isAPrefab)
unpackPrefab = EditorGUILayout.Toggle("Unpack Prefab", unpackPrefab);
}
EditorGUI.BeginDisabledGroup(prefabReplacement == null);
GUILayout.Label("Keep Properties from Original:");
using (new GUILayout.HorizontalScope())
{
keepPosition = GUILayout.Toggle(keepPosition, "Position", EditorStyles.miniButtonLeft, GUILayout.Height(16));
keepRotation = GUILayout.Toggle(keepRotation, "Rotation", EditorStyles.miniButtonMid, GUILayout.Height(16));
keepScale = GUILayout.Toggle(keepScale, "Scale", EditorStyles.miniButtonMid, GUILayout.Height(16));
keepParenting = GUILayout.Toggle(keepParenting, "Parenting", EditorStyles.miniButtonRight, GUILayout.Height(16));
}
using (new GUILayout.HorizontalScope())
{
keepName = GUILayout.Toggle(keepName, "Name", EditorStyles.miniButtonLeft, GUILayout.Height(16));
keepTag = GUILayout.Toggle(keepTag, "Tag", EditorStyles.miniButtonMid, GUILayout.Height(16));
keepLayer = GUILayout.Toggle(keepLayer, "Layer", EditorStyles.miniButtonMid, GUILayout.Height(16));
keepStatic = GUILayout.Toggle(keepStatic, "Static", EditorStyles.miniButtonRight, GUILayout.Height(16));
}
if (GUILayout.Button("Replace All", Styles.bigButton, GUILayout.Height(24)) && prefabReplacement != null)
{
Undo.RecordObjects(searchResults.ToArray(), "Replace Objects");
for(int i = 0; i < searchResults.Count; i++)
{
var obj = searchResults[i];
var newObj = SwapObject(obj, prefabReplacement, searchResults);
searchResults[i] = newObj;
}
}
EditorGUI.EndDisabledGroup();
GUILayout.Space(8);
}
GameObject SwapObject(GameObject toReplace, GameObject replacement, List<GameObject> others)
{
GameObject newObj;
if (PrefabUtility.GetPrefabAssetType(replacement) != PrefabAssetType.NotAPrefab && !unpackPrefab)
newObj = (GameObject)PrefabUtility.InstantiatePrefab(replacement);
else
newObj = Instantiate(replacement);
if (keepName)
newObj.name = toReplace.name;
if(keepPosition)
newObj.transform.position = toReplace.transform.position;
if(keepRotation)
newObj.transform.rotation = toReplace.transform.rotation;
if(keepParenting)
newObj.transform.parent = toReplace.transform.parent;
if(keepScale)
newObj.transform.localScale = toReplace.transform.localScale;
if(keepTag)
newObj.tag = toReplace.tag;
if(keepLayer)
newObj.layer = toReplace.layer;
if(keepStatic)
newObj.isStatic = toReplace.isStatic;
foreach(var other in others)
{
if(other.transform.parent == toReplace.transform)
{
other.transform.parent = newObj.transform;
}
}
DestroyImmediate(toReplace);
return newObj;
}
void SearchButtonsGUI(SearchBy by, object criteria)
{
using (new GUILayout.HorizontalScope())
{
if (GUILayout.Button("Find", Styles.bigButton, GUILayout.Height(24)))
Search(SearchOp.Find, by, criteria);
if (GUILayout.Button("Add", Styles.bigButton, GUILayout.Height(24)))
Search(SearchOp.Add, by, criteria);
if (GUILayout.Button("Refine", Styles.bigButton, GUILayout.Height(24)))
Search(SearchOp.Refine, by, criteria);
}
}
static GameObject[] FindAllSceneObjects()
{
var all = Resources.FindObjectsOfTypeAll<GameObject>();
all = all.Where(o => o.scene.isLoaded).ToArray();
return all;
}
void Search(SearchOp op, SearchBy by, object criteria)
{
List<GameObject> query = new List<GameObject>();
var all = FindAllSceneObjects();
switch (by)
{
case SearchBy.Name:
foreach(var go in all)
{
if (go.name.Contains((string)criteria))
query.Add(go);
}
break;
case SearchBy.Tag:
query.AddRange(GameObject.FindGameObjectsWithTag((string)criteria));
break;
case SearchBy.Layer:
foreach (var go in all)
{
if (go.layer == LayerMask.NameToLayer((string)criteria))
query.Add(go);
}
break;
case SearchBy.ComponentType:
if(s_assemblyTypes.ContainsKey((string)criteria))
{
Type t = s_assemblyTypes[(string)criteria];
if( typeof(Component).IsAssignableFrom(t))
{
Component[] components = (Component[])Resources.FindObjectsOfTypeAll(t);
if(components != null)
{
foreach(var c in components)
{
if (c.gameObject.scene != null && !query.Contains(c.gameObject))
query.Add(c.gameObject);
}
}
}
}
break;
case SearchBy.Mesh:
Mesh mesh = (Mesh)criteria;
foreach (var go in all)
{
MeshFilter filter = go.GetComponent<MeshFilter>();
if (filter != null && filter.sharedMesh == mesh)
{
query.Add(go);
}
}
break;
case SearchBy.Material:
Material mat = (Material)criteria;
foreach (var go in all)
{
Renderer renderer = go.GetComponent<Renderer>();
if (renderer != null)
{
if(renderer.sharedMaterials.Contains(mat))
{
query.Add(go);
}
}
}
break;
case SearchBy.Selection:
foreach(var selected in Selection.gameObjects)
{
bool recurse = (bool)criteria;
if(!recurse)
query.Add(selected);
else
query.AddRange(selected.GetAllChildren());
}
break;
}
switch (op)
{
case SearchOp.Find:
searchResults = query;
break;
case SearchOp.Add:
foreach(var item in query)
{
if (!searchResults.Contains(item))
searchResults.Add(item);
}
break;
case SearchOp.Refine:
List<GameObject> refined = new List<GameObject>();
foreach (var item in searchResults)
{
if (query.Contains(item))
refined.Add(item);
}
searchResults = refined;
break;
}
}
[SerializeField]
List<GameObject> searchResults= new List<GameObject>();
Vector2 scroll;
void SearchResultsGUI()
{
using (new GUILayout.HorizontalScope())
{
GUILayout.Label("Search Results", Styles.boldLabel);
GUILayout.FlexibleSpace();
if(GUILayout.Button("Select in Scene", GUILayout.Height(24)))
{
Selection.objects = searchResults.ToArray();
}
if(GUILayout.Button("Clear", GUILayout.Height(24)))
{
searchResults.Clear();
}
}
scroll = GUILayout.BeginScrollView(scroll, EditorStyles.helpBox);
{
GameObject toRemove = null;
// Trim all nulls
searchResults = searchResults.Where(o => o != null).ToList();
foreach(var obj in searchResults)
{
using (new GUILayout.HorizontalScope(EditorStyles.textField))
{
GUILayout.Label(obj.name, EditorStyles.label);
if(GUILayout.Button("X", GUILayout.Width(32)))
{
toRemove = obj;
}
}
}
if (toRemove != null)
searchResults.Remove(toRemove);
}
GUILayout.EndScrollView();
}
static class Contents
{
public static GUIContent title = new GUIContent("Find and Replace", (Texture)EditorGUIUtility.LoadRequired("ViewToolZoom On"));
public static GUIContent criteria = new GUIContent("Criteria");
public static GUIContent nameSearch = new GUIContent("GameObject Name");
public static GUIContent tagSearch = new GUIContent("Tag");
public static GUIContent layerSearch = new GUIContent("Layer");
public static GUIContent componentSearch = new GUIContent("Component Type");
public static GUIContent meshSearch = new GUIContent("Mesh");
public static GUIContent materialSearch = new GUIContent("Material");
public static GUIContent selectionRecurse = new GUIContent("Include Children");
public static GUIContent prefabReplacement = new GUIContent("Prefab Replacement");
}
static class Styles
{
public static readonly GUIStyle boldLabel = GetBoldLabel();
public static readonly GUIStyle bigButton = GetBigButton();
static GUIStyle GetBoldLabel()
{
var style = new GUIStyle(EditorStyles.boldLabel);
style.fontSize = 14;
return style;
}
static GUIStyle GetBigButton()
{
var style = new GUIStyle(EditorStyles.miniButton);
style.fontSize = 14;
return style;
}
}
}
}

Просмотреть файл

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2ee173722a41c4c4c8388b7206e59a83
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0b748787917f8d7459fa7973629a9afe
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,203 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
namespace GameplayIngredients.Editor
{
public static class LinkGameView
{
static readonly string kPreferenceName = "GameplayIngredients.LinkGameView";
static readonly string kLinkCameraName = "___LINK__SCENE__VIEW__CAMERA___";
public static bool Active
{
get
{
// Get preference only when not playing
if (!Application.isPlaying)
m_Active = EditorPrefs.GetBool(kPreferenceName, false);
return m_Active;
}
set
{
// Update preference only when not playing
if(!Application.isPlaying)
EditorPrefs.SetBool(kPreferenceName, value);
m_Active = value;
if(s_GameObject != null)
s_GameObject.SetActive(value);
UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
}
}
static bool m_Active = false;
public static SceneView LockedSceneView
{
get
{
return s_LockedSceneView;
}
set
{
s_LockedSceneView = value;
}
}
static SceneView s_LockedSceneView;
[InitializeOnLoadMethod]
static void Initialize()
{
SceneView.duringSceneGui += Update;
EditorApplication.playModeStateChanged += OnPlayModeChanged;
}
static void OnPlayModeChanged(PlayModeStateChange state)
{
// Reset State when entering editmode or play mode
if(state == PlayModeStateChange.EnteredEditMode || state == PlayModeStateChange.EnteredPlayMode)
{
if (Active)
Active = true;
else
Active = false;
}
else // Cleanup before switching state
{
if (s_GameObject != null)
Object.DestroyImmediate(s_GameObject);
}
}
const string kMenuPath = "Edit/Link SceneView and GameView %,";
public const int kMenuPriority = 230;
[MenuItem(kMenuPath, priority = kMenuPriority, validate = false)]
static void Toggle()
{
if (Active)
Active = false;
else
Active = true;
}
[MenuItem(kMenuPath, priority = kMenuPriority, validate = true)]
static bool ToggleCheck()
{
Menu.SetChecked(kMenuPath, Active);
return SceneView.sceneViews.Count > 0;
}
static GameObject s_GameObject;
static void Update(SceneView sceneView)
{
// Check if camera Exists
if (s_GameObject == null)
{
// If disconnected (should not happen, but hey...)
var result = GameObject.Find(kLinkCameraName);
if (result != null) // reconnect
s_GameObject = result;
else // Create the camera if it does not exist
s_GameObject = CreateLinkedCamera();
if (Application.isPlaying)
Active = false;
}
// If we have a VirtualCameraManager, manage its state here
if(Application.isPlaying && Manager.Has<VirtualCameraManager>())
{
var camera = Manager.Get<VirtualCameraManager>().gameObject;
if(camera.activeInHierarchy && Active) // We need to disable the VirtualCameraManager
{
camera.SetActive(false);
}
else if (!camera.activeInHierarchy && !Active) // We need to re-enable the VirtualCameraManager
{
camera.SetActive(true);
}
}
if (Active)
{
var sv = s_LockedSceneView == null ? SceneView.lastActiveSceneView : s_LockedSceneView;
var sceneCamera = sv.camera;
var camera = s_GameObject.GetComponent<Camera>();
bool needRepaint = sceneCamera.transform.position != camera.transform.position
|| sceneCamera.transform.rotation != camera.transform.rotation
|| sceneCamera.fieldOfView != camera.fieldOfView;
if(needRepaint)
{
s_GameObject.transform.position = sceneCamera.transform.position;
s_GameObject.transform.rotation = sceneCamera.transform.rotation;
camera.orthographic = sceneCamera.orthographic;
camera.fieldOfView = sceneCamera.fieldOfView;
camera.orthographicSize = sceneCamera.orthographicSize;
UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
needRepaint = false;
}
}
}
const string kDefaultPrefabName = "LinkGameViewCamera";
static GameObject CreateLinkedCamera()
{
// Try to find an Asset named as the default name
string[] assets = AssetDatabase.FindAssets(kDefaultPrefabName);
if(assets.Length > 0)
{
string path = AssetDatabase.GUIDToAssetPath(assets[0]);
GameObject obj = (GameObject)AssetDatabase.LoadAssetAtPath(path, typeof(GameObject));
if (obj != null)
{
var instance = GameObject.Instantiate(obj);
if(instance.GetComponent<Camera>() != null)
{
instance.hideFlags = HideFlags.HideAndDontSave;
instance.tag = "MainCamera";
instance.name = kLinkCameraName;
instance.SetActive(Active);
instance.GetComponent<Camera>().depth = int.MaxValue;
return instance;
}
else
{
Debug.LogWarning("LinkGameView Found default prefab but has no camera!");
}
}
else
Debug.LogWarning("LinkGameView Found default prefab but is not gameobject!");
}
// Otherwise ... Create default from code
var go = new GameObject(kLinkCameraName);
go.hideFlags = HideFlags.HideAndDontSave;
go.tag = "MainCamera";
var camera = go.AddComponent<Camera>();
camera.depth = int.MaxValue;
go.SetActive(Active);
return go;
}
}
}

Просмотреть файл

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b80d5428a5e868b41ba603471f379a02
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,20 @@
{
"name": "GameplayIngredients-Editor",
"references": [
"NaughtyAttributes.Core",
"NaughtyAttributes>Editor",
"GameplayIngredients",
"Unity.ugui",
"Unity.Timeline"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": []
}

Просмотреть файл

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: a4e1a37fe12446f47976df6a3019ef5f
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,33 @@
using System.Linq;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace GameplayIngredients.Editor
{
public class GameplayIngredientsAssetPostprocessor : AssetPostprocessor
{
static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
{
if (importedAssets.Contains(WelcomeScreen.kSettingsAssetPath))
{
Debug.Log("Imported GameplayIngredientsSettings");
WelcomeScreen.Reload();
}
string[] allDiscovery = AssetDatabase.FindAssets("t:DiscoverAsset");
bool needDiscoveryReload = false;
foreach(var guid in allDiscovery)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
if(importedAssets.Contains(path))
{
needDiscoveryReload = true;
break;
}
}
if (needDiscoveryReload)
DiscoverWindow.Reload();
}
}
}

Просмотреть файл

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a13118b22a04c0d4d95bb500a88e59ab
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e3cfe5bb18bcf554b83a3f0646547273
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,122 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEditor;
namespace GameplayIngredients.Editor
{
public class GlobalsDebugWindow : EditorWindow
{
[MenuItem("Window/Gameplay Ingredients/Globals Debug")]
static void Open()
{
GetWindow<GlobalsDebugWindow>();
}
private void OnEnable()
{
titleContent = new GUIContent("Globals Debug");
minSize = new Vector2(360, 140);
Globals.OnGlobalsUpdated += Globals_OnGlobalsUpdated;
}
private void Globals_OnGlobalsUpdated (Globals.Type t, string name, object value)
{
Repaint();
}
private void OnDisable()
{
Globals.OnGlobalsUpdated -= Globals_OnGlobalsUpdated;
}
Vector2 scroll;
private void OnGUI()
{
var localBools = Globals.GetBoolNames(Globals.Scope.Local);
var globalBools = Globals.GetBoolNames(Globals.Scope.Global);
var localInts = Globals.GetIntNames(Globals.Scope.Local);
var globalInts = Globals.GetIntNames(Globals.Scope.Global);
var localFloats = Globals.GetFloatNames(Globals.Scope.Local);
var globalFloats = Globals.GetFloatNames(Globals.Scope.Global);
var localStrings = Globals.GetStringNames(Globals.Scope.Local);
var globalStrings = Globals.GetStringNames(Globals.Scope.Global);
var localObjects = Globals.GetObjectNames(Globals.Scope.Local);
var globalObjects = Globals.GetObjectNames(Globals.Scope.Global);
GUI.backgroundColor = new Color(0.8f, 0.8f, 0.8f, 1);
using(new GUILayout.HorizontalScope(EditorStyles.toolbar))
{
GUILayout.Label("Name", Styles.header);
GUILayout.Label("Global", Styles.header, GUILayout.Width(64));
GUILayout.Label("Type", Styles.header, GUILayout.Width(64));
GUILayout.Label("Value", Styles.header, GUILayout.Width(128));
}
GUI.backgroundColor = Color.white;
scroll = EditorGUILayout.BeginScrollView(scroll);
foreach (var item in globalBools.OrderBy(o => o)) { DrawItem(item, Globals.Scope.Global, Globals.Type.Boolean); }
foreach (var item in localBools.OrderBy(o => o)) { DrawItem(item, Globals.Scope.Local, Globals.Type.Boolean); }
foreach (var item in globalInts.OrderBy(o => o)) { DrawItem(item, Globals.Scope.Global, Globals.Type.Integer); }
foreach (var item in localInts.OrderBy(o => o)) { DrawItem(item, Globals.Scope.Local, Globals.Type.Integer); }
foreach (var item in globalFloats.OrderBy(o => o)) { DrawItem(item, Globals.Scope.Global, Globals.Type.Float); }
foreach (var item in localFloats.OrderBy(o => o)) { DrawItem(item, Globals.Scope.Local, Globals.Type.Float); }
foreach (var item in globalStrings.OrderBy(o => o)) { DrawItem(item, Globals.Scope.Global, Globals.Type.String); }
foreach (var item in localStrings.OrderBy(o => o)) { DrawItem(item, Globals.Scope.Local, Globals.Type.String); }
foreach (var item in globalObjects.OrderBy(o => o)) { DrawItem(item, Globals.Scope.Global, Globals.Type.GameObject); }
foreach (var item in localObjects.OrderBy(o => o)) { DrawItem(item, Globals.Scope.Local, Globals.Type.GameObject); }
EditorGUILayout.EndScrollView();
}
void DrawItem(string name, Globals.Scope scope, Globals.Type type)
{
using(new GUILayout.HorizontalScope())
{
GUILayout.Label(name, Styles.cell);
GUILayout.Label(scope.ToString(), Styles.cell, GUILayout.Width(64));
GUILayout.Label(type.ToString(), Styles.cell, GUILayout.Width(64));
switch (type)
{
case Globals.Type.Boolean:
GUILayout.Toggle(Globals.GetBool(name, scope),"", GUILayout.Width(128));
break;
case Globals.Type.Integer:
GUILayout.TextField(Globals.GetInt(name, scope).ToString(), GUILayout.Width(128));
break;
case Globals.Type.String:
GUILayout.TextField(Globals.GetString(name, scope).ToString(), GUILayout.Width(128));
break;
case Globals.Type.Float:
GUILayout.TextField(Globals.GetFloat(name, scope).ToString(), GUILayout.Width(128));
break;
case Globals.Type.GameObject:
EditorGUILayout.ObjectField("",Globals.GetObject(name, scope), typeof(GameObject), true, GUILayout.Width(128));
break;
default:
break;
}
}
}
static class Styles
{
public static GUIStyle header;
public static GUIStyle cell;
static Styles()
{
header = new GUIStyle(EditorStyles.toolbarButton);
header.alignment = TextAnchor.MiddleLeft;
header.fontStyle = FontStyle.Bold;
cell = new GUIStyle(EditorStyles.toolbarButton);
cell.alignment = TextAnchor.MiddleLeft;
cell.fontSize = 10;
}
}
}
}

Просмотреть файл

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: afc22b24e415f0d4a87bcfd086d002cc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,85 @@
using UnityEngine;
using UnityEditor;
namespace GameplayIngredients
{
static class HiearchyItems
{
#region TRIGGERS
[MenuItem("GameObject/Gameplay Ingredients/Events/Trigger (Box)", false, 10)]
static void CreateTriggerBox()
{
var go = new GameObject();
var col = go.AddComponent<BoxCollider>();
col.isTrigger = true;
var evt = go.AddComponent<Events.OnTriggerEvent>();
go.name = "Box Trigger";
if (Selection.activeGameObject != null)
go.transform.parent = Selection.activeGameObject.transform;
}
[MenuItem("GameObject/Gameplay Ingredients/Events/Trigger (Sphere)", false, 10)]
static void CreateTriggerSphere()
{
var go = new GameObject();
var col = go.AddComponent<SphereCollider>();
col.isTrigger = true;
var evt = go.AddComponent<Events.OnTriggerEvent>();
go.name = "Sphere Trigger";
if (Selection.activeGameObject != null)
go.transform.parent = Selection.activeGameObject.transform;
}
[MenuItem("GameObject/Gameplay Ingredients/Events/Trigger (Capsule)", false, 10)]
static void CreateTriggerCapsule()
{
var go = new GameObject();
var col = go.AddComponent<CapsuleCollider>();
col.isTrigger = true;
var evt = go.AddComponent<Events.OnTriggerEvent>();
go.name = "Capsule Trigger";
if (Selection.activeGameObject != null)
go.transform.parent = Selection.activeGameObject.transform;
}
[MenuItem("GameObject/Gameplay Ingredients/Events/On Awake", false, 10)]
static void CreateOnAwake()
{
var go = new GameObject();
var evt = go.AddComponent<Events.OnAwakeEvent>();
go.name = "On Awake";
if (Selection.activeGameObject != null)
go.transform.parent = Selection.activeGameObject.transform;
}
[MenuItem("GameObject/Gameplay Ingredients/Events/On Enable", false, 10)]
static void CreateOnEnableDisable()
{
var go = new GameObject();
var evt = go.AddComponent<Events.OnEnableDisableEvent>();
go.name = "On Enable/Disable";
if (Selection.activeGameObject != null)
go.transform.parent = Selection.activeGameObject.transform;
}
[MenuItem("GameObject/Gameplay Ingredients/Events/On Start", false, 10)]
static void CreateOnStart()
{
var go = new GameObject();
var evt = go.AddComponent<Events.OnStartEvent>();
go.name = "On Start";
if (Selection.activeGameObject != null)
go.transform.parent = Selection.activeGameObject.transform;
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 28d66973767a30643a54411070050920
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d5dcb83e338ada74c9a36ec453e5fa26
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,212 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
#if UNITY_2019_3_OR_NEWER
using UnityEngine.VFX;
#else
using UnityEngine.Experimental.VFX;
#endif
using UnityEditor;
using GameplayIngredients.StateMachines;
using UnityEngine.Playables;
namespace GameplayIngredients.Editor
{
[InitializeOnLoad]
public static class HierarchyHints
{
const string kMenuPath = "Edit/Advanced Hierarchy View %.";
public const int kMenuPriority = 230;
[MenuItem(kMenuPath, priority = kMenuPriority, validate = false)]
static void Toggle()
{
if (Active)
Active = false;
else
Active = true;
}
[MenuItem(kMenuPath, priority = kMenuPriority, validate = true)]
static bool ToggleCheck()
{
Menu.SetChecked(kMenuPath, Active);
return SceneView.sceneViews.Count > 0;
}
static readonly string kPreferenceName = "GameplayIngredients.HierarchyHints";
public static bool Active
{
get
{
return EditorPrefs.GetBool(kPreferenceName, false);
}
set
{
EditorPrefs.SetBool(kPreferenceName, value);
UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
}
}
static HierarchyHints()
{
EditorApplication.hierarchyWindowItemOnGUI -= HierarchyOnGUI;
EditorApplication.hierarchyWindowItemOnGUI += HierarchyOnGUI;
}
static Dictionary<Type, string> s_Definitions = new Dictionary<Type, string>()
{
{ typeof(Folder), "Folder Icon"},
{ typeof(MonoBehaviour), "cs Script Icon"},
{ typeof(Camera), "Camera Icon"},
{ typeof(MeshRenderer), "MeshRenderer Icon"},
{ typeof(SkinnedMeshRenderer), "SkinnedMeshRenderer Icon"},
{ typeof(BoxCollider), "BoxCollider Icon"},
{ typeof(SphereCollider), "SphereCollider Icon"},
{ typeof(CapsuleCollider), "CapsuleCollider Icon"},
{ typeof(MeshCollider), "MeshCollider Icon"},
{ typeof(AudioSource), "AudioSource Icon"},
{ typeof(Animation), "Animation Icon"},
{ typeof(Animator), "Animator Icon"},
{ typeof(PlayableDirector), "PlayableDirector Icon"},
{ typeof(Light), "Light Icon"},
{ typeof(LightProbeGroup), "LightProbeGroup Icon"},
{ typeof(LightProbeProxyVolume), "LightProbeProxyVolume Icon"},
{ typeof(ReflectionProbe), "ReflectionProbe Icon"},
{ typeof(VisualEffect), "VisualEffect Icon"},
{ typeof(ParticleSystem), "ParticleSystem Icon"},
{ typeof(Canvas), "Canvas Icon"},
{ typeof(Image), "Image Icon"},
{ typeof(Text), "Text Icon"},
{ typeof(Button), "Button Icon"},
{ typeof(StateMachine), "Packages/net.peeweek.gameplay-ingredients/Icons/Misc/ic-StateMachine.png"},
{ typeof(State), "Packages/net.peeweek.gameplay-ingredients/Icons/Misc/ic-State.png"},
};
static void HierarchyOnGUI(int instanceID, Rect selectionRect)
{
if (!Active) return;
var fullRect = selectionRect;
#if UNITY_2019_3_OR_NEWER
fullRect.xMin = 32;
#else
fullRect.xMin = 16;
#endif
fullRect.xMax = EditorGUIUtility.currentViewWidth;
GameObject o = EditorUtility.InstanceIDToObject(instanceID) as GameObject;
if (o == null) return;
var c = GUI.color;
bool isFolder = o.GetComponent<Folder>() != null;
if(isFolder)
{
fullRect.xMin += 28 + 14 * GetObjectDepth(o.transform);
fullRect.width = 16;
EditorGUI.DrawRect(fullRect, EditorGUIUtility.isProSkin? Styles.proBackground : Styles.personalBackground);
DrawIcon(fullRect, Contents.GetContent(typeof(Folder)), o.GetComponent<Folder>().Color);
}
else
{
if (o.isStatic)
{
GUI.Label(fullRect, " S");
EditorGUI.DrawRect(fullRect, Colors.dimGray);
}
foreach (var type in s_Definitions.Keys)
{
if (o.GetComponents(type).Length > 0) selectionRect = DrawIcon(selectionRect, Contents.GetContent(type), Color.white);
}
}
GUI.color = c;
}
static int GetObjectDepth(Transform t, int depth=0)
{
if (t.parent == null)
return depth;
else
return GetObjectDepth(t.parent, depth + 1);
}
static Rect DrawIcon(Rect rect, GUIContent content, Color color, int size = 16)
{
GUI.color = color;
GUI.Label(rect, content, Styles.icon);
rect.width = rect.width - size;
return rect;
}
static class Contents
{
static Dictionary<Type, GUIContent> s_Icons = new Dictionary<Type, GUIContent>();
public static void AddIcon(Type type, string IconName)
{
GUIContent icon;
Texture texture = AssetDatabase.LoadAssetAtPath<Texture>(IconName);
if (texture == null)
icon = EditorGUIUtility.IconContent(IconName);
else
icon = new GUIContent(texture);
s_Icons.Add(type, icon);
}
public static GUIContent GetContent(Type t)
{
if (!s_Icons.ContainsKey(t) && s_Definitions.ContainsKey(t))
AddIcon(t,s_Definitions[t]);
return s_Icons[t];
}
}
static class Colors
{
public static Color orange = new Color(1.0f, 0.7f, 0.1f);
public static Color red = new Color(1.0f, 0.4f, 0.3f);
public static Color yellow = new Color(0.8f, 1.0f, 0.1f);
public static Color green = new Color(0.2f, 1.0f, 0.1f);
public static Color blue = new Color(0.5f, 0.8f, 1.0f);
public static Color violet = new Color(0.8f, 0.5f, 1.0f);
public static Color purple = new Color(1.0f, 0.5f, 0.8f);
public static Color dimGray = new Color(0.4f, 0.4f, 0.4f, 0.2f);
}
static class Styles
{
public static GUIStyle rightLabel;
public static GUIStyle icon;
public static Color proBackground = new Color(0.25f, 0.25f, 0.25f, 1.0f);
public static Color personalBackground = new Color(0.75f, 0.75f, 0.75f, 1.0f);
static Styles()
{
rightLabel = new GUIStyle(EditorStyles.label);
rightLabel.alignment = TextAnchor.MiddleRight;
rightLabel.normal.textColor = Color.white;
rightLabel.onNormal.textColor = Color.white;
rightLabel.active.textColor = Color.white;
rightLabel.onActive.textColor = Color.white;
icon = new GUIStyle(rightLabel);
icon.padding = new RectOffset();
icon.margin = new RectOffset();
}
}
}
}

Просмотреть файл

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a6ca563f0dba0814c804f2cdbef717d9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,146 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System;
using System.Reflection;
using UnityEngine.SceneManagement;
namespace GameplayIngredients.Editor
{
public static class MenuItems
{
public const int kWindowMenuPriority = 100;
public const int kPlayMenuPriority = 160;
public const int kMenuPriority = 330;
#region PLAY HERE
[MenuItem("Edit/Play from SceneView Position #%&P", priority = kPlayMenuPriority)]
static void PlayHere()
{
EditorApplication.isPlaying = true;
}
[MenuItem("Edit/Play from SceneView Position #%&P", priority = kPlayMenuPriority, validate = true)]
static bool PlayHereValidate()
{
return PlayFromHere.IsReady;
}
#endregion
#region GROUP_UNGROUP
const int kGroupMenuIndex = 500;
const string kGroupMenuString = "Edit/Group Selected %G";
const string kUnGroupMenuString = "Edit/Un-Group Selected %#G";
[MenuItem(kGroupMenuString, priority = kGroupMenuIndex, validate = false)]
static void Group()
{
if (Selection.gameObjects.Length <= 1)
return;
var selected = Selection.gameObjects;
Transform parent = selected[0].transform.parent;
Scene scene = selected[0].scene;
bool sparseParents = false;
foreach (var obj in selected)
{
if (obj.transform.parent != parent || obj.scene != scene)
{
sparseParents = true;
break;
}
}
if (sparseParents)
{
parent = null;
scene = SceneManager.GetActiveScene();
}
Vector3 posSum = Vector3.zero;
foreach (var go in selected)
{
posSum += go.transform.position;
}
GameObject groupObj = new GameObject("Group");
groupObj.transform.position = posSum / selected.Length;
groupObj.transform.parent = parent;
groupObj.isStatic = true;
foreach (var go in selected)
go.transform.parent = groupObj.transform;
// Expand by pinging the first object
EditorGUIUtility.PingObject(selected[0]);
}
[MenuItem(kGroupMenuString, priority = kGroupMenuIndex, validate = true)]
static bool GroupCheck()
{
return (Selection.gameObjects.Length > 1);
}
[MenuItem(kUnGroupMenuString, priority = kGroupMenuIndex+1, validate = false)]
static void UnGroup()
{
if (Selection.gameObjects.Length == 0)
return;
var selected = Selection.gameObjects;
List<Transform> oldParents = new List<Transform>();
foreach(var go in selected)
{
if(go.transform.parent != null)
{
if(!oldParents.Contains(go.transform.parent))
oldParents.Add(go.transform.parent);
go.transform.parent = go.transform.parent.parent;
}
}
List<GameObject> toDelete = new List<GameObject>();
// Cleanup old parents
foreach(var parent in oldParents)
{
var go = parent.gameObject;
if(parent.childCount == 0 && parent.GetComponents<Component>().Length == 1) // if no more children and only transform/rectTransform
{
toDelete.Add(go);
}
}
foreach (var trash in toDelete)
GameObject.DestroyImmediate(trash);
}
[MenuItem(kUnGroupMenuString, priority = kGroupMenuIndex+1, validate = true)]
static bool UnGroupCheck()
{
return (Selection.gameObjects.Length > 0);
}
#endregion
#region ASSETS
[UnityEditor.MenuItem("Assets/Create/Game Level")]
static void CreateGameLevel()
{
GameplayIngredients.Editor.AssetFactory.CreateAssetInProjectWindow<GameLevel>("", "New Game Level.asset");
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9b95ff60e46051544a400d4a0afa962b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: abc8c99e8458f7f468eee26216bd1879
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше