diff --git a/Packages/com.opsive.behaviordesigner/Editor.meta b/Packages/com.opsive.behaviordesigner/Editor.meta new file mode 100644 index 0000000..7082ed2 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 26ac373dcc50b57419e903b8853f3593 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons.meta new file mode 100644 index 0000000..b0c1dbb --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 142d426ab319c944c8627c59dc5d9f06 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/BehaviorDesignerIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/BehaviorDesignerIcon.png new file mode 100644 index 0000000..61c3f9f Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/BehaviorDesignerIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/BehaviorDesignerIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/BehaviorDesignerIcon.png.meta new file mode 100644 index 0000000..350bb56 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/BehaviorDesignerIcon.png.meta @@ -0,0 +1,104 @@ +fileFormatVersion: 2 +guid: e0a8f1df788b6274a9a24003859dfa7e +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + applyGammaDecoding: 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: 0 + - 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: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkActiveStackedTask.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkActiveStackedTask.png new file mode 100644 index 0000000..3360969 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkActiveStackedTask.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkActiveStackedTask.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkActiveStackedTask.png.meta new file mode 100644 index 0000000..95d2316 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkActiveStackedTask.png.meta @@ -0,0 +1,127 @@ +fileFormatVersion: 2 +guid: 1230b934cbd748345b13125468a34720 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkCollapsedSlot.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkCollapsedSlot.png new file mode 100644 index 0000000..55dcb97 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkCollapsedSlot.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkCollapsedSlot.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkCollapsedSlot.png.meta new file mode 100644 index 0000000..a9deaa1 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkCollapsedSlot.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 98eddd8dea34cc1429daaebbc435b3b7 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkConditionalAbortBothIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkConditionalAbortBothIcon.png new file mode 100644 index 0000000..c25b3f0 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkConditionalAbortBothIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkConditionalAbortBothIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkConditionalAbortBothIcon.png.meta new file mode 100644 index 0000000..7cdb027 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkConditionalAbortBothIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 1c01950cc0f1c994cb5ff3576969ebbf +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkConditionalAbortLowerPriorityIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkConditionalAbortLowerPriorityIcon.png new file mode 100644 index 0000000..ba5d9c4 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkConditionalAbortLowerPriorityIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkConditionalAbortLowerPriorityIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkConditionalAbortLowerPriorityIcon.png.meta new file mode 100644 index 0000000..166d6fb --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkConditionalAbortLowerPriorityIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: ba6528926e3f4f7438d3b9737f595ec6 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkConditionalAbortSelfIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkConditionalAbortSelfIcon.png new file mode 100644 index 0000000..e4a115c Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkConditionalAbortSelfIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkConditionalAbortSelfIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkConditionalAbortSelfIcon.png.meta new file mode 100644 index 0000000..695343b --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkConditionalAbortSelfIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: ff3ba64f23e708645b24cc7509b5ebe5 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkExecutionFailure.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkExecutionFailure.png new file mode 100644 index 0000000..223d6fc Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkExecutionFailure.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkExecutionFailure.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkExecutionFailure.png.meta new file mode 100644 index 0000000..c9ffe3a --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkExecutionFailure.png.meta @@ -0,0 +1,127 @@ +fileFormatVersion: 2 +guid: 8d159db7a8da43e41a50a77e43cfd6ba +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkExecutionFailureReevaluate.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkExecutionFailureReevaluate.png new file mode 100644 index 0000000..6df0ace Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkExecutionFailureReevaluate.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkExecutionFailureReevaluate.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkExecutionFailureReevaluate.png.meta new file mode 100644 index 0000000..13bf1bd --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkExecutionFailureReevaluate.png.meta @@ -0,0 +1,127 @@ +fileFormatVersion: 2 +guid: 26de8afeb313fd84291f98e68db44df7 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkExecutionSuccess.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkExecutionSuccess.png new file mode 100644 index 0000000..188d1b9 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkExecutionSuccess.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkExecutionSuccess.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkExecutionSuccess.png.meta new file mode 100644 index 0000000..adf9061 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkExecutionSuccess.png.meta @@ -0,0 +1,127 @@ +fileFormatVersion: 2 +guid: 240eed9b6e6dc004f94216f1e9fcc390 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkExecutionSuccessReevaluate.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkExecutionSuccessReevaluate.png new file mode 100644 index 0000000..9172202 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkExecutionSuccessReevaluate.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkExecutionSuccessReevaluate.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkExecutionSuccessReevaluate.png.meta new file mode 100644 index 0000000..6955530 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/DarkExecutionSuccessReevaluate.png.meta @@ -0,0 +1,127 @@ +fileFormatVersion: 2 +guid: 0a5037ce131729b4fa0ffa9e1e13d387 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/LightActiveStackedTask.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightActiveStackedTask.png new file mode 100644 index 0000000..4916616 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightActiveStackedTask.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/LightActiveStackedTask.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightActiveStackedTask.png.meta new file mode 100644 index 0000000..26004b2 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightActiveStackedTask.png.meta @@ -0,0 +1,127 @@ +fileFormatVersion: 2 +guid: e57f179ee476f274dbe537179e67bf04 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/LightCollapsedSlot.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightCollapsedSlot.png new file mode 100644 index 0000000..d8b6a63 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightCollapsedSlot.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/LightCollapsedSlot.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightCollapsedSlot.png.meta new file mode 100644 index 0000000..1a6940f --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightCollapsedSlot.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: c26e9105fdca0a54da087f5992aa9e61 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/LightConditionalAbortBothIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightConditionalAbortBothIcon.png new file mode 100644 index 0000000..aba55bc Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightConditionalAbortBothIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/LightConditionalAbortBothIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightConditionalAbortBothIcon.png.meta new file mode 100644 index 0000000..5e3099c --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightConditionalAbortBothIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 90b22fc04519bdb44b4d83665e86381d +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/LightConditionalAbortLowerPriorityIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightConditionalAbortLowerPriorityIcon.png new file mode 100644 index 0000000..2b784c9 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightConditionalAbortLowerPriorityIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/LightConditionalAbortLowerPriorityIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightConditionalAbortLowerPriorityIcon.png.meta new file mode 100644 index 0000000..fdee981 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightConditionalAbortLowerPriorityIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 20be04a2e46cb9d40b601dccdfbe153b +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/LightConditionalAbortSelfIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightConditionalAbortSelfIcon.png new file mode 100644 index 0000000..09c9eae Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightConditionalAbortSelfIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/LightConditionalAbortSelfIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightConditionalAbortSelfIcon.png.meta new file mode 100644 index 0000000..a0c53a7 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightConditionalAbortSelfIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 5d44e66bacdbe51408dd30e519c2b318 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/LightExecutionFailure.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightExecutionFailure.png new file mode 100644 index 0000000..b8b9e23 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightExecutionFailure.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/LightExecutionFailure.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightExecutionFailure.png.meta new file mode 100644 index 0000000..066a3e6 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightExecutionFailure.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: c3622912d9f7bcd41a54a95add672423 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/LightExecutionFailureReevaluate.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightExecutionFailureReevaluate.png new file mode 100644 index 0000000..48abd28 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightExecutionFailureReevaluate.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/LightExecutionFailureReevaluate.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightExecutionFailureReevaluate.png.meta new file mode 100644 index 0000000..1704f31 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightExecutionFailureReevaluate.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 5a6d713911c8ec3488639e2934329033 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/LightExecutionSuccess.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightExecutionSuccess.png new file mode 100644 index 0000000..c257f7c Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightExecutionSuccess.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/LightExecutionSuccess.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightExecutionSuccess.png.meta new file mode 100644 index 0000000..c22a2cb --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightExecutionSuccess.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: cf3f27e8ca1f20f4680890e078c7613a +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/LightExecutionSuccessReevaluate.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightExecutionSuccessReevaluate.png new file mode 100644 index 0000000..a7c2d05 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightExecutionSuccessReevaluate.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/LightExecutionSuccessReevaluate.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightExecutionSuccessReevaluate.png.meta new file mode 100644 index 0000000..8bc501f --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/LightExecutionSuccessReevaluate.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: bba6bdc3af0aac44dadd1ca3a8485b05 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks.meta new file mode 100644 index 0000000..045c3f7 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9a6e740a6dc5e3b4fbb1f3d9c77a070e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkActionIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkActionIcon.png new file mode 100644 index 0000000..e3d72ae Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkActionIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkActionIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkActionIcon.png.meta new file mode 100644 index 0000000..160edf0 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkActionIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 3bbdfa553da4d554e9d74f8d88915aac +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkCompositeIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkCompositeIcon.png new file mode 100644 index 0000000..a7bd863 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkCompositeIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkCompositeIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkCompositeIcon.png.meta new file mode 100644 index 0000000..d863e46 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkCompositeIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 3afb3814c40717440b175b6fde4e73c2 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkConditionalEvaluatorIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkConditionalEvaluatorIcon.png new file mode 100644 index 0000000..82b4a38 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkConditionalEvaluatorIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkConditionalEvaluatorIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkConditionalEvaluatorIcon.png.meta new file mode 100644 index 0000000..614b9f4 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkConditionalEvaluatorIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 63d6a403c13816a49b58d1de830ca51e +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkConditionalIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkConditionalIcon.png new file mode 100644 index 0000000..8e1ce40 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkConditionalIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkConditionalIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkConditionalIcon.png.meta new file mode 100644 index 0000000..8f0891c --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkConditionalIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: dea5c23eac9d12c4cbd380cc879816ea +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkCooldownIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkCooldownIcon.png new file mode 100644 index 0000000..6705cad Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkCooldownIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkCooldownIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkCooldownIcon.png.meta new file mode 100644 index 0000000..6883c95 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkCooldownIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: b5459f67bc5033e49ad7a763cdb885bb +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkDecoratorIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkDecoratorIcon.png new file mode 100644 index 0000000..6cb9484 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkDecoratorIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkDecoratorIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkDecoratorIcon.png.meta new file mode 100644 index 0000000..78a2d14 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkDecoratorIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 9abc6c99a8db43b49b2b0d48cca90105 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkEventIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkEventIcon.png new file mode 100644 index 0000000..7100331 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkEventIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkEventIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkEventIcon.png.meta new file mode 100644 index 0000000..407f125 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkEventIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 9041375773f69454792084ab67820b7e +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkHasReceivedEventIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkHasReceivedEventIcon.png new file mode 100644 index 0000000..51a5e0f Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkHasReceivedEventIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkHasReceivedEventIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkHasReceivedEventIcon.png.meta new file mode 100644 index 0000000..7dc8849 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkHasReceivedEventIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: e6fc90c130121da4f9067b5e15b02975 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkIdleIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkIdleIcon.png new file mode 100644 index 0000000..500afef Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkIdleIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkIdleIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkIdleIcon.png.meta new file mode 100644 index 0000000..bc6fbee --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkIdleIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: fc4d1b83384913b4abfbd8455db6df5b +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkInverterIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkInverterIcon.png new file mode 100644 index 0000000..c9c95a9 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkInverterIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkInverterIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkInverterIcon.png.meta new file mode 100644 index 0000000..eb378d4 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkInverterIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 53fe4de81c20e924095bdb5f3447acdc +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkIteratorIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkIteratorIcon.png new file mode 100644 index 0000000..b132a45 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkIteratorIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkIteratorIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkIteratorIcon.png.meta new file mode 100644 index 0000000..6f7c8a0 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkIteratorIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 3c1366e1dc8fe0b46b4a6c8724194cdd +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkLogIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkLogIcon.png new file mode 100644 index 0000000..1a2254c Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkLogIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkLogIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkLogIcon.png.meta new file mode 100644 index 0000000..7e7619c --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkLogIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: c97bee71424b3e247a161d1279643506 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkOnInterruptIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkOnInterruptIcon.png new file mode 100644 index 0000000..e80fbf4 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkOnInterruptIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkOnInterruptIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkOnInterruptIcon.png.meta new file mode 100644 index 0000000..cd95ec4 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkOnInterruptIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 10ed9753a0870c84889dc42a7de397a8 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkOnPhysicsCallbackIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkOnPhysicsCallbackIcon.png new file mode 100644 index 0000000..9a04dac Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkOnPhysicsCallbackIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkOnPhysicsCallbackIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkOnPhysicsCallbackIcon.png.meta new file mode 100644 index 0000000..19a69ee --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkOnPhysicsCallbackIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 06864c37115f11445b04701c616d0e14 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkParallelIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkParallelIcon.png new file mode 100644 index 0000000..52387d9 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkParallelIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkParallelIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkParallelIcon.png.meta new file mode 100644 index 0000000..2fb6686 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkParallelIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: f612c025389b22640b1b6df88f4502e7 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkParallelSelectorIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkParallelSelectorIcon.png new file mode 100644 index 0000000..95c7490 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkParallelSelectorIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkParallelSelectorIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkParallelSelectorIcon.png.meta new file mode 100644 index 0000000..cfa2bab --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkParallelSelectorIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: d47aff1a00bcc6d4da8ca0df32ed8415 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkPerformInterruptionIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkPerformInterruptionIcon.png new file mode 100644 index 0000000..a874728 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkPerformInterruptionIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkPerformInterruptionIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkPerformInterruptionIcon.png.meta new file mode 100644 index 0000000..7da0c1f --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkPerformInterruptionIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 7c0aba0d8377aac48966d8e3f817a2a8 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkPrioritySelectorIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkPrioritySelectorIcon.png new file mode 100644 index 0000000..93f5c62 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkPrioritySelectorIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkPrioritySelectorIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkPrioritySelectorIcon.png.meta new file mode 100644 index 0000000..4c00f53 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkPrioritySelectorIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: cea0f2b6cee06a742bb35dcc40202e8e +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkRandomProbabilityIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkRandomProbabilityIcon.png new file mode 100644 index 0000000..7a518bf Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkRandomProbabilityIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkRandomProbabilityIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkRandomProbabilityIcon.png.meta new file mode 100644 index 0000000..5f3091c --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkRandomProbabilityIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 69bf50f8923f54c4c8bb8e258883a411 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkRandomSelectorIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkRandomSelectorIcon.png new file mode 100644 index 0000000..d98e797 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkRandomSelectorIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkRandomSelectorIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkRandomSelectorIcon.png.meta new file mode 100644 index 0000000..bf6ec5b --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkRandomSelectorIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: d7c1e0f5830316e449df8a35561df859 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkRandomSequenceIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkRandomSequenceIcon.png new file mode 100644 index 0000000..e8ba829 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkRandomSequenceIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkRandomSequenceIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkRandomSequenceIcon.png.meta new file mode 100644 index 0000000..bd846d9 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkRandomSequenceIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: edb30349221143a408c76da55a6aa809 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkRepeaterIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkRepeaterIcon.png new file mode 100644 index 0000000..8d179b5 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkRepeaterIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkRepeaterIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkRepeaterIcon.png.meta new file mode 100644 index 0000000..b47ad69 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkRepeaterIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: ceb6f3e7f67cde640b28b2a15ec13ffe +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkReturnFailureIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkReturnFailureIcon.png new file mode 100644 index 0000000..3b86ce3 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkReturnFailureIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkReturnFailureIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkReturnFailureIcon.png.meta new file mode 100644 index 0000000..81b783a --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkReturnFailureIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 667a475ceee05824188a36b24ec8d392 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkReturnSuccessIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkReturnSuccessIcon.png new file mode 100644 index 0000000..b76cec7 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkReturnSuccessIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkReturnSuccessIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkReturnSuccessIcon.png.meta new file mode 100644 index 0000000..f11e8a6 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkReturnSuccessIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 66f47acff1d46f848bc8c22b221ee1d0 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkSelectorIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkSelectorIcon.png new file mode 100644 index 0000000..da25d92 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkSelectorIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkSelectorIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkSelectorIcon.png.meta new file mode 100644 index 0000000..4dbc13e --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkSelectorIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 4c3d0559a9ebc604e88b16e9a3fdfa05 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkSendEventIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkSendEventIcon.png new file mode 100644 index 0000000..89dc3cb Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkSendEventIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkSendEventIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkSendEventIcon.png.meta new file mode 100644 index 0000000..37f0045 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkSendEventIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: bde76446ddfbd234488e8d591bc75e2f +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkSequenceIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkSequenceIcon.png new file mode 100644 index 0000000..ee09a93 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkSequenceIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkSequenceIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkSequenceIcon.png.meta new file mode 100644 index 0000000..82ce447 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkSequenceIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 8981cc246f900b24da46ae10eb49b68b +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkStackedActionIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkStackedActionIcon.png new file mode 100644 index 0000000..f94a98d Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkStackedActionIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkStackedActionIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkStackedActionIcon.png.meta new file mode 100644 index 0000000..cfbdbf9 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkStackedActionIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: dacf20a036b1f5e41886d84ac4a47779 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkStackedConditionalIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkStackedConditionalIcon.png new file mode 100644 index 0000000..a9df314 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkStackedConditionalIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkStackedConditionalIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkStackedConditionalIcon.png.meta new file mode 100644 index 0000000..79290c3 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkStackedConditionalIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: b2368834b8b80144a8b1ab97b609e966 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkStartIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkStartIcon.png new file mode 100644 index 0000000..e1b4428 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkStartIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkStartIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkStartIcon.png.meta new file mode 100644 index 0000000..38313f0 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkStartIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 8c35407905159694e8b83df15d3b039b +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkUntilFailureIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkUntilFailureIcon.png new file mode 100644 index 0000000..8a1da43 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkUntilFailureIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkUntilFailureIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkUntilFailureIcon.png.meta new file mode 100644 index 0000000..d1adaa4 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkUntilFailureIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 60da350fd1f5b48428e466b79cb85cb2 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkUntilSuccessIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkUntilSuccessIcon.png new file mode 100644 index 0000000..b696ee4 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkUntilSuccessIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkUntilSuccessIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkUntilSuccessIcon.png.meta new file mode 100644 index 0000000..9b3eff7 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkUntilSuccessIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: f2e750025a5812640919385b75319d6f +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkUtilitySelectorIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkUtilitySelectorIcon.png new file mode 100644 index 0000000..8a7a0de Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkUtilitySelectorIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkUtilitySelectorIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkUtilitySelectorIcon.png.meta new file mode 100644 index 0000000..1b4d07e --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkUtilitySelectorIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 9d36cd363c3e08246a6e9eaf5ad99d69 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkWaitIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkWaitIcon.png new file mode 100644 index 0000000..6ad623f Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkWaitIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkWaitIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkWaitIcon.png.meta new file mode 100644 index 0000000..cebcd00 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/DarkWaitIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: b4b59e888607422409f1efa599af34ae +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightActionIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightActionIcon.png new file mode 100644 index 0000000..7e4184b Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightActionIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightActionIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightActionIcon.png.meta new file mode 100644 index 0000000..7108257 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightActionIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 6437308e972f99f48953f20198fd4e94 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightCompositeIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightCompositeIcon.png new file mode 100644 index 0000000..e7b94e0 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightCompositeIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightCompositeIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightCompositeIcon.png.meta new file mode 100644 index 0000000..93ff04b --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightCompositeIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 7fb12c74939f50b41b1679eb8f9e79ab +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightConditionalEvaluator.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightConditionalEvaluator.png new file mode 100644 index 0000000..28b0af7 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightConditionalEvaluator.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightConditionalEvaluator.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightConditionalEvaluator.png.meta new file mode 100644 index 0000000..ad355f7 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightConditionalEvaluator.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 3d3c18273075b3f40b6c921943f33964 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightConditionalIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightConditionalIcon.png new file mode 100644 index 0000000..9cf68ab Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightConditionalIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightConditionalIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightConditionalIcon.png.meta new file mode 100644 index 0000000..0b2e4c2 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightConditionalIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 2963cf3eb0c036449829254b2074c4c3 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightCooldownIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightCooldownIcon.png new file mode 100644 index 0000000..e668755 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightCooldownIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightCooldownIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightCooldownIcon.png.meta new file mode 100644 index 0000000..7ebfeb3 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightCooldownIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 480c79a18119d2a488b5d984211463f1 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightDecoratorIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightDecoratorIcon.png new file mode 100644 index 0000000..4641a4e Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightDecoratorIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightDecoratorIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightDecoratorIcon.png.meta new file mode 100644 index 0000000..cb4250c --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightDecoratorIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 1ee7d6a0873e3d942b556d3093d8173f +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightEventIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightEventIcon.png new file mode 100644 index 0000000..4988c53 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightEventIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightEventIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightEventIcon.png.meta new file mode 100644 index 0000000..0b8eb5b --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightEventIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: b1382ad24c668174c9a6e0bd00f229e3 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightHasReceivedEventIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightHasReceivedEventIcon.png new file mode 100644 index 0000000..c71ebf4 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightHasReceivedEventIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightHasReceivedEventIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightHasReceivedEventIcon.png.meta new file mode 100644 index 0000000..984ae17 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightHasReceivedEventIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 69959064b54a0cb4cb077dbb6967a3e1 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightIdleIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightIdleIcon.png new file mode 100644 index 0000000..7ec0018 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightIdleIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightIdleIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightIdleIcon.png.meta new file mode 100644 index 0000000..e599e50 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightIdleIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 79a6985a753bb244fb5b32dc0f26addb +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightInverterIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightInverterIcon.png new file mode 100644 index 0000000..15cf2a5 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightInverterIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightInverterIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightInverterIcon.png.meta new file mode 100644 index 0000000..27cc51c --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightInverterIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 8d991ea2b725c214c85580d5647c578c +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightIteratorIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightIteratorIcon.png new file mode 100644 index 0000000..2e7feaa Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightIteratorIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightIteratorIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightIteratorIcon.png.meta new file mode 100644 index 0000000..9f5d737 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightIteratorIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 5b924a7ff18f0544aaa585af94ac536c +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightLogIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightLogIcon.png new file mode 100644 index 0000000..1bdbb22 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightLogIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightLogIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightLogIcon.png.meta new file mode 100644 index 0000000..bb89c4b --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightLogIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 138439e3588de5d449b7949d68d32ad8 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightOnInterruptIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightOnInterruptIcon.png new file mode 100644 index 0000000..8f1c561 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightOnInterruptIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightOnInterruptIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightOnInterruptIcon.png.meta new file mode 100644 index 0000000..2fe4cd1 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightOnInterruptIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 98f584ca47ddad64d9878314395ce160 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightOnPhysicsCallbackIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightOnPhysicsCallbackIcon.png new file mode 100644 index 0000000..74f5217 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightOnPhysicsCallbackIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightOnPhysicsCallbackIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightOnPhysicsCallbackIcon.png.meta new file mode 100644 index 0000000..4c53be9 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightOnPhysicsCallbackIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 8b8a2793322238240b4f25171d772003 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightParallelIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightParallelIcon.png new file mode 100644 index 0000000..00de516 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightParallelIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightParallelIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightParallelIcon.png.meta new file mode 100644 index 0000000..f74f54f --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightParallelIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 8a4a401bcfb527a48a08351efaf92e14 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightParallelSelectorIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightParallelSelectorIcon.png new file mode 100644 index 0000000..1cc2f62 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightParallelSelectorIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightParallelSelectorIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightParallelSelectorIcon.png.meta new file mode 100644 index 0000000..a7bd3f8 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightParallelSelectorIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 108591b5d7a6bd94383d16a62cb3b4a7 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightPerformInterruptionIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightPerformInterruptionIcon.png new file mode 100644 index 0000000..5e577d9 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightPerformInterruptionIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightPerformInterruptionIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightPerformInterruptionIcon.png.meta new file mode 100644 index 0000000..856cddd --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightPerformInterruptionIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 90105f40f82a30e45b08d150c1928950 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightPrioritySelectorIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightPrioritySelectorIcon.png new file mode 100644 index 0000000..41974c0 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightPrioritySelectorIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightPrioritySelectorIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightPrioritySelectorIcon.png.meta new file mode 100644 index 0000000..0e8a686 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightPrioritySelectorIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 744afc2640950e045961296f1d5800d7 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightRandomProbabilityIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightRandomProbabilityIcon.png new file mode 100644 index 0000000..b5800f9 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightRandomProbabilityIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightRandomProbabilityIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightRandomProbabilityIcon.png.meta new file mode 100644 index 0000000..016c1eb --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightRandomProbabilityIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 6c5770241610a4c4aae4ac3af0ac8bf8 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightRandomSelectorIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightRandomSelectorIcon.png new file mode 100644 index 0000000..d147a58 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightRandomSelectorIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightRandomSelectorIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightRandomSelectorIcon.png.meta new file mode 100644 index 0000000..b15f82b --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightRandomSelectorIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 7638e4bc5a1f4cd488801902387ec5ea +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightRandomSequenceIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightRandomSequenceIcon.png new file mode 100644 index 0000000..7af07e3 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightRandomSequenceIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightRandomSequenceIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightRandomSequenceIcon.png.meta new file mode 100644 index 0000000..4e6a912 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightRandomSequenceIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: cfb9039832ed52748b617bde070898dc +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightRepeaterIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightRepeaterIcon.png new file mode 100644 index 0000000..189169b Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightRepeaterIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightRepeaterIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightRepeaterIcon.png.meta new file mode 100644 index 0000000..5831f6a --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightRepeaterIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: bb415ca6de87c3d49ab9a94fe8a6fca8 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightReturnFailureIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightReturnFailureIcon.png new file mode 100644 index 0000000..4575c17 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightReturnFailureIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightReturnFailureIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightReturnFailureIcon.png.meta new file mode 100644 index 0000000..f309e99 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightReturnFailureIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 7d32c9b05505df24a94069606f3b823d +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightReturnSuccessIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightReturnSuccessIcon.png new file mode 100644 index 0000000..5e53fef Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightReturnSuccessIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightReturnSuccessIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightReturnSuccessIcon.png.meta new file mode 100644 index 0000000..44b5db0 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightReturnSuccessIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 3eb990b93a7fd6e479d6b032c7e6973f +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightSelectorIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightSelectorIcon.png new file mode 100644 index 0000000..324fab5 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightSelectorIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightSelectorIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightSelectorIcon.png.meta new file mode 100644 index 0000000..3ebbf28 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightSelectorIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: de3acf0e386a26246b8bc999b1ef8e32 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightSendEventIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightSendEventIcon.png new file mode 100644 index 0000000..c549398 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightSendEventIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightSendEventIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightSendEventIcon.png.meta new file mode 100644 index 0000000..b99ba8a --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightSendEventIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 6d03b96c0f79bee4ab2e14fc82aa0031 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightSequenceIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightSequenceIcon.png new file mode 100644 index 0000000..10d6b64 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightSequenceIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightSequenceIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightSequenceIcon.png.meta new file mode 100644 index 0000000..04c5327 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightSequenceIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 4a7b39d8e0d056a4a9d8eb390b4bc9b8 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightStackedActionIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightStackedActionIcon.png new file mode 100644 index 0000000..219a933 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightStackedActionIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightStackedActionIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightStackedActionIcon.png.meta new file mode 100644 index 0000000..de74839 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightStackedActionIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 2df1cb3efc025214cbab4df573bb3515 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightStackedConditionalIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightStackedConditionalIcon.png new file mode 100644 index 0000000..ec7f9b1 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightStackedConditionalIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightStackedConditionalIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightStackedConditionalIcon.png.meta new file mode 100644 index 0000000..395cc88 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightStackedConditionalIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 86fbf527a2c761e45bc4a47cf4894902 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightStartIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightStartIcon.png new file mode 100644 index 0000000..6ca4b8a Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightStartIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightStartIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightStartIcon.png.meta new file mode 100644 index 0000000..58c1d78 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightStartIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: df820d6e71423194188c7dcb1c1ae2e2 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightUntilFailureIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightUntilFailureIcon.png new file mode 100644 index 0000000..7c96e46 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightUntilFailureIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightUntilFailureIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightUntilFailureIcon.png.meta new file mode 100644 index 0000000..a633251 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightUntilFailureIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 3d29cc3223984f44291c0e423a0aa6c6 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightUntilSuccessIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightUntilSuccessIcon.png new file mode 100644 index 0000000..66f1c9d Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightUntilSuccessIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightUntilSuccessIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightUntilSuccessIcon.png.meta new file mode 100644 index 0000000..348a83a --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightUntilSuccessIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 4e9ac4f2dd8bfe741a5f889efb1ade67 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightUtilitySelectorIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightUtilitySelectorIcon.png new file mode 100644 index 0000000..172e817 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightUtilitySelectorIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightUtilitySelectorIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightUtilitySelectorIcon.png.meta new file mode 100644 index 0000000..b3afa10 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightUtilitySelectorIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: db3d0b77c7f9e0b4f9157aa03178836a +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightWaitIcon.png b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightWaitIcon.png new file mode 100644 index 0000000..772fbb4 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightWaitIcon.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightWaitIcon.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightWaitIcon.png.meta new file mode 100644 index 0000000..68a4b26 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Icons/Tasks/LightWaitIcon.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: e1cb9cb566a90fb4489bf31465b99747 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Managers.meta b/Packages/com.opsive.behaviordesigner/Editor/Managers.meta new file mode 100644 index 0000000..12434e6 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Managers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fa7ae1b2addcf87409cb38b62daefec5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Managers/AddOnsManager.cs b/Packages/com.opsive.behaviordesigner/Editor/Managers/AddOnsManager.cs new file mode 100644 index 0000000..d2f9cd8 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Managers/AddOnsManager.cs @@ -0,0 +1,18 @@ +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Editor.Managers +{ + using Opsive.Shared.Editor.Managers; + + /// + /// Draws a list of all of the available add-ons. + /// + [OrderedEditorItem("Add-Ons", 12)] + public class AddOnsManager : Opsive.Shared.Editor.Managers.AddOnsManager + { + protected override string AddOnsURL => "https://opsive.com/asset/BehaviorDesigner/AddOnsList.txt"; + } +} \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Editor/Managers/AddOnsManager.cs.meta b/Packages/com.opsive.behaviordesigner/Editor/Managers/AddOnsManager.cs.meta new file mode 100644 index 0000000..4a6f743 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Managers/AddOnsManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cdcf33bfa5dc24248a6152f89300f0c2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Managers/AssetInfo.cs b/Packages/com.opsive.behaviordesigner/Editor/Managers/AssetInfo.cs new file mode 100644 index 0000000..91f6250 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Managers/AssetInfo.cs @@ -0,0 +1,19 @@ +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Editor.Managers +{ + /// + /// Static class defining information about the asset. + /// + public static class AssetInfo + { + public static string Version { get => "2.1.12"; } + + public static string Name { get => "Behavior Designer Pro"; } + + public static string PackageName => "com.opsive.behaviordesigner"; + } +} \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Editor/Managers/AssetInfo.cs.meta b/Packages/com.opsive.behaviordesigner/Editor/Managers/AssetInfo.cs.meta new file mode 100644 index 0000000..47c4fd4 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Managers/AssetInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fa07a5b0e063044478181a6a40bf038e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Managers/BehaviorMainWindow.cs b/Packages/com.opsive.behaviordesigner/Editor/Managers/BehaviorMainWindow.cs new file mode 100644 index 0000000..39a3728 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Managers/BehaviorMainWindow.cs @@ -0,0 +1,68 @@ +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Editor.Managers +{ + using Opsive.Shared.Editor.Managers; + using UnityEditor; + using UnityEngine; + + /// + /// The MainManagerWindow is an editor window which contains all of the sub managers. This window draws the high level menu options and draws + /// the selected sub manager. + /// + [InitializeOnLoad] + public class BehaviorMainWindow : MainManagerWindow + { + protected override string AssetName => AssetInfo.Name; + protected override string AssetVersion => AssetInfo.Version; + protected override string UpdateCheckURL => string.Format("https://opsive.com/asset/UpdateCheck.php?asset=BehaviorDesigner&type={0}&version={1}&unityversion={2}&devplatform={3}&targetplatform={4}", + AssetInfo.Name.Replace(" ", ""), AssetInfo.Version, Application.unityVersion, Application.platform, EditorUserBuildSettings.activeBuildTarget); + protected override string LatestVersionKey => "Opsive.BehaviorDesigner.Editor.LatestVersion"; + protected override string LastUpdateCheckKey => "Opsive.BehaviorDesigner.Editor.LastUpdateCheck"; + protected override string ManagerNamespace => "Opsive.BehaviorDesigner.Editor"; + + /// + /// Initializes the Main Manager. + /// + [MenuItem("Tools/Opsive/Behavior Designer/Welcome", false, 30)] + public static MainManagerWindow ShowWindow() + { + var window = EditorWindow.GetWindow(false, "Behavior Window"); + window.minSize = new Vector2(680, 670); + return window; + } + + /// + /// Initializes the Main Manager and shows the Samples Manager. + /// + [MenuItem("Tools/Opsive/Behavior Designer/Samples", false, 31)] + public static void ShowSamplesManagerWindow() + { + var window = ShowWindow(); + window.Open(typeof(SamplesManager)); + } + + /// + /// Initializes the Main Manager and shows the Integrations Manager. + /// + [MenuItem("Tools/Opsive/Behavior Designer/Integrations", false, 32)] + public static void ShowIntegrationsManagerWindow() + { + var window = ShowWindow(); + window.Open(typeof(IntegrationsManager)); + } + + /// + /// Initializes the Main Manager and shows the Add-Ons Manager. + /// + [MenuItem("Tools/Opsive/Behavior Designer/Add-Ons", false, 33)] + public static void ShowAddOnsManagerWindow() + { + var window = ShowWindow(); + window.Open(typeof(AddOnsManager)); + } + } +} \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Editor/Managers/BehaviorMainWindow.cs.meta b/Packages/com.opsive.behaviordesigner/Editor/Managers/BehaviorMainWindow.cs.meta new file mode 100644 index 0000000..b7bc7df --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Managers/BehaviorMainWindow.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7eb87493a412def42ab4459e90b63fad +timeCreated: 1500568651 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Managers/Images.meta b/Packages/com.opsive.behaviordesigner/Editor/Managers/Images.meta new file mode 100644 index 0000000..39f8df3 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Managers/Images.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 95d69bf54d5801d408dfe7e5f6aa0436 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Managers/Images/Editor.png b/Packages/com.opsive.behaviordesigner/Editor/Managers/Images/Editor.png new file mode 100644 index 0000000..cd8ace6 Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Managers/Images/Editor.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Managers/Images/Editor.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Managers/Images/Editor.png.meta new file mode 100644 index 0000000..3830a8b --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Managers/Images/Editor.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: d52eae9187aad5b41aff6dd60e49247a +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Managers/Images/Repository.png b/Packages/com.opsive.behaviordesigner/Editor/Managers/Images/Repository.png new file mode 100644 index 0000000..ce691df Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Managers/Images/Repository.png differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Managers/Images/Repository.png.meta b/Packages/com.opsive.behaviordesigner/Editor/Managers/Images/Repository.png.meta new file mode 100644 index 0000000..7e95041 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Managers/Images/Repository.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 020153b61b65cf34f82ccc9b186cb700 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Managers/IntegrationsManager.cs b/Packages/com.opsive.behaviordesigner/Editor/Managers/IntegrationsManager.cs new file mode 100644 index 0000000..ae5c8be --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Managers/IntegrationsManager.cs @@ -0,0 +1,18 @@ +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Editor.Managers +{ + using Opsive.Shared.Editor.Managers; + + /// + /// Draws a list of all of the available integrations. + /// + [OrderedEditorItem("Integrations", 11)] + public class IntegrationsManager : Opsive.Shared.Editor.Managers.IntegrationsManager + { + protected override string IntegrationsURL => "https://opsive.com/asset/BehaviorDesigner/IntegrationsList.txt"; + } +} \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Editor/Managers/IntegrationsManager.cs.meta b/Packages/com.opsive.behaviordesigner/Editor/Managers/IntegrationsManager.cs.meta new file mode 100644 index 0000000..8968dc8 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Managers/IntegrationsManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 722bac958cec61240b407653551d0dfc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Managers/Opsive.BehaviorDesigner.Editor.Managers.asmdef b/Packages/com.opsive.behaviordesigner/Editor/Managers/Opsive.BehaviorDesigner.Editor.Managers.asmdef new file mode 100644 index 0000000..25e125a --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Managers/Opsive.BehaviorDesigner.Editor.Managers.asmdef @@ -0,0 +1,29 @@ +{ + "name": "Opsive.BehaviorDesigner.Editor.Managers", + "rootNamespace": "Opsive.BehaviorDesigner.Editor.Managers", + "references": [ + "GUID:734d92eba21c94caba915361bd5ac177", + "GUID:e0cd26848372d4e5c891c569017e11f1", + "GUID:bbb15c76beca87041af309d0035105a2", + "GUID:27cb7fd045e5bb44f8c617ce69325b1d", + "GUID:97a55b351d7460f4f87d2ad07066bf4e", + "GUID:cf0567158f87e3c4c9be32bb870ec7b9" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [ + { + "name": "com.unity.entities", + "expression": "1.3.5", + "define": "UNITY_ENTITIES" + } + ], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Editor/Managers/Opsive.BehaviorDesigner.Editor.Managers.asmdef.meta b/Packages/com.opsive.behaviordesigner/Editor/Managers/Opsive.BehaviorDesigner.Editor.Managers.asmdef.meta new file mode 100644 index 0000000..fbb053a --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Managers/Opsive.BehaviorDesigner.Editor.Managers.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d923cf8fc4ca8464bb84bcfbec68a2ff +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Managers/SamplesManager.cs b/Packages/com.opsive.behaviordesigner/Editor/Managers/SamplesManager.cs new file mode 100644 index 0000000..03d8e2a --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Managers/SamplesManager.cs @@ -0,0 +1,24 @@ +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Editor.Managers +{ + using Opsive.Shared.Editor.Managers; + + /// + /// Draws a list of all of the available samples. + /// + [OrderedEditorItem("Samples", 10)] + public class SamplesManager :Manager + { + public override void BuildVisualElements() + { + ManagerUtility.ShowControlBox("Import Samples", "Imports the sample scenes. These scenes use the universal render pipeline.", null, "Import Samples", () => + { + ManagerUtility.ImportSample(AssetInfo.PackageName); + }, m_ManagerContentContainer, true); + } + } +} \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Editor/Managers/SamplesManager.cs.meta b/Packages/com.opsive.behaviordesigner/Editor/Managers/SamplesManager.cs.meta new file mode 100644 index 0000000..8ce200a --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Managers/SamplesManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3790a505de4b60244afbd23f13ead000 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Managers/Startup.cs b/Packages/com.opsive.behaviordesigner/Editor/Managers/Startup.cs new file mode 100644 index 0000000..fa5197e --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Managers/Startup.cs @@ -0,0 +1,72 @@ +#if !OPSIVE_IMPORT_DEBUG +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Editor.Managers +{ + using Opsive.Shared.Editor.Import; + using System.IO; + using UnityEditor; + using UnityEngine; + + /// + /// Shows the welcome screen and check for minimum installed packages. + /// + [InitializeOnLoad] + public class Startup + { + private const string c_ImportStatusPath = "Assets/Opsive/ImportStatus.asset"; + + /// + /// Perform editor checks as soon as the scripts are done compiling. + /// + static Startup() + { + EditorApplication.update += EditorStartup; + } + + /// + /// Show the editor window if it hasn't been shown before. + /// + private static void EditorStartup() + { + if (EditorApplication.isCompiling) { + return; + } + + EditorApplication.update -= EditorStartup; + AssetDatabase.Refresh(); + ImportStatus importStatus = null; + var importStatusAssets = AssetDatabase.FindAssets("t:ImportStatus"); + if (importStatusAssets != null && importStatusAssets.Length > 0) { + for (int i = 0; i < importStatusAssets.Length; ++i) { + var path = AssetDatabase.GUIDToAssetPath(importStatusAssets[i]); + if (string.IsNullOrEmpty(path)) { + path = importStatusAssets[i]; + } + importStatus = AssetDatabase.LoadAssetAtPath(path, typeof(ImportStatus)) as ImportStatus; + if (importStatus != null) { + break; + } + } + } + if (importStatus == null) { + // The import status hasn't been created yet. Create it in the same location as the Opsive folder. + importStatus = ScriptableObject.CreateInstance(); + Directory.CreateDirectory(Path.GetDirectoryName(c_ImportStatusPath)); + AssetDatabase.CreateAsset(importStatus, c_ImportStatusPath); + AssetDatabase.Refresh(); + } + + if (!importStatus.BehaviorWindowShown) { + var window = BehaviorMainWindow.ShowWindow(); + window.Open(typeof(WelcomeScreenManager)); + importStatus.BehaviorWindowShown = true; + EditorUtility.SetDirty(importStatus); + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Editor/Managers/Startup.cs.meta b/Packages/com.opsive.behaviordesigner/Editor/Managers/Startup.cs.meta new file mode 100644 index 0000000..2137502 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Managers/Startup.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9075c8a032fa68945bf2d25260aa36ee +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Managers/WelcomeScreenManager.cs b/Packages/com.opsive.behaviordesigner/Editor/Managers/WelcomeScreenManager.cs new file mode 100644 index 0000000..59d712d --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Managers/WelcomeScreenManager.cs @@ -0,0 +1,181 @@ +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Editor.Managers +{ + using Opsive.Shared.Editor.Managers; + using UnityEditor; + using UnityEngine.UIElements; + + /// + /// Shows a starting window with useful links. + /// + [OrderedEditorItem("Welcome", 0)] + public class WelcomeScreenManager : Opsive.Shared.Editor.Managers.WelcomeScreenManager + { + private const string c_GraphDesignerSymbol = "GRAPH_DESIGNER"; + private const string c_EditorTextureGUID = "d52eae9187aad5b41aff6dd60e49247a"; + private const string c_RepositoryTextureGUID = "020153b61b65cf34f82ccc9b186cb700"; + + private VisualElement m_EntityHelpBoxContainer; + + /// + /// The name of the asset. + /// + protected override string AssetName => AssetInfo.Name; + + /// + /// The version of the asset. + /// + protected override string AssetVersion => AssetInfo.Version; + + /// + /// Should the large documentation image be added? + /// + protected override bool AddLargeDocumentationImage => false; + + /// + /// Returns the URL for the documentation page. + /// + /// The URL for the documentation page. + protected override string GetDocumentationURL() + { + return "https://opsive.com/support/documentation/behavior-designer-pro/"; + } + + /// + /// Returns the URL for the videos page. + /// + /// The URL for the videos page. + protected override string GetVideosURL() + { + return "https://opsive.com/videos?pid=28276"; + } + + /// + /// Returns the URL for the asset page. + /// + /// The URL for the asset page. + protected override string GetAssetURL() + { + return "https://assetstore.unity.com/packages/slug/298743"; + } + + /// + /// Checks to ensure the required packages are installed. + /// + /// The parent VisualElement. + protected override void AddHeader(VisualElement parent) + { + EditorApplication.update += CheckForEntities; + +#if !UNITY_ENTITIES + m_EntityHelpBoxContainer = ManagerUtility.AddHelpBox(parent, "Behavior Designer requires the Entities package. Press the button below to install.", HelpBoxMessageType.Error, "Install", (HelpBox helpbox, Button actionButton) => + { + helpbox.text = "Installing the entities package. Unity will reimport after the package has been installed.\n\n" + + "Restart Unity if you receive compiler errors after Unity has reimported.\n\n" + + "Behavior Designer can be access from the Tools/Opsive/Behavior Designer/Editor menu."; + helpbox.messageType = HelpBoxMessageType.Info; + actionButton.SetEnabled(false); + m_WelcomeLabel.style.display = DisplayStyle.None; + + UnityEditor.PackageManager.Client.Add("com.unity.entities"); + }); + m_WelcomeLabel.style.display = DisplayStyle.None; +#else + base.AddHeader(parent); +#endif + } + + /// + /// Checks for the Entity package installation. + /// + private void CheckForEntities() + { +#if !GRAPH_DESIGNER && UNITY_ENTITIES + AddSymbol(c_GraphDesignerSymbol); + EditorApplication.update -= CheckForEntities; + + if (m_EntityHelpBoxContainer != null) { + m_EntityHelpBoxContainer.style.display = DisplayStyle.None; + m_WelcomeLabel.style.display = DisplayStyle.Flex; + } +#elif GRAPH_DESIGNER + if (m_EntityHelpBoxContainer != null) { + m_EntityHelpBoxContainer.style.display = DisplayStyle.None; + m_WelcomeLabel.style.display = DisplayStyle.Flex; + } +#endif + } + + /// + /// Adds the specified symbol to the compiler definitions. + /// + /// The symbol to add. + private static void AddSymbol(string symbol) + { + // Set on all available build targets. + var buildTargets = System.Enum.GetValues(typeof(BuildTarget)) as BuildTarget[]; + foreach (var buildTarget in buildTargets) { + if (buildTarget is BuildTarget.NoTarget) { + continue; + } + + var buildTargetGroup = BuildPipeline.GetBuildTargetGroup(buildTarget); + if (!BuildPipeline.IsBuildTargetSupported(buildTargetGroup, buildTarget)) { + continue; + } + +#if UNITY_2023_1_OR_NEWER + var namedBuildTarget = UnityEditor.Build.NamedBuildTarget.FromBuildTargetGroup(buildTargetGroup); + var symbols = PlayerSettings.GetScriptingDefineSymbols(namedBuildTarget); +#else + var symbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTargetGroup); +#endif + if (symbols.Contains(symbol)) { + continue; + } + symbols += (";" + symbol); +#if UNITY_2023_1_OR_NEWER + PlayerSettings.SetScriptingDefineSymbols(namedBuildTarget, symbols); +#else + PlayerSettings.SetScriptingDefineSymbolsForGroup(buildTargetGroup, symbols); +#endif + } + } + + /// + /// Adds the resource images to the parent element. + /// + /// The parent that the images should be added to. + protected override void AddImages(VisualElement parent) + { + AddLargeImage(parent, c_EditorTextureGUID, () => { +#if GRAPH_DESIGNER + BehaviorDesignerWindow.ShowWindow(); +#else + UnityEngine.Debug.LogError("Error: Unable to open the Behavior Designer window. Ensure the Entities package has been installed."); +#endif + }); + + // Documentation and Videos. + AddImageRow(parent, c_SmallDocumentationTextureGUID, GetDocumentationURL(), + c_VideosTextureGUID, GetVideosURL()); + + // Repository and Downloads. + AddImageRow(parent, c_RepositoryTextureGUID, "https://opsive.com/assets/behavior-designer-pro-subscription", + c_DownloadsTextureGUID, IntegrationsManager.GetDownloadsLink()); + + // Forum and Discord. + AddImageRow(parent, c_ForumTextureGUID, "https://opsive.com/forum/", + c_DiscordTextureGUID, "https://discord.gg/QX6VFgc"); + // Review and Showcase. + AddImageRow(parent, c_ReviewTextureGUID, GetAssetURL(), + c_ShowcaseTextureGUID, "https://opsive.com/showcase/"); + // Professional Services. + AddImageRow(parent, c_ProfessionalServicesTextureGUID, "https://opsive.com", string.Empty, string.Empty); + } + } +} \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Editor/Managers/WelcomeScreenManager.cs.meta b/Packages/com.opsive.behaviordesigner/Editor/Managers/WelcomeScreenManager.cs.meta new file mode 100644 index 0000000..8d9eeb6 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Managers/WelcomeScreenManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5b1cb06d692d68543b5f50cb2c132e42 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/NodeViews.meta b/Packages/com.opsive.behaviordesigner/Editor/NodeViews.meta new file mode 100644 index 0000000..fd7436f --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/NodeViews.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ef9baff9776e9c84fb838d40b31cff61 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/NodeViews/EventNodeViewControl.cs b/Packages/com.opsive.behaviordesigner/Editor/NodeViews/EventNodeViewControl.cs new file mode 100644 index 0000000..e3c60db --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/NodeViews/EventNodeViewControl.cs @@ -0,0 +1,118 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Editor.Controls.NodeViews +{ + using Opsive.Shared.Editor.UIElements.Controls; + using Opsive.BehaviorDesigner.Runtime; + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.BehaviorDesigner.Runtime.Tasks; + using Opsive.GraphDesigner.Editor; + using Opsive.GraphDesigner.Editor.Controls.NodeViews; + using Opsive.GraphDesigner.Editor.Elements; + using Opsive.GraphDesigner.Editor.Events; + using Opsive.GraphDesigner.Runtime; + using Unity.Entities; + using UnityEngine.UIElements; + using UnityEngine; + using UnityEditor; + + /// + /// Adds UI elements within the event node. + /// + [ControlType(typeof(IEventNode))] + public class EventNodeViewControl : NodeViewBase + { + private const string c_DarkSuccessIconGUID = "240eed9b6e6dc004f94216f1e9fcc390"; + private const string c_LightSuccessIconGUID = "cf3f27e8ca1f20f4680890e078c7613a"; + private const string c_DarkFailureIconGUID = "8d159db7a8da43e41a50a77e43cfd6ba"; + private const string c_LightFailureIconGUID = "c3622912d9f7bcd41a54a95add672423"; + + private IEventNode m_Node; + private GraphWindow m_GraphWindow; + private BehaviorTree m_BehaviorTree; + private EventNode m_EventNode; + + private Image m_ExecutionStatusIcon; + private Texture m_SuccessIcon; + private Texture m_FailureIcon; + + /// + /// Addes the UIElements for the specified runtime node to the editor Node within the graph. + /// + /// A reference to the GraphWindow. + /// The parent UIElement that should contain the node UIElements. + /// The node that the control represents. + public override void AddNodeView(GraphWindow graphWindow, VisualElement parent, object node) + { + graphWindow.rootVisualElement.styleSheets.Add(Shared.Editor.Utility.EditorUtility.LoadAsset("9c6834c10d404ac4b95be745f4411f96")); // TaskStyles.uss + + m_Node = node as IEventNode; + m_GraphWindow = graphWindow; + m_BehaviorTree = m_GraphWindow.Graph as BehaviorTree; + m_EventNode = parent.GetFirstAncestorOfType(); + + // AddNodeView can be called multiple times. Ensure there is only one execution status image. + var previousExecutionStatus = m_EventNode.Q("event-execution-status"); + if (previousExecutionStatus != null) { + previousExecutionStatus.parent.Remove(previousExecutionStatus); + } + m_ExecutionStatusIcon = new Image(); + m_ExecutionStatusIcon.name = "event-execution-status"; + parent.parent.Add(m_ExecutionStatusIcon); // The execution status icon should be placed behind every node element. + m_ExecutionStatusIcon.SendToBack(); + + m_SuccessIcon = Shared.Editor.Utility.EditorUtility.LoadAsset(EditorGUIUtility.isProSkin ? c_DarkSuccessIconGUID : c_LightSuccessIconGUID); + m_FailureIcon = Shared.Editor.Utility.EditorUtility.LoadAsset(EditorGUIUtility.isProSkin ? c_DarkFailureIconGUID : c_LightFailureIconGUID); + + m_ExecutionStatusIcon.RegisterCallback(c => + { + GraphEventHandler.RegisterEvent(GraphEventType.WindowUpdate, UpdateNode); + }); + m_ExecutionStatusIcon.RegisterCallback(c => + { + GraphEventHandler.UnregisterEvent(GraphEventType.WindowUpdate, UpdateNode); + }); + } + + /// + /// Updates the node with the current execution status icon. + /// + private void UpdateNode() + { + if (m_BehaviorTree == null || m_BehaviorTree.Entity == Entity.Null || m_Node.ConnectedIndex == ushort.MaxValue || !m_BehaviorTree.World.EntityManager.Exists(m_BehaviorTree.Entity)) { + return; + } + + var connectedNode = m_GraphWindow.Graph.LogicNodes[m_Node.ConnectedIndex]; + // The tree may not be initialized. + if (connectedNode.RuntimeIndex == ushort.MaxValue) { + return; + } + var taskComponents = m_BehaviorTree.World.EntityManager.GetBuffer(m_BehaviorTree.Entity); + var taskComponent = taskComponents[connectedNode.RuntimeIndex]; + if (taskComponent.Status == TaskStatus.Success) { + m_ExecutionStatusIcon.image = m_SuccessIcon; + } else if (taskComponent.Status == TaskStatus.Failure) { + m_ExecutionStatusIcon.image = m_FailureIcon; + } else if (m_ExecutionStatusIcon.image != null) { + m_ExecutionStatusIcon.image = null; + } + + if (m_ExecutionStatusIcon.image != null) { + m_ExecutionStatusIcon.style.width = m_ExecutionStatusIcon.image.width; + } + + if (taskComponent.Status == TaskStatus.Running || taskComponent.Status == TaskStatus.Queued) { + m_EventNode.SetColorState(ColorState.Active, 0); + } else { + var nodeIndex = m_GraphWindow.GraphEditor.GetNodeIndex(m_Node); + m_EventNode.SetColorState(m_GraphWindow.Graph.IsNodeEnabled(false, nodeIndex) ? ColorState.Default : ColorState.Disabled, 0.5f); + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Editor/NodeViews/EventNodeViewControl.cs.meta b/Packages/com.opsive.behaviordesigner/Editor/NodeViews/EventNodeViewControl.cs.meta new file mode 100644 index 0000000..1cbbe55 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/NodeViews/EventNodeViewControl.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6c90fafbcac7a174c9d9b765d9065ef0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/NodeViews/Opsive.BehaviorDesigner.Editor.Controls.NodeViews.asmdef b/Packages/com.opsive.behaviordesigner/Editor/NodeViews/Opsive.BehaviorDesigner.Editor.Controls.NodeViews.asmdef new file mode 100644 index 0000000..dba7113 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/NodeViews/Opsive.BehaviorDesigner.Editor.Controls.NodeViews.asmdef @@ -0,0 +1,32 @@ +{ + "name": "Opsive.BehaviorDesigner.Editor.Controls.NodeViews", + "rootNamespace": "", + "references": [ + "GUID:734d92eba21c94caba915361bd5ac177", + "GUID:d8b63aba1907145bea998dd612889d6b", + "GUID:e0cd26848372d4e5c891c569017e11f1", + "GUID:bbb15c76beca87041af309d0035105a2", + "GUID:27cb7fd045e5bb44f8c617ce69325b1d", + "GUID:f9fbcd65fc33f6847b0f124cf7e891b6", + "GUID:97a55b351d7460f4f87d2ad07066bf4e", + "GUID:cf0567158f87e3c4c9be32bb870ec7b9", + "GUID:e9319bc8ab9315745bdf80aeffa01d6d" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [ + { + "name": "com.unity.entities", + "expression": "1.3.5", + "define": "UNITY_ENTITIES" + } + ], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Editor/NodeViews/Opsive.BehaviorDesigner.Editor.Controls.NodeViews.asmdef.meta b/Packages/com.opsive.behaviordesigner/Editor/NodeViews/Opsive.BehaviorDesigner.Editor.Controls.NodeViews.asmdef.meta new file mode 100644 index 0000000..fcb9f7f --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/NodeViews/Opsive.BehaviorDesigner.Editor.Controls.NodeViews.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 98e4b74cf0784f4458e03260557a6cc4 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/NodeViews/PriorityEvaluatorNodeViewControl.cs b/Packages/com.opsive.behaviordesigner/Editor/NodeViews/PriorityEvaluatorNodeViewControl.cs new file mode 100644 index 0000000..95000b2 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/NodeViews/PriorityEvaluatorNodeViewControl.cs @@ -0,0 +1,95 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Editor.Controls.NodeViews +{ + using Opsive.GraphDesigner.Editor; + using Opsive.GraphDesigner.Editor.Events; + using Opsive.GraphDesigner.Runtime; + using Opsive.BehaviorDesigner.Runtime; + using Opsive.BehaviorDesigner.Runtime.Systems; + using Opsive.BehaviorDesigner.Runtime.Tasks.Decorators; + using Opsive.Shared.Editor.UIElements.Controls; + using Unity.Entities; + using UnityEngine; + using UnityEngine.UIElements; + + /// + /// Implements TypeControlBase for the PriorityEvaluator type. + /// + [ControlType(typeof(PriorityEvaluator))] + public class PriorityEvaluatorNodeViewControl : TaskNodeViewControl + { + private BehaviorTree m_BehaviorTree; + private ILogicNode m_Node; + private ushort m_PriorityEvaluatorComponentIndex = ushort.MaxValue; + + private Label m_PriorityValueLabel; + + /// + /// Addes the UIElements for the specified runtime node to the editor Node within the graph. + /// + /// A reference to the GraphWindow. + /// The parent UIElement that should contain the node UIElements. + /// The node that the control represents. + public override void AddNodeView(GraphWindow graphWindow, VisualElement parent, object node) + { + base.AddNodeView(graphWindow, parent, node); + + if (!Application.isPlaying) { + return; + } + + m_BehaviorTree = graphWindow.Graph as BehaviorTree; + m_Node = node as ILogicNode; + + parent.RegisterCallback(c => + { + GraphEventHandler.RegisterEvent(GraphEventType.WindowUpdate, UpdateUtilityValue); + }); + parent.RegisterCallback(c => + { + GraphEventHandler.UnregisterEvent(GraphEventType.WindowUpdate, UpdateUtilityValue); + }); + + m_PriorityValueLabel = new Label(); + m_PriorityValueLabel.style.alignSelf = Align.Center; + parent.Add(m_PriorityValueLabel); + } + + /// + /// Updates the utility value. + /// + private void UpdateUtilityValue() + { + if (m_BehaviorTree == null || m_BehaviorTree.Entity == Entity.Null || m_Node.RuntimeIndex == ushort.MaxValue) { + return; + } + + var taskObjectComponents = m_BehaviorTree.World.EntityManager.GetBuffer(m_BehaviorTree.Entity); + if (m_PriorityEvaluatorComponentIndex == ushort.MaxValue) { + // Find the corresponding index of the TaskObject. + for (int i = 0; i < taskObjectComponents.Length; ++i) { + if (taskObjectComponents[i].Index == m_Node.RuntimeIndex) { + m_PriorityEvaluatorComponentIndex = (ushort)i; + break; + } + } + + if (m_PriorityEvaluatorComponentIndex == ushort.MaxValue) { + return; + } + } + + var priorityEvaluator = m_BehaviorTree.GetTask(taskObjectComponents[m_PriorityEvaluatorComponentIndex].Index) as PriorityEvaluator; + if (priorityEvaluator == null) { + return; + } + m_PriorityValueLabel.text = "Value: " + priorityEvaluator.GetPriorityValue(); + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Editor/NodeViews/PriorityEvaluatorNodeViewControl.cs.meta b/Packages/com.opsive.behaviordesigner/Editor/NodeViews/PriorityEvaluatorNodeViewControl.cs.meta new file mode 100644 index 0000000..fd08bbd --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/NodeViews/PriorityEvaluatorNodeViewControl.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a9387930721f1dd42909d2053f5063ef +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/NodeViews/StackedTaskNodeViewControl.cs b/Packages/com.opsive.behaviordesigner/Editor/NodeViews/StackedTaskNodeViewControl.cs new file mode 100644 index 0000000..dc778f0 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/NodeViews/StackedTaskNodeViewControl.cs @@ -0,0 +1,134 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Editor.Controls.NodeViews +{ + using Opsive.GraphDesigner.Editor; + using Opsive.BehaviorDesigner.Runtime.Tasks; + using Opsive.Shared.Editor.UIElements.Controls; + using UnityEngine.UIElements; + using UnityEditor; + using UnityEngine; + + /// + /// Implements TypeControlBase for the StackedTask type. + /// + [ControlType(typeof(StackedTask))] + public class StackedTaskNodeViewControl : TaskNodeViewControl + { + private const float c_ActiveIconRotationSpeed = 30; + + /// + /// Displays information about the nested task within the Stacked Task. + /// + private class TaskView : VisualElement + { + private const string c_DarkActiveIconGUID = "1230b934cbd748345b13125468a34720"; + private const string c_LightActiveIconGUID = "e57f179ee476f274dbe537179e67bf04"; + + private int m_Index; + private Image m_ActiveImage; + private float m_CurrentRotation; + + /// + /// TaskView constructor. + /// + /// The index of the task. + /// A reference to the task. + public TaskView(int index, Task task) + { + m_Index = index; + + var horizontalLayout = new VisualElement(); + horizontalLayout.AddToClassList("horizontal-layout"); + horizontalLayout.style.height = 18; + var label = new Label(task.ToString()); + label.style.flexGrow = 1; + horizontalLayout.Add(label); + m_ActiveImage = new Image(); + m_ActiveImage.image = Shared.Editor.Utility.EditorUtility.LoadAsset(EditorGUIUtility.isProSkin ? c_DarkActiveIconGUID : c_LightActiveIconGUID); + m_ActiveImage.style.width = 16; + m_ActiveImage.style.height = 16; + m_ActiveImage.style.display = DisplayStyle.None; + horizontalLayout.Add(m_ActiveImage); + + Add(horizontalLayout); + } + + /// + /// Updates the status of the task. + /// + /// The index that is active. + public void UpdateStatus(int activeIndex) + { + m_ActiveImage.style.display = (m_Index == activeIndex ? DisplayStyle.Flex : DisplayStyle.None); + if (m_Index == activeIndex) { + if (Application.isPlaying) { + m_CurrentRotation += c_ActiveIconRotationSpeed; + m_ActiveImage.style.rotate = new Rotate(Angle.Degrees(m_CurrentRotation)); + } + } else { + m_CurrentRotation = 0f; + m_ActiveImage.style.rotate = new Rotate(Angle.Degrees(0f)); + } + } + } + + private StackedTask m_StackedTask; + private TaskView[] m_TaskViews; + + /// + /// Addes the UIElements for the specified runtime node to the editor Node within the graph. + /// + /// A reference to the GraphWindow. + /// The parent UIElement that should contain the node UIElements. + /// The node that the control represents. + public override void AddNodeView(GraphWindow graphWindow, VisualElement parent, object node) + { + base.AddNodeView(graphWindow, parent, node); + + m_StackedTask = node as StackedTask; + if (m_StackedTask.Tasks == null) { + return; + } + + var tasks = m_StackedTask.Tasks; + m_TaskViews = new TaskView[tasks.Length]; + for (int i = 0; i < tasks.Length; ++i) { + var task = m_StackedTask.Tasks[i]; + // The task no longer exists. Replace it. + if (task == null) { + tasks[i] = new UnknownTask(); + m_StackedTask.Tasks = tasks; + } + m_TaskViews[i] = new TaskView(i, m_StackedTask.Tasks[i]); + parent.Add(m_TaskViews[i]); + } + } + + /// + /// Internal method which updates the node with the current execution status. + /// + /// The status of the task. + protected override TaskStatus UpdateNodeInternal() + { + var activeIndex = -1; + TaskStatus status; + if ((status = base.UpdateNodeInternal()) == TaskStatus.Running && m_StackedTask.Tasks.Length > 1) { + activeIndex = m_StackedTask.ActiveIndex; + for (int i = 0; i < m_TaskViews.Length; ++i) { + m_TaskViews[i].UpdateStatus(activeIndex); + } + } else { + for (int i = 0; i < m_TaskViews.Length; ++i) { + m_TaskViews[i].UpdateStatus(activeIndex); + } + } + return status; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Editor/NodeViews/StackedTaskNodeViewControl.cs.meta b/Packages/com.opsive.behaviordesigner/Editor/NodeViews/StackedTaskNodeViewControl.cs.meta new file mode 100644 index 0000000..9d011c5 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/NodeViews/StackedTaskNodeViewControl.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 40ae380983a04824fb14ea4a89343e87 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/NodeViews/TaskNodeViewControl.cs b/Packages/com.opsive.behaviordesigner/Editor/NodeViews/TaskNodeViewControl.cs new file mode 100644 index 0000000..8b14d13 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/NodeViews/TaskNodeViewControl.cs @@ -0,0 +1,288 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Editor.Controls.NodeViews +{ + using Opsive.Shared.Editor.UIElements.Controls; + using Opsive.BehaviorDesigner.Runtime; + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.BehaviorDesigner.Runtime.Tasks; + using Opsive.GraphDesigner.Editor; + using Opsive.GraphDesigner.Editor.Controls.NodeViews; + using Opsive.GraphDesigner.Editor.Elements; + using Opsive.GraphDesigner.Editor.Events; + using Opsive.GraphDesigner.Runtime; + using Unity.Entities; + using UnityEngine.UIElements; + using UnityEngine; + using UnityEditor; + + /// + /// Adds UI elements within the task node. + /// + [ControlType(typeof(IAction))] + [ControlType(typeof(IConditional))] + [ControlType(typeof(IComposite))] + [ControlType(typeof(IDecorator))] + public class TaskNodeViewControl : NodeViewBase + { + private const string c_DarkConditionalAbortLowerPriorityIconGUID = "ba6528926e3f4f7438d3b9737f595ec6"; + private const string c_LightConditionalAbortLowerPriorityIconGUID = "20be04a2e46cb9d40b601dccdfbe153b"; + private const string c_DarkConditionalAbortSelfIconGUID = "ff3ba64f23e708645b24cc7509b5ebe5"; + private const string c_LightConditionalAbortSelfIconGUID = "5d44e66bacdbe51408dd30e519c2b318"; + private const string c_DarkConditionalAbortBothIconGUID = "1c01950cc0f1c994cb5ff3576969ebbf"; + private const string c_LightConditionalAbortBothIconGUID = "90b22fc04519bdb44b4d83665e86381d"; + + private const string c_DarkSuccessIconGUID = "240eed9b6e6dc004f94216f1e9fcc390"; + private const string c_LightSuccessIconGUID = "cf3f27e8ca1f20f4680890e078c7613a"; + private const string c_DarkSuccessReevaluateIconGUID = "0a5037ce131729b4fa0ffa9e1e13d387"; + private const string c_LightSuccessReevaluateIconGUID = "bba6bdc3af0aac44dadd1ca3a8485b05"; + private const string c_DarkFailureIconGUID = "8d159db7a8da43e41a50a77e43cfd6ba"; + private const string c_LightFailureIconGUID = "c3622912d9f7bcd41a54a95add672423"; + private const string c_DarkFailureReevaluateIconGUID = "26de8afeb313fd84291f98e68db44df7"; + private const string c_LightFailureReevaluateIconGUID = "5a6d713911c8ec3488639e2934329033"; + + private ILogicNode m_Node; + private GraphWindow m_GraphWindow; + private BehaviorTree m_BehaviorTree; + + private Image m_ExecutionStatusIcon; + private Image m_ConditionalAbortIcon; + private LogicNode m_LogicNode; + + private Texture m_SuccessIcon; + private Texture m_SuccessReevaluateIcon; + private Texture m_FailureIcon; + private Texture m_FailureReevaluateIcon; + + /// + /// Addes the UIElements for the specified runtime node to the editor Node within the graph. + /// + /// A reference to the GraphWindow. + /// The parent UIElement that should contain the node UIElements. + /// The node that the control represents. + public override void AddNodeView(GraphWindow graphWindow, VisualElement parent, object node) + { + graphWindow.rootVisualElement.styleSheets.Add(Shared.Editor.Utility.EditorUtility.LoadAsset("9c6834c10d404ac4b95be745f4411f96")); // TaskStyles.uss + + m_Node = node as ILogicNode; + m_GraphWindow = graphWindow; + m_BehaviorTree = m_GraphWindow.Graph as BehaviorTree; + m_LogicNode = parent.GetFirstAncestorOfType(); + + if (node is IConditionalAbortParent conditionalAbortParent) { + m_ConditionalAbortIcon = new Image(); + m_ConditionalAbortIcon.name = "conditional-abort-icon"; + parent.parent.Add(m_ConditionalAbortIcon); + SetConditionalAbortIcon(conditionalAbortParent); + + m_ConditionalAbortIcon.RegisterCallback(c => + { + GraphEventHandler.RegisterEvent(GraphEventType.NodeValueUpdated, UpdateNodeValue); + }); + m_ConditionalAbortIcon.RegisterCallback(c => + { + GraphEventHandler.UnregisterEvent(GraphEventType.NodeValueUpdated, UpdateNodeValue); + }); + } + + // Subtree references can click into its references. + if (m_Node is ISubtreeReference) { + m_LogicNode.RegisterCallback(OnSubtreeRferenceMouseDown); + } + + // AddNodeView can be called multiple times. Ensure there is only one execution status image. + var previousExecutionStatus = m_LogicNode.Q("execution-status"); + if (previousExecutionStatus != null) { + previousExecutionStatus.parent.Remove(previousExecutionStatus); + } + m_ExecutionStatusIcon = new Image(); + m_ExecutionStatusIcon.name = "execution-status"; + parent.parent.Add(m_ExecutionStatusIcon); // The execution status icon should be placed behind every node element. + m_ExecutionStatusIcon.SendToBack(); + + m_SuccessIcon = Shared.Editor.Utility.EditorUtility.LoadAsset(EditorGUIUtility.isProSkin ? c_DarkSuccessIconGUID : c_LightSuccessIconGUID); + m_SuccessReevaluateIcon = Shared.Editor.Utility.EditorUtility.LoadAsset(EditorGUIUtility.isProSkin ? c_DarkSuccessReevaluateIconGUID : c_LightSuccessReevaluateIconGUID); + m_FailureIcon = Shared.Editor.Utility.EditorUtility.LoadAsset(EditorGUIUtility.isProSkin ? c_DarkFailureIconGUID : c_LightFailureIconGUID); + m_FailureReevaluateIcon = Shared.Editor.Utility.EditorUtility.LoadAsset(EditorGUIUtility.isProSkin ? c_DarkFailureReevaluateIconGUID : c_LightFailureReevaluateIconGUID); + + m_ExecutionStatusIcon.RegisterCallback(c => + { + GraphEventHandler.RegisterEvent(GraphEventType.WindowUpdate, UpdateNode); + m_GraphWindow.OnSelectionChange += OnSelectionChange; + }); + m_ExecutionStatusIcon.RegisterCallback(c => + { + GraphEventHandler.UnregisterEvent(GraphEventType.WindowUpdate, UpdateNode); + m_GraphWindow.OnSelectionChange -= OnSelectionChange; + }); + OnSelectionChange(Selection.activeObject); + } + + /// + /// Sets the conditional abort icon. + /// + /// The conditional abort node. + private void SetConditionalAbortIcon(IConditionalAbortParent conditionalAbortParent) + { + if (conditionalAbortParent.AbortType == ConditionalAbortType.LowerPriority) { + m_ConditionalAbortIcon.image = Shared.Editor.Utility.EditorUtility.LoadAsset(EditorGUIUtility.isProSkin ? c_DarkConditionalAbortLowerPriorityIconGUID : c_LightConditionalAbortLowerPriorityIconGUID); + } else if (conditionalAbortParent.AbortType == ConditionalAbortType.Self) { + m_ConditionalAbortIcon.image = Shared.Editor.Utility.EditorUtility.LoadAsset(EditorGUIUtility.isProSkin ? c_DarkConditionalAbortSelfIconGUID : c_LightConditionalAbortSelfIconGUID); + } else if (conditionalAbortParent.AbortType == ConditionalAbortType.Both) { + m_ConditionalAbortIcon.image = Shared.Editor.Utility.EditorUtility.LoadAsset(EditorGUIUtility.isProSkin ? c_DarkConditionalAbortBothIconGUID : c_LightConditionalAbortBothIconGUID); + } else { + m_ConditionalAbortIcon.image = null; + } + } + + /// + /// A value has been updated for the specified node. + /// + /// The node that has been updated. + private void UpdateNodeValue(object node) + { + if (node != m_Node) { + return; + } + + SetConditionalAbortIcon(node as IConditionalAbortParent); + } + + /// + /// Updates the node with the current execution status. + /// + private void UpdateNode() + { + UpdateNodeInternal(); + } + + /// + /// Internal method which updates the node with the current execution status. + /// + /// The status of the task. + protected virtual TaskStatus UpdateNodeInternal() + { + if (m_BehaviorTree == null || m_BehaviorTree.Entity == Entity.Null || m_Node.RuntimeIndex == ushort.MaxValue || !m_BehaviorTree.World.EntityManager.Exists(m_BehaviorTree.Entity)) { + // The task is no longer active. Reset the status while keeping the previous execution state. + m_LogicNode.SetColorState(m_GraphWindow.GraphEditor.IsNodeHierarchyEnabled(m_Node) ? ColorState.Default : ColorState.Disabled, 0.5f); + if (m_ExecutionStatusIcon.image != null) { + if (m_ExecutionStatusIcon.image == m_SuccessReevaluateIcon) { + m_ExecutionStatusIcon.image = m_SuccessIcon; + } else if (m_ExecutionStatusIcon.image == m_FailureReevaluateIcon) { + m_ExecutionStatusIcon.image = m_FailureIcon; + } + m_ExecutionStatusIcon.style.width = m_ExecutionStatusIcon.image.width; + } + return TaskStatus.Inactive; + } + + var taskComponents = m_BehaviorTree.World.EntityManager.GetBuffer(m_BehaviorTree.Entity); + var taskComponent = taskComponents[m_Node.RuntimeIndex]; + if (taskComponent.Status == TaskStatus.Success) { + if (taskComponent.Reevaluate) { + m_ExecutionStatusIcon.image = m_SuccessReevaluateIcon; + } else { + m_ExecutionStatusIcon.image = m_SuccessIcon; + } + } else if (taskComponent.Status == TaskStatus.Failure) { + if (taskComponent.Reevaluate) { + m_ExecutionStatusIcon.image = m_FailureReevaluateIcon; + } else { + m_ExecutionStatusIcon.image = m_FailureIcon; + } + } else if (m_ExecutionStatusIcon.image != null) { + m_ExecutionStatusIcon.image = null; + } + + if (m_ExecutionStatusIcon.image != null) { + m_ExecutionStatusIcon.style.width = m_ExecutionStatusIcon.image.width; + } + + if (taskComponent.Status == TaskStatus.Running || taskComponent.Status == TaskStatus.Queued) { + m_LogicNode.SetColorState(ColorState.Active, 0); + } else { + m_LogicNode.SetColorState(m_GraphWindow.GraphEditor.IsNodeHierarchyEnabled(m_Node) ? ColorState.Default : ColorState.Disabled, 0.5f); + } + return taskComponent.Status; + } + + /// + /// Enables or disables the NodeView. + /// + /// True if the NodeView is enabled. + public override void SetEnabled(bool enable) + { + if (m_ConditionalAbortIcon != null) { + m_ConditionalAbortIcon.SetEnabled(enable); + } + } + + /// + /// The mouse has been pressed. + /// + /// The event that triggered the press. + private void OnSubtreeRferenceMouseDown(MouseDownEvent evt) + { + if (evt.clickCount != 2) { + return; + } + + var subtreeReference = m_Node as ISubtreeReference; + if (subtreeReference.Subtrees == null) { + return; + } + + for (int i = 0; i < subtreeReference.Subtrees.Length; ++i) { + var subtree = subtreeReference.Subtrees[i]; + if (subtree == null) { + continue; + } + + Selection.activeObject = subtree; + } + } + + /// + /// The GraphWindow selection has changed. + /// + /// The new selection. + private void OnSelectionChange(UnityEngine.Object selection) + { + if (!Application.isPlaying || m_BehaviorTree == null || m_BehaviorTree.Entity == Entity.Null || !m_BehaviorTree.enabled || !m_BehaviorTree.Baked) { + return; + } + + // The behavior tree was baked. Ensure the BehaviorTree component is pointing to the correct Entity. + var worlds = World.All; + var foundEntity = false; + for (int i = 0; i < worlds.Count; ++i) { + var defaultEntities = worlds[i].EntityManager.GetAllEntities(Unity.Collections.Allocator.Temp); + if (defaultEntities != null) { + var originalGuid = m_BehaviorTree.World.EntityManager.GetComponentData(m_BehaviorTree.Entity); + + foreach (var defaultEntity in defaultEntities) { + if (worlds[i].EntityManager.HasComponent(defaultEntity)) { + var entityGuid = worlds[i].EntityManager.GetComponentData(defaultEntity); + if (originalGuid.OriginatingId == entityGuid.OriginatingId) { + m_BehaviorTree.World = worlds[i]; + m_BehaviorTree.Entity = defaultEntity; + foundEntity = true; + break; + } + } + } + defaultEntities.Dispose(); + if (foundEntity) { + m_BehaviorTree.Baked = false; + break; + } + } + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Editor/NodeViews/TaskNodeViewControl.cs.meta b/Packages/com.opsive.behaviordesigner/Editor/NodeViews/TaskNodeViewControl.cs.meta new file mode 100644 index 0000000..0057d33 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/NodeViews/TaskNodeViewControl.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 34ab799a714c2db4ab2d69566510bfc4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/NodeViews/UtilityEvaluatorNodeViewControl.cs b/Packages/com.opsive.behaviordesigner/Editor/NodeViews/UtilityEvaluatorNodeViewControl.cs new file mode 100644 index 0000000..67fda65 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/NodeViews/UtilityEvaluatorNodeViewControl.cs @@ -0,0 +1,95 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Editor.Controls.NodeViews +{ + using Opsive.GraphDesigner.Editor; + using Opsive.GraphDesigner.Editor.Events; + using Opsive.GraphDesigner.Runtime; + using Opsive.BehaviorDesigner.Runtime; + using Opsive.BehaviorDesigner.Runtime.Systems; + using Opsive.BehaviorDesigner.Runtime.Tasks.Decorators; + using Opsive.Shared.Editor.UIElements.Controls; + using Unity.Entities; + using UnityEngine; + using UnityEngine.UIElements; + + /// + /// Implements TypeControlBase for the UtilityEvaluator type. + /// + [ControlType(typeof(UtilityEvaluator))] + public class UtilityEvaluatorNodeViewControl : TaskNodeViewControl + { + private BehaviorTree m_BehaviorTree; + private ILogicNode m_Node; + private ushort m_UtilityEvaluatorComponentIndex = ushort.MaxValue; + + private Label m_UtilityValueLabel; + + /// + /// Addes the UIElements for the specified runtime node to the editor Node within the graph. + /// + /// A reference to the GraphWindow. + /// The parent UIElement that should contain the node UIElements. + /// The node that the control represents. + public override void AddNodeView(GraphWindow graphWindow, VisualElement parent, object node) + { + base.AddNodeView(graphWindow, parent, node); + + if (!Application.isPlaying) { + return; + } + + m_BehaviorTree = graphWindow.Graph as BehaviorTree; + m_Node = node as ILogicNode; + + parent.RegisterCallback(c => + { + GraphEventHandler.RegisterEvent(GraphEventType.WindowUpdate, UpdateUtilityValue); + }); + parent.RegisterCallback(c => + { + GraphEventHandler.UnregisterEvent(GraphEventType.WindowUpdate, UpdateUtilityValue); + }); + + m_UtilityValueLabel = new Label(); + m_UtilityValueLabel.style.alignSelf = Align.Center; + parent.Add(m_UtilityValueLabel); + } + + /// + /// Updates the utility value. + /// + private void UpdateUtilityValue() + { + if (m_BehaviorTree == null || m_BehaviorTree.Entity == Entity.Null || m_Node.RuntimeIndex == ushort.MaxValue) { + return; + } + + var taskObjectComponents = m_BehaviorTree.World.EntityManager.GetBuffer(m_BehaviorTree.Entity); + if (m_UtilityEvaluatorComponentIndex == ushort.MaxValue) { + // Find the corresponding index of the TaskObject. + for (int i = 0; i < taskObjectComponents.Length; ++i) { + if (taskObjectComponents[i].Index == m_Node.RuntimeIndex) { + m_UtilityEvaluatorComponentIndex = (ushort)i; + break; + } + } + + if (m_UtilityEvaluatorComponentIndex == ushort.MaxValue) { + return; + } + } + + var utilityEvaluator = m_BehaviorTree.GetTask(taskObjectComponents[m_UtilityEvaluatorComponentIndex].Index) as UtilityEvaluator; + if (utilityEvaluator == null) { + return; + } + m_UtilityValueLabel.text = "Value: " + System.Math.Round(utilityEvaluator.GetUtilityValue(), 3); + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Editor/NodeViews/UtilityEvaluatorNodeViewControl.cs.meta b/Packages/com.opsive.behaviordesigner/Editor/NodeViews/UtilityEvaluatorNodeViewControl.cs.meta new file mode 100644 index 0000000..ecb0e9e --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/NodeViews/UtilityEvaluatorNodeViewControl.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a1a209242018ecc418ad24f5427f88f1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/NodeViews/WaitNodeViewControl.cs b/Packages/com.opsive.behaviordesigner/Editor/NodeViews/WaitNodeViewControl.cs new file mode 100644 index 0000000..39e3c31 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/NodeViews/WaitNodeViewControl.cs @@ -0,0 +1,111 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Editor.Controls.NodeViews +{ + using Opsive.BehaviorDesigner.Runtime; + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.BehaviorDesigner.Runtime.Tasks.Actions; + using Opsive.GraphDesigner.Editor; + using Opsive.GraphDesigner.Editor.Events; + using Opsive.GraphDesigner.Runtime; + using Opsive.Shared.Editor.UIElements.Controls; + using Unity.Entities; + using UnityEngine; + using UnityEngine.UIElements; + + /// + /// Implements TypeControlBase for the Wait type. + /// + [ControlType(typeof(Wait))] + public class WaitNodeViewControl : TaskNodeViewControl + { + private BehaviorTree m_BehaviorTree; + private ILogicNode m_Node; + private ushort m_WaitComponentIndex = ushort.MaxValue; + private ProgressBar m_ProgressBar; + + /// + /// Addes the UIElements for the specified runtime node to the editor Node within the graph. + /// + /// A reference to the GraphWindow. + /// The parent UIElement that should contain the node UIElements. + /// The node that the control represents. + public override void AddNodeView(GraphWindow graphWindow, VisualElement parent, object node) + { + base.AddNodeView(graphWindow, parent, node); + + if (!Application.isPlaying) { + return; + } + + m_BehaviorTree = graphWindow.Graph as BehaviorTree; + m_Node = node as ILogicNode; + + parent.RegisterCallback(c => + { + GraphEventHandler.RegisterEvent(GraphEventType.WindowUpdate, UpdateWaitProgress); + }); + parent.RegisterCallback(c => + { + GraphEventHandler.UnregisterEvent(GraphEventType.WindowUpdate, UpdateWaitProgress); + }); + + m_ProgressBar = new ProgressBar(); + parent.Add(m_ProgressBar); + } + + /// + /// Updates the wait progress bar. + /// + private void UpdateWaitProgress() + { + if (m_BehaviorTree == null || m_BehaviorTree.Entity == Entity.Null || m_Node.RuntimeIndex == ushort.MaxValue) { + m_ProgressBar.style.display = DisplayStyle.None; + return; + } + + var waitComponents = m_BehaviorTree.World.EntityManager.GetBuffer(m_BehaviorTree.Entity); + if (m_WaitComponentIndex == ushort.MaxValue) { + // Find the corresponding index of the WaitComponent. + for (int i = 0; i < waitComponents.Length; ++i) { + if (waitComponents[i].Index == m_Node.RuntimeIndex) { + m_WaitComponentIndex = (ushort)i; + break; + } + } + + if (m_WaitComponentIndex == ushort.MaxValue) { + return; + } + } + + var waitComponent = waitComponents[m_WaitComponentIndex]; + if (waitComponent.PauseTime != 0) { + return; + } + m_ProgressBar.highValue = (float)waitComponent.WaitDuration; + + var taskComponents = m_BehaviorTree.World.EntityManager.GetBuffer(m_BehaviorTree.Entity); + var elapsed = -1f; + if (taskComponents[m_Node.RuntimeIndex].Status == Runtime.Tasks.TaskStatus.Running) { + elapsed = Mathf.Clamp(Time.time - (float)waitComponent.StartTime, 0, (float)waitComponent.WaitDuration); + m_ProgressBar.value = elapsed; + } else if (taskComponents[m_Node.RuntimeIndex].Status == Runtime.Tasks.TaskStatus.Success) { + elapsed = (float)waitComponent.WaitDuration; + m_ProgressBar.value = elapsed; + } else if (taskComponents[m_Node.RuntimeIndex].Status == Runtime.Tasks.TaskStatus.Inactive) { + m_ProgressBar.value = 0; + } + + m_ProgressBar.title = (elapsed >= 0 ? System.Math.Round(elapsed, 2).ToString() + "/" : string.Empty) + System.Math.Round(waitComponent.WaitDuration, 2).ToString() + "s"; + if (m_ProgressBar.style.display == DisplayStyle.None) { + m_ProgressBar.style.display = DisplayStyle.Flex; + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Editor/NodeViews/WaitNodeViewControl.cs.meta b/Packages/com.opsive.behaviordesigner/Editor/NodeViews/WaitNodeViewControl.cs.meta new file mode 100644 index 0000000..12da59d --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/NodeViews/WaitNodeViewControl.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c971440ad87a6904daefedbbbd9b5cd4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Opsive.BehaviorDesigner.Editor.dll b/Packages/com.opsive.behaviordesigner/Editor/Opsive.BehaviorDesigner.Editor.dll new file mode 100644 index 0000000..87e3cef Binary files /dev/null and b/Packages/com.opsive.behaviordesigner/Editor/Opsive.BehaviorDesigner.Editor.dll differ diff --git a/Packages/com.opsive.behaviordesigner/Editor/Opsive.BehaviorDesigner.Editor.dll.meta b/Packages/com.opsive.behaviordesigner/Editor/Opsive.BehaviorDesigner.Editor.dll.meta new file mode 100644 index 0000000..06a3e76 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Opsive.BehaviorDesigner.Editor.dll.meta @@ -0,0 +1,70 @@ +fileFormatVersion: 2 +guid: c42964479d4f62540867ad0acdb1ef66 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: + - GRAPH_DESIGNER + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Editor: 0 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude Win: 1 + Exclude Win64: 1 + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 1 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: AnyOS + - first: + Standalone: Linux64 + second: + enabled: 0 + settings: + CPU: AnyCPU + - first: + Standalone: OSXUniversal + second: + enabled: 0 + settings: + CPU: AnyCPU + - first: + Standalone: Win + second: + enabled: 0 + settings: + CPU: AnyCPU + - first: + Standalone: Win64 + second: + enabled: 0 + settings: + CPU: AnyCPU + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Styles.meta b/Packages/com.opsive.behaviordesigner/Editor/Styles.meta new file mode 100644 index 0000000..a6910be --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Styles.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ae6a7b3cd5a26064a8abc3132ea543a9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Editor/Styles/TaskStyles.uss b/Packages/com.opsive.behaviordesigner/Editor/Styles/TaskStyles.uss new file mode 100644 index 0000000..e0296cc --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Styles/TaskStyles.uss @@ -0,0 +1,29 @@ +TaskView +{ + overflow: hidden; +} + +#conditional-abort-icon +{ + top: 2px; + padding-left: 3px; + position: absolute; +} + +#event-execution-status +{ + bottom: 1px; + right: -1px; + align-self: flex-end; + position: absolute; + height: 20px; +} + +#execution-status +{ + top: 2px; + right: 2px; + align-self: flex-end; + position: absolute; + height: 24px; +} \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Editor/Styles/TaskStyles.uss.meta b/Packages/com.opsive.behaviordesigner/Editor/Styles/TaskStyles.uss.meta new file mode 100644 index 0000000..7ce3d8e --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Editor/Styles/TaskStyles.uss.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9c6834c10d404ac4b95be745f4411f96 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 diff --git a/Packages/com.opsive.behaviordesigner/Runtime.meta b/Packages/com.opsive.behaviordesigner/Runtime.meta new file mode 100644 index 0000000..fc2b9de --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5488ed20bc1de7f4187785e9bd70221d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/BehaviorTree.cs b/Packages/com.opsive.behaviordesigner/Runtime/BehaviorTree.cs new file mode 100644 index 0000000..ef937b8 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/BehaviorTree.cs @@ -0,0 +1,1983 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Opsive.BehaviorDesigner.Editor")] +namespace Opsive.BehaviorDesigner.Runtime +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.BehaviorDesigner.Runtime.Groups; + using Opsive.BehaviorDesigner.Runtime.Systems; + using Opsive.BehaviorDesigner.Runtime.Tasks; + using Opsive.BehaviorDesigner.Runtime.Tasks.Events; + using Opsive.BehaviorDesigner.Runtime.Utility; + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using Unity.Entities; + using UnityEngine; + using System; + using System.Collections; + using System.Collections.Generic; + using System.Reflection; + + /// + /// Container for managing behavior tree logic. + /// + public class BehaviorTree : MonoBehaviour, IGraph, IGraphComponent, ISharedVariableContainer + { + [Tooltip("The name of the behavior tree.")] + [SerializeField] [Delayed] private string m_GraphName = "Behavior Tree"; + [Tooltip("A user specified ID for the graph.")] + [SerializeField] [Delayed] private int m_Index; + [Tooltip("The graph data.")] + [SerializeField] private BehaviorTreeData m_Data = new BehaviorTreeData(); + [Tooltip("Should the behavior tree start when the component is enabled?")] + [SerializeField] private bool m_StartWhenEnabled = true; + [Tooltip("Should the behavior tree pause when the tree is disabled?")] + [SerializeField] private bool m_PauseWhenDisabled; + [Tooltip("Specifies when the behavior tree should be updated.")] + [SerializeField] private UpdateMode m_UpdateMode; + [Tooltip("Specifies how many tasks should be updated during a single tick.")] + [SerializeField] private EvaluationType m_EvaluationType; + [Tooltip("The maximum number of tasks that can run if the evaluation type is set to EvaluationType.Count.")] + [SerializeField] [Range(1, ushort.MaxValue)] private int m_MaxEvaluationCount = 1; + [Tooltip("A reference to the subtree.")] + [SerializeField] private Subtree m_Subtree; + + private GameObject m_GameObject; + private World m_World; + private Entity m_Entity; + private Dictionary m_NodeIndexByRuntimeIndex = new Dictionary(); + private static Dictionary s_BehaviorTreeByEntity = new Dictionary(); + private static EventNodeComparer s_EventNodeComparer = new EventNodeComparer(); + private bool m_SubtreeOverride; + + public string Name { get => m_GraphName; set => m_GraphName = value; } + public int Index { get => m_Index; set => m_Index = value; } + public int UniqueID { get => m_Data.UniqueID; } + public UnityEngine.Object Parent { get { + if (this == null) { return null; } + return Application.isPlaying && m_GameObject != null ? m_GameObject : gameObject; + } } + private BehaviorTreeData Data { get => !Application.isPlaying && m_Subtree != null ? m_Subtree.Data : m_Data; } + public bool StartWhenEnabled { get => m_StartWhenEnabled; set => m_StartWhenEnabled = value; } + public bool PauseWhenDisabled { get => m_PauseWhenDisabled; set => m_PauseWhenDisabled = value; } + public UpdateMode UpdateMode { get => m_UpdateMode; set => m_UpdateMode = value; } + public EvaluationType EvaluationType { get => m_EvaluationType; set => m_EvaluationType = value; } + public int MaxEvaluationCount { get => m_MaxEvaluationCount; set => m_MaxEvaluationCount = Mathf.Max(1, Mathf.Min(ushort.MaxValue, value)); } + public IGraph Subgraph + { + get => m_Subtree; + set + { + if (m_Subtree == (Subtree)value) { + return; + } + + var active = IsActive(); + ClearTree(); + m_Subtree = value as Subtree; + m_SubtreeOverride = false; + InheritSubtree(false); + if (active && !IsPaused()) { + StartBehavior(); + } +#if UNITY_EDITOR + // Generate a new ID so the graph reloads. + if (Application.isPlaying) { + m_Data.RuntimeUniqueID = Guid.NewGuid().GetHashCode(); + } +#endif + } + } + + public ILogicNode[] LogicNodes { get => Data.LogicNodes; set => Data.LogicNodes = value as ITreeLogicNode[]; } + public ITreeLogicNode[] TreeLogicNodes { get => Data.LogicNodes; set => Data.LogicNodes = value; } + public IEventNode[] EventNodes { get => Data.EventNodes; set => Data.EventNodes = value; } + public SharedVariable[] SharedVariables { get => m_Data.SharedVariables; set => m_Data.SharedVariables = value; } + public SharedVariableGroup[] SharedVariableGroups { +#if UNITY_EDITOR + get => m_Data.SharedVariableGroups; + set => m_Data.SharedVariableGroups = value; +#else + get => null; + set { } +#endif + } + public ushort[] DisabledLogicNodes { get => Data.DisabledLogicNodes; set => Data.DisabledLogicNodes = value; } + public ushort[] DisabledEventNodes { get => Data.DisabledEventNodes; set => Data.DisabledEventNodes = value; } + + public SharedVariable.SharingScope VariableScope { get => SharedVariable.SharingScope.Graph; } + public World World { get => m_World; set { m_World = value; } } + public Entity Entity { get => m_Entity; set { m_Entity = value; } } + public bool Baked { get; set; } + public static int BehaviorTreeCount { get => s_BehaviorTreeByEntity.Count; } + + public LogicNodeProperties[] LogicNodeProperties { +#if UNITY_EDITOR + get => Data.LogicNodeProperties; + set => Data.LogicNodeProperties = value; +#else + get => null; + set { } +#endif + } + public NodeProperties[] EventNodeProperties { +#if UNITY_EDITOR + get => Data.EventNodeProperties; + set => Data.EventNodeProperties = value; +#else + get => null; + set { } +#endif + } + public GroupProperties[] GroupProperties { +#if UNITY_EDITOR + get => Data.GroupProperties; + set => Data.GroupProperties = value; +#else + get => null; + set { } +#endif + } + public TaskStatus Status { get + { + if (!Application.isPlaying || m_World == null || m_Entity == null || m_Data == null || m_Data.LogicNodes == null || Data.EventNodes == null) { return TaskStatus.Inactive; } + + // Find the Start event node. + Start startEventNode = null; + for (int i = 0; i < m_Data.EventNodes.Length; ++i) { + if (m_Data.EventNodes[i].GetType() == typeof(Start)) { + startEventNode = m_Data.EventNodes[i] as Start; + } + } + if (startEventNode == null || startEventNode.ConnectedIndex >= m_Data.LogicNodes.Length) { return TaskStatus.Inactive; } + + // The runtime index will match with the correct Entity TaskComponent. + var runtimeIndex = m_Data.LogicNodes[startEventNode.ConnectedIndex].RuntimeIndex; + var taskComponents = m_World.EntityManager.GetBuffer(m_Entity); + if (runtimeIndex >= taskComponents.Length) { return TaskStatus.Inactive; } + + // Retun the status of the task that the Start node is connected to. This is the current tree status. + return taskComponents[runtimeIndex].Status; + } } + + // Flow callbacks. + public Action OnBehaviorTreeStarted; + public Action OnBehaviorTreeStopped; + public Action OnBehaviorTreeDestroyed; + + // Physics callbacks. + public Action OnBehaviorTreeCollisionEnter; + public Action OnBehaviorTreeCollisionExit; + public Action OnBehaviorTreeCollisionEnter2D; + public Action OnBehaviorTreeCollisionExit2D; + public Action OnBehaviorTreeTriggerEnter; + public Action OnBehaviorTreeTriggerExit; + public Action OnBehaviorTreeTriggerEnter2D; + public Action OnBehaviorTreeTriggerExit2D; + public Action OnBehaviorTreeControllerColliderHit; + + // Event callbacks. + public Action OnWillSave; + public Action OnDidSave; + public Action OnWillLoad; + public Action OnDidLoad; + + // Coroutine support. + private Dictionary> m_ActiveTaskCoroutines; + + /// + /// Serializes the behavior tree. + /// + public void Serialize() + { + Data.Serialize(); + if (m_Subtree != null) { + m_Data.SerializeSharedVariables(); + } + } + + /// + /// Deserialize the behavior tree. + /// + /// Should the behavior tree be force deserialized? + /// True if the tree was deserialized. + public bool Deserialize(bool force = false) + { + if (this == null) { + return false; + } + + // Force the deserialization if the tree hasn't been deserialized yet at runtime. + if (Application.isPlaying && m_GameObject == null) { + force = true; + m_GameObject = gameObject; + } + + var deserialized = false; + if (m_Subtree != null) { + deserialized = InheritSubtree(force); + } else if (m_Data != null) { + deserialized = m_Data.Deserialize(this, this, force, Application.isPlaying, Application.isPlaying); + } + + // Initialize tasks after deserialization. This is only needed at edit time as the tasks are initialized elsewhere at runtime. + if (!Application.isPlaying && deserialized && m_Data != null && m_Data.LogicNodes != null) { + for (int i = 0; i < m_Data.LogicNodes.Length; ++i) { + if (m_Data.LogicNodes[i] is Task task) { + task.Initialize(this, (ushort)i); + } + } + } + + return deserialized; + } + + /// + /// Inherits the subtree tasks and variables. + /// + /// Should the behavior tree be force deserialized? + /// True if the subtree was inherited. + private bool InheritSubtree(bool force) + { + if (m_Subtree == null) { + if (Application.isPlaying) { + m_Data.EventNodes = null; + m_Data.LogicNodes = null; + m_Data.SubtreeNodesReferences = null; + m_Data.DisabledLogicNodes = null; + m_Data.DisabledEventNodes = null; +#if UNITY_EDITOR + m_Data.EventNodeProperties = null; + m_Data.LogicNodeProperties = null; + m_Data.SharedVariableGroups = null; + m_Data.GroupProperties = null; +#endif + } + return false; + } + + // The local behavior tree variables should be used. + m_Data.DeserializeSharedVariables(this, force, false); + if (m_Subtree.DeserializeSharedVariables(force || (Application.isPlaying && !m_SubtreeOverride)) && Application.isPlaying && !m_SubtreeOverride && m_Data.SharedVariables != null) { + // Set the binding on the subtree before the tasks are loaded. This is necessary because a new SharedVariable instance may need to be created. + for (int i = 0; i < m_Data.SharedVariables.Length; ++i) { + m_Subtree.Data.OverrideVariableBinding(this, m_Data.SharedVariables[i]); + } + } + // Subtrees will not have access to GameObject or Scene variables. Copy the reference from the parent tree in order to allow the subtree to correctly load all of the SharedVariables. + if (Application.isPlaying && !m_SubtreeOverride && m_Data.VariableByNameMap != null) { + foreach (var variableMap in m_Data.VariableByNameMap) { + var sharedVariable = variableMap.Value; + if (sharedVariable.Scope == SharedVariable.SharingScope.GameObject || sharedVariable.Scope == SharedVariable.SharingScope.Scene) { + var variableAssignment = new BehaviorTreeData.VariableAssignment(sharedVariable.Name, sharedVariable.Scope); + if (m_Subtree.Data.VariableByNameMap.ContainsKey(variableAssignment)) { + continue; + } + m_Subtree.Data.VariableByNameMap.Add(variableAssignment, sharedVariable); + } + } + } + + if (!m_Subtree.Deserialize(force || (Application.isPlaying && !m_Subtree.Pooled && !m_SubtreeOverride), false, Application.isPlaying, false)) { + return false; + } + + // Copy the deserialized objects at runtime to ensure each object is unique. + if (Application.isPlaying && !m_SubtreeOverride) { + m_Data.OverrideData(this, m_Subtree.Data, m_Data.SharedVariables, m_Subtree.Pooled); + m_GameObject = gameObject; + m_SubtreeOverride = true; + } + + return true; + } + + /// + /// Adds the specified node. + /// + /// The node that should be added. + public void AddNode(ILogicNode node) + { + Data.AddNode(node as ITreeLogicNode); + } + + /// + /// Removes the specified node. + /// + /// The node that should be removed. + /// True if the node was removed. + public bool RemoveNode(ILogicNode node) + { + return Data.RemoveNode(node as ITreeLogicNode); + } + + /// + /// Adds the specified event node. + /// + /// The event node that should be added. + public void AddNode(IEventNode eventNode) + { + Data.AddNode(eventNode); + } + + /// + /// Removes the specified event node. + /// + /// The event node that should be removed. + /// True if the event node was removed. + public bool RemoveNode(IEventNode eventNode) + { + return Data.RemoveNode(eventNode); + } + + /// + /// Returns the Node of the specified type. + /// + /// The type of Node that should be retrieved. + /// The Node of the specified type (can be null). + public ILogicNode GetNode(Type type) + { + return Data.GetNode(type); + } + + /// + /// Returns the EventNode of the specified type. + /// + /// The type of EventNode that should be retrieved. + /// The EventNode of the specified type (can be null). If the node is found the index will also be returned. + public (IEventNode, ushort) GetEventNode(Type type) + { + return Data.GetEventNode(type); + } + + /// + /// The component has been enabled. + /// + private void OnEnable() + { + if (m_World != null && m_StartWhenEnabled) { + StartBehavior(); + } + } + + /// + /// The component has started. + /// + private void Start() + { + if (m_StartWhenEnabled) { + StartBehavior(); + } + } + + /// + /// Starts the behavior tree. + /// + /// True if the behavior tree was started. + public bool StartBehavior() + { + var world = m_World == null ? World.DefaultGameObjectInjectionWorld : m_World; + var entity = m_Entity == Entity.Null ? world.EntityManager.CreateEntity() : m_Entity; + return StartBehavior(world, entity); + } + + /// + /// Starts the behavior tree. + /// + /// The world that should contain the behavior tree. + /// The entity that should contain the behavior tree. + /// True if the behavior tree was started. + public bool StartBehavior(World world, Entity entity) + { + return StartBehavior(world, entity, typeof(Start)); + } + + /// + /// Starts the behavior tree. + /// + /// The world that contains the entity. + /// The entity that should contain the behavior tree. + /// The type of branch that should be started. + /// True if the behavior tree was started. + public bool StartBehavior(World world, Entity entity, Type startBranchType) + { + if (world == null) { + return false; + } + + if (s_BehaviorTreeByEntity.ContainsKey(entity)) { + // The behavior tree may be paused. + if (IsPaused(world, entity)) { + world.EntityManager.SetComponentEnabled(entity, true); + if (OnBehaviorTreeStarted != null) { + OnBehaviorTreeStarted(); + } + // Tasks can implement a pause specific interface. + var tasks = Data.LogicNodes; + for (int i = 0; i < tasks.Length; ++i) { + if (!(tasks[i] is IPausableTask pausableTask)) { + continue; + } + pausableTask.Resume(world, entity); + } + return true; + } + // The tree cannot be started multiple times. + return false; + } + s_BehaviorTreeByEntity.Add(entity, this); + + if (!InitializeTree(world, entity)) { + return false; + } + + if (OnBehaviorTreeStarted != null) { + OnBehaviorTreeStarted(); + } + return StartBranch(startBranchType); + } + + /// + /// Initializes the tree within DOTS for all of the event tasks. + /// + /// True if the behavior tree was initialized. + internal bool InitializeTree() + { + var world = m_World == null ? World.DefaultGameObjectInjectionWorld : m_World; + var entity = m_Entity == Entity.Null ? world.EntityManager.CreateEntity() : m_Entity; + return InitializeTree(world, entity); + } + + /// + /// Initializes the tree within DOTS for all of the event tasks. + /// + /// The world that contains the entity. + /// The entity that should contain the behavior tree. + /// True if the behavior tree was initialized. + internal bool InitializeTree(World world, Entity entity) + { + if (!Deserialize(false)) { + enabled = false; + return false; + } + + if (m_Data.EventNodes == null || world == null) { + return false; + } + + // The tree may be reinitialized with the same world/entity. + m_World = world; + m_Entity = entity; + + // The tree may have already been initialized. + if (world.EntityManager.HasComponent(entity)) { + return true; + } + + // Initialize the branch according to the connected index. This will ensure when the task is referencing other + // tasks the index will be correct. + var eventNodes = m_Data.EventNodes; + HashSet disabledNodes = null; + if (m_Data.DisabledEventNodes != null && m_Data.DisabledEventNodes.Length > 0) { + disabledNodes = new HashSet(); + for (int i = 0; i < m_Data.DisabledEventNodes.Length; ++i) { + disabledNodes.Add(eventNodes[m_Data.DisabledEventNodes[i]]); + } + } +#if UNITY_EDITOR + var eventNodeProperties = Data.EventNodeProperties; + Array.Sort(eventNodes, eventNodeProperties, s_EventNodeComparer); + Data.EventNodeProperties = eventNodeProperties; +#endif + Array.Sort(eventNodes, s_EventNodeComparer); + // The disabled event nodes array only stores the index. Update the index with the sorted value. + if (disabledNodes != null) { + var index = 0; + var disabledEventNodes = m_Data.DisabledEventNodes; + for (int i = 0; i < eventNodes.Length; ++i) { + if (disabledNodes.Contains(eventNodes[i])) { + disabledEventNodes[index] = (ushort)i; + index++; + } + } + m_Data.DisabledEventNodes = disabledEventNodes; + } + + for (int i = 0; i < eventNodes.Length; ++i) { + InitializeBranch(world, entity, eventNodes[i]); + } + return true; + } + + /// + /// Initialize the specified event branch within DOTS. + /// + /// The world that the entity exists in. + /// The entity that the branch should be added to. + /// The task that should be setup. + private void InitializeBranch(World world, Entity entity, IEventNode eventTask) + { + if (Data.LogicNodes == null) { + return; + } + + // There must be a starting event node. + if (eventTask == null || eventTask.ConnectedIndex >= Data.LogicNodes.Length) { + return; + } + + if (!world.EntityManager.HasBuffer(entity)) { + var taskComponentBuffer = world.EntityManager.AddBuffer(entity); + taskComponentBuffer.EnsureCapacity(Data.LogicNodes.Length); + } + + DynamicBuffer branchComponents; + if (world.EntityManager.HasBuffer(entity)) { + branchComponents = world.EntityManager.GetBuffer(entity); + } else { + branchComponents = world.EntityManager.AddBuffer(entity); + } + var startBranchIndex = (ushort)branchComponents.Length; + branchComponents.Add(new BranchComponent() { ActiveIndex = ushort.MaxValue, NextIndex = ushort.MaxValue, LastActiveIndex = ushort.MaxValue, CanExecute = true }); + + ComponentUtility.AddEvaluationComponent(world, entity, m_Data.LogicNodes.Length, m_EvaluationType, m_MaxEvaluationCount); + world.EntityManager.AddComponent(entity); + world.EntityManager.AddComponent(entity); + // A manual update mode will require the user to call the Tick method. + if (m_UpdateMode == UpdateMode.Manual) { + world.EntityManager.SetComponentEnabled(entity, false); + world.EntityManager.SetComponentEnabled(entity, false); + } + + // Get the required parent system groups. + var traversalTaskSystemGroup = world.GetOrCreateSystemManaged(); + var reevaluateTaskSystemGroup = world.GetOrCreateSystemManaged(); + var interruptTaskSystemGroup = world.GetOrCreateSystemManaged(); + + // Add the necessary cleanup systems. + var behaviorTreeSystemGroup = world.GetOrCreateSystemManaged(); + behaviorTreeSystemGroup.AddSystemToUpdateList(world.GetOrCreateSystem()); + behaviorTreeSystemGroup.AddSystemToUpdateList(world.GetOrCreateSystem()); + + var canReevaluate = false; + var taskComponents = world.EntityManager.GetBuffer(entity); + var taskOffset = (ushort)(eventTask.ConnectedIndex - taskComponents.Length); + for (int i = eventTask.ConnectedIndex; i < m_Data.LogicNodes.Length; ++i) { + // Don't initialize tasks that aren't connected to the event node. + if (i > eventTask.ConnectedIndex && m_Data.LogicNodes[i].ParentIndex == ushort.MaxValue) { + break; + } + + taskComponents = world.EntityManager.GetBuffer(entity); + + // Determine the branch index based off of the parent. If the parent is a parallel node then the node will be part of a new branch. + var branchIndex = startBranchIndex; + if (m_Data.LogicNodes[i].ParentIndex != ushort.MaxValue) { + branchComponents = world.EntityManager.GetBuffer(entity); + var parentIndex = m_Data.LogicNodes[i].ParentIndex; + if (m_Data.LogicNodes[parentIndex] is IParallelNode) { + branchIndex = (ushort)branchComponents.Length; + } else { + branchIndex = taskComponents[parentIndex - taskOffset].BranchIndex; + } + + // A new branch component may need to be added to keep track of the active task index for that branch. + if (branchIndex >= branchComponents.Length) { + branchComponents.Add(new BranchComponent() { ActiveIndex = ushort.MaxValue, NextIndex = ushort.MaxValue, LastActiveIndex = ushort.MaxValue, CanExecute = true }); + } + } + + // The TaskComponent index will be different from the LogicNode index if the tree has a gap of tasks that are not connected. + // The RuntimeIndex maps the LogicNode index to the TaskComponent index. + var node = m_Data.LogicNodes[i]; + node.RuntimeIndex = (ushort)(node.Index - taskOffset); + m_Data.LogicNodes[i] = node; + if (!m_NodeIndexByRuntimeIndex.ContainsKey(node.RuntimeIndex)) { // The index will already exist if multiple entities use the same MonoBehaviour. + m_NodeIndexByRuntimeIndex.Add(node.RuntimeIndex, node.Index); + } + + if (m_Data.LogicNodes[i] is IAuthoringTask authoringTask) { + authoringTask.AddBufferElement(world, entity, gameObject); + taskComponents = world.EntityManager.GetBuffer(entity); + taskComponents.Add(new TaskComponent { + Status = TaskStatus.Inactive, + Index = node.RuntimeIndex, + ParentIndex = AdjustByIndexOffset(m_Data.LogicNodes[i].ParentIndex, taskOffset), + SiblingIndex = AdjustByIndexOffset(m_Data.LogicNodes[i].SiblingIndex, taskOffset), + BranchIndex = branchIndex, + FlagComponentType = authoringTask.Flag, + Disabled = !IsNodeEnabled(true, m_Data.LogicNodes[i].ParentIndex) || !IsNodeEnabled(true, i), + }); + + world.EntityManager.AddComponent(entity, authoringTask.Flag); + world.EntityManager.SetComponentEnabled(entity, authoringTask.Flag, false); + traversalTaskSystemGroup.AddSystemToUpdateList(world.GetOrCreateSystem(authoringTask.SystemType)); + } else if (m_Data.LogicNodes[i] is Task taskObject) { + taskObject.AddBufferElement(world, entity, GetHashCode(), node.RuntimeIndex); + taskComponents = world.EntityManager.GetBuffer(entity); + taskComponents.Add(new TaskComponent { + Status = TaskStatus.Inactive, + Index = node.RuntimeIndex, + ParentIndex = AdjustByIndexOffset(m_Data.LogicNodes[i].ParentIndex, taskOffset), + SiblingIndex = AdjustByIndexOffset(m_Data.LogicNodes[i].SiblingIndex, taskOffset), + BranchIndex = branchIndex, + FlagComponentType = typeof(TaskObjectFlag), + Disabled = !IsNodeEnabled(true, m_Data.LogicNodes[i].ParentIndex) || !IsNodeEnabled(true, i), + }); + world.EntityManager.AddComponent(entity, typeof(TaskObjectFlag)); + world.EntityManager.SetComponentEnabled(entity, typeof(TaskObjectFlag), false); + traversalTaskSystemGroup.AddSystemToUpdateList(world.GetOrCreateSystem(typeof(TaskObjectSystem))); + + taskObject.Initialize(this, node.RuntimeIndex); + } else { + Debug.LogError("Error: Unknown Task Type.", this); + continue; + } + + // Conditional tasks can be reevaluated. + if (m_Data.LogicNodes[i] is IConditional && m_Data.LogicNodes[i].ParentIndex != ushort.MaxValue) { + var reevaluateFlag = new ComponentType(); + Type reevaluateSystem; + if (m_Data.LogicNodes[i] is IAuthoringTask conditionalAuthoringTask) { + if (m_Data.LogicNodes[i] is IReevaluateResponder reevaluateTask) { + reevaluateFlag = reevaluateTask.ReevaluateFlag; + reevaluateSystem = reevaluateTask.ReevaluateSystemType; + } else { + Debug.LogWarning($"Warning: The task {m_Data.LogicNodes[i]} doesn't have a separate reevaluation tag. This may lead to unexpected results. It is recommend " + + $"that the task implements the IReevaluate interface."); + reevaluateFlag = conditionalAuthoringTask.Flag; + reevaluateSystem = conditionalAuthoringTask.SystemType; + } + } else { + reevaluateFlag = typeof(TaskObjectReevaluateFlag); + reevaluateSystem = typeof(TaskObjectReevaluateSystem); + } + world.EntityManager.AddComponent(entity, reevaluateFlag); + world.EntityManager.SetComponentEnabled(entity, reevaluateFlag, false); + ComponentUtility.AddInterruptComponents(world.EntityManager, entity); + reevaluateTaskSystemGroup.AddSystemToUpdateList(world.GetOrCreateSystem(reevaluateSystem)); + + // Ignore any decorator tasks when determining the parent. Composite tasks can only be a conditional abort parent. + IComposite parentComposite = null; + ushort parentIndex; + var compositeParentIndex = m_Data.LogicNodes[i].ParentIndex; + do { + parentComposite = m_Data.LogicNodes[compositeParentIndex] as IComposite; + parentIndex = compositeParentIndex; + compositeParentIndex = m_Data.LogicNodes[compositeParentIndex].ParentIndex; + } while (compositeParentIndex != ushort.MaxValue && parentComposite == null); + + var abortParent = parentComposite as IConditionalAbortParent; + if (abortParent != null && abortParent.AbortType != ConditionalAbortType.None) { + canReevaluate = true; + var lowerPriorityLowerIndex = ushort.MaxValue; + var lowerPriorityUpperIndex = ushort.MaxValue; + // Lower Priority aborts are recursive allowing a nested conditional task to be reevaluated even if the direct + // parent's sibling isn't active. + if (abortParent.AbortType == ConditionalAbortType.LowerPriority || abortParent.AbortType == ConditionalAbortType.Both) { + var parentChildCount = m_Data.GetChildCount(m_Data.LogicNodes[parentIndex], m_Data.LogicNodes); + lowerPriorityLowerIndex = AdjustByIndexOffset((ushort)(parentIndex + parentChildCount), taskOffset); + var parentTranversalIndex = parentIndex; + IConditionalAbortParent parentAbortParent = null; + while (parentTranversalIndex != ushort.MaxValue && ((parentAbortParent = m_Data.LogicNodes[parentTranversalIndex] as IConditionalAbortParent) != null || m_Data.LogicNodes[parentTranversalIndex] is IDecorator)) { + if (parentAbortParent != null && parentAbortParent.AbortType != ConditionalAbortType.LowerPriority && parentAbortParent.AbortType != ConditionalAbortType.Both) { + break; + } + parentIndex = parentTranversalIndex; + parentTranversalIndex = m_Data.LogicNodes[parentTranversalIndex].ParentIndex; + } + + // The conditional abort can reevaluate up to the rightmost task of the parent. + parentTranversalIndex = parentTranversalIndex != ushort.MaxValue ? parentTranversalIndex : parentIndex; + parentChildCount = m_Data.GetChildCount(m_Data.LogicNodes[parentTranversalIndex], m_Data.LogicNodes); + lowerPriorityUpperIndex = AdjustByIndexOffset((ushort)(parentTranversalIndex + parentChildCount), taskOffset); + } + var selfPriorityUpperIndex = ushort.MaxValue; + if (abortParent.AbortType == ConditionalAbortType.Self || abortParent.AbortType == ConditionalAbortType.Both) { + if (m_Data.LogicNodes[parentIndex].SiblingIndex == ushort.MaxValue) { + selfPriorityUpperIndex = (ushort)(parentIndex + m_Data.GetChildCount(m_Data.LogicNodes[parentIndex], m_Data.LogicNodes)); + } else { + selfPriorityUpperIndex = (ushort)(m_Data.LogicNodes[parentIndex].SiblingIndex - 1); + } + } + + var reevaluateTaskComponents = world.EntityManager.AddBuffer(entity); + var reevaluateTaskComponent = new ReevaluateTaskComponent() + { + Index = node.RuntimeIndex, + AbortType = abortParent.AbortType, + ReevaluateFlagComponentType = reevaluateFlag, + LowerPriorityLowerIndex = lowerPriorityLowerIndex, + LowerPriorityUpperIndex = lowerPriorityUpperIndex, + SelfPriorityUpperIndex = selfPriorityUpperIndex, + }; + + reevaluateTaskComponents.Add(reevaluateTaskComponent); + } + } + + // Add any systems that respond to interrupts. + if (m_Data.LogicNodes[i] is IInterruptResponder interruptResponder) { + interruptTaskSystemGroup.AddSystemToUpdateList(world.GetOrCreateSystem(interruptResponder.InterruptSystemType)); + } + } + + if (canReevaluate) { + reevaluateTaskSystemGroup.AddSystemToUpdateList(world.GetOrCreateSystem(typeof(ReevaluateSystem))); + } + + // The event task may perform its own logic. + if (eventTask is IEventNodeEntityReceiver entityReceiver) { + entityReceiver.AddBufferElement(world, entity, gameObject, taskOffset); + } + if (eventTask is IEventNodeGameObjectReceiver gameObjectReceiver) { + gameObjectReceiver.Initialize(this); + } + + traversalTaskSystemGroup.SortSystems(); + } + + /// + /// Adjusts the index by the specified offset. + /// + /// The index that should be adjusted. + /// The offset that should be adjusted by. + /// THe index by the specified offset. + private ushort AdjustByIndexOffset(ushort index, ushort offset) + { + if (index == ushort.MaxValue) { return index; } + return (ushort)(index - offset); + } + + /// + /// Stars the branch with the specified event task type. + /// + /// The branch that should be started. + /// True if the branch was started. + public bool StartBranch(Type eventTaskType) + { + if (m_World == null || m_Entity == Entity.Null) { + return false; + } + + return StartBranch(m_World, m_Entity, eventTaskType); + } + + /// + /// Stars the branch with the specified event task type. + /// + /// The world that the entity exists in. + /// The entity that contains the branch. + /// The branch that should be started. + /// True if the branch was started. + public bool StartBranch(World world, Entity entity, Type eventTaskType) + { + if (!s_BehaviorTreeByEntity.ContainsKey(entity)) { + return StartBehavior(world, entity, eventTaskType); + } + + if (m_Data.EventNodes == null || entity.Index == 0 || !Application.isPlaying) { + return false; + } + + for (int i = 0; i < m_Data.EventNodes.Length; ++i) { + if (m_Data.EventNodes[i].GetType() == eventTaskType) { + // The branch cannot start if it is disabled. + if (!IsNodeEnabled(false, i)) { + Debug.LogError($"Error: Unable to start the {eventTaskType.Name} branch because the node is disabled.", this); + return false; + } + + return StartBranch(world, entity, m_Data.EventNodes[i]); + } + } + + Debug.LogError($"Error: Unable to start the {eventTaskType.Name} branch because it can't be found.", this); + return false; + } + + /// + /// Starts the branch with the specified event task. + /// + /// The branch that should be started. + /// True if the branch was started. + public bool StartBranch(IEventNode eventTask) + { + if (m_World == null || m_Entity == Entity.Null) { + return false; + } + + return StartBranch(m_World, m_Entity, eventTask); + } + + /// + /// Starts the branch with the specified event task. + /// + /// The world that the entity exists in. + /// The entity that contains the branch. + /// The branch that should be started. + /// True if the branch was started. + public bool StartBranch(World world, Entity entity, IEventNode eventTask) + { + if (!Application.isPlaying || entity == Entity.Null) { + return false; + } + + // The branch can't be started if it's not connected to any tasks. + if (eventTask.ConnectedIndex == ushort.MaxValue) { + Debug.LogError($"Error: Unable to start the {eventTask.GetType().Name} branch because it doesn't have a connecting task.", this); + return false; + } + + // The tree needs to be setup before the branch can start. + if (!world.EntityManager.HasBuffer(entity)) { + InitializeTree(); + } + + var connectedIndex = m_Data.LogicNodes[eventTask.ConnectedIndex].RuntimeIndex; + return StartBranch(world, entity, connectedIndex, m_UpdateMode == UpdateMode.EveryFrame); + } + + /// + /// Starts the branch. This method is static allowing for alread-baked entities to be able to start the branch. + /// + /// The world that the entity exists in. + /// The entity that contains the branch. + /// The index of the starting task. + /// Should the branch start evaluation? If false the tree will manually need to be ticked. + /// True if the branch was started. + internal static bool StartBranch(World world, Entity entity, ushort connectedIndex, bool startEvaluation) + { + var taskComponents = world.EntityManager.GetBuffer(entity); + if (connectedIndex >= taskComponents.Length) { + Debug.LogError($"Error: Unable to start the branch on entity {entity} because the start index is greater than the task count."); + return false; + } + + var startTask = taskComponents[connectedIndex]; + // The branch can't be started twice or if it is disabled. + if (startTask.Status == TaskStatus.Queued || startTask.Status == TaskStatus.Running || startTask.Disabled) { + return false; + } + + var systemGroup = world.GetExistingSystemManaged(); + if (systemGroup == null) { + systemGroup = World.DefaultGameObjectInjectionWorld.GetExistingSystemManaged(); + if (systemGroup == null) { + return false; + } + } + systemGroup.Enabled = true; + + // The branch can start. + startTask.Status = TaskStatus.Queued; + taskComponents[connectedIndex] = startTask; + + var activeFlag = taskComponents[connectedIndex].FlagComponentType; + world.EntityManager.SetComponentEnabled(entity, activeFlag, true); + + var branchComponents = world.EntityManager.GetBuffer(entity); + var branchIndex = taskComponents[connectedIndex].BranchIndex; + var branchComponent = branchComponents[branchIndex]; + branchComponent.ActiveIndex = branchComponent.NextIndex = connectedIndex; + branchComponent.LastActiveIndex = ushort.MaxValue; + branchComponent.ActiveFlagComponentType = activeFlag; + branchComponents[branchIndex] = branchComponent; + + ComponentUtility.ResetEvaluationComponent(world, entity); + + if (startEvaluation) { + world.EntityManager.SetComponentEnabled(entity, true); + world.EntityManager.SetComponentEnabled(entity, true); + } + return true; + } + + /// + /// Returns the behavior tree component specified by the entity. + /// + /// The entity that should be retrieved. + /// The behavior tree component specified by the ID. + public static BehaviorTree GetBehaviorTree(Entity entity) + { + if (s_BehaviorTreeByEntity.TryGetValue(entity, out var behaviorTree)) { + return behaviorTree; + } + return null; + } + + /// + /// Returns the task at the specified index. + /// + /// The index of the task. + /// The task at the specified index. + public ITreeLogicNode GetTask(int index) + { + Deserialize(); + + if (m_Data.LogicNodes == null || index < 0 || index >= m_Data.LogicNodes.Length) { + return null; + } + if (Application.isPlaying && m_NodeIndexByRuntimeIndex.Count > 0) { + return m_Data.LogicNodes[m_NodeIndexByRuntimeIndex[index]]; + } + return m_Data.LogicNodes[index]; + } + + /// + /// Finds the task with the specified type. + /// + /// The first task found with the specified type (can be null). + public T FindTask() where T : Task + { + Deserialize(); + + if (m_Data.LogicNodes == null || m_Data.LogicNodes.Length == 0) { + return null; + } + + for (int i = 0; i < m_Data.LogicNodes.Length; ++i) { + if (m_Data.LogicNodes[i] is T task) { + return task; + } + if (m_Data.LogicNodes[i] is IContainerNode containerNode) { + if (containerNode.Nodes == null) { + continue; + } + for (int j = 0; j < containerNode.Nodes.Length; ++j) { + if (containerNode.Nodes[j] is T stackedTask) { + return stackedTask; + } + } + } + + } + + return null; + } + + /// + /// Finds the tasks with the specified type. This method does not have any allocations. + /// + /// A pre-initialized array that will contain the found tasks. + /// The number of tasks found with the specified type. + public int FindTasks(T[] foundTasks) where T : Task + { + if (foundTasks == null || foundTasks.Length == 0) { + return 0; + } + + Deserialize(); + if (m_Data.LogicNodes == null || m_Data.LogicNodes.Length == 0) { + return 0; + } + + var count = 0; + for (int i = 0; i < m_Data.LogicNodes.Length; ++i) { + if (m_Data.LogicNodes[i] is T task) { + foundTasks[count] = task; + count++; + if (count == foundTasks.Length) { + return count; + } + } + if (m_Data.LogicNodes[i] is IContainerNode containerNode) { + if (containerNode.Nodes == null) { + continue; + } + for (int j = 0; j < containerNode.Nodes.Length; ++j) { + if (containerNode.Nodes[j] is T stackedTask) { + foundTasks[count] = stackedTask; + count++; + if (count == foundTasks.Length) { + return count; + } + } + } + } + + } + + return count; + } + + /// + /// Finds the tasks with the specified type. + /// + /// An array containing the found tasks. + public T[] FindTasks() where T : Task + { + Deserialize(); + + if (m_Data.LogicNodes == null || m_Data.LogicNodes.Length == 0) { + return null; + } + + // Assume the maximum number of tasks will be found. The array will be resized before returning. + var foundTasks = new T[m_Data.LogicNodes.Length]; + var count = FindTasks(foundTasks); + if (foundTasks.Length != count) { + Array.Resize(ref foundTasks, count); + } + return foundTasks; + } + + /// + /// Ticks the behavior tree. The UpdateMode must be set to Manual. + /// The behavior tree will not be executed instantaneously. It will instead be ticked the next time the DOTS system group is updated. + /// + public void Tick() + { + if (m_UpdateMode != UpdateMode.Manual) { + Debug.LogWarning("Warning: The behavior tree UpdateMode must be set to Manual in order to be ticked manually.", this); + return; + } + + if (m_World == null || m_Entity == Entity.Null) { + Debug.LogWarning("Warning: The behavior tree must be started in order for it to be ticked manually.", this); + return; + } + + Tick(m_World, m_Entity); + } + + /// + /// Ticks the behavior tree. + /// The behavior tree will not be executed instantaneously. It will instead be ticked the next time the DOTS system group is updated. + /// + /// The world that the entity exists in. + /// The entity that contains the behavior tree. + public static void Tick(World world, Entity entity) + { + if (world == null || entity.Index == 0) { + return; + } + world.EntityManager.SetComponentEnabled(entity, true); + } + + /// + /// Reevaluates the SubtreeReferences by calling the EvaluateSubtrees method. + /// + public void ReevaluateSubtreeReferences() + { + if (!m_Data.ReevaluateSubtreeReferences(this, this, ClearTree)) { + return; + } + + // Restart the tree. + InitializeTree(); + if (enabled && m_GameObject.activeSelf) { + StartBehavior(); + } + } + + /// + /// Stops or pauses the behavior tree. + /// + /// Should the behavior tree be paused? + /// True if the behavior tree was stopped or paused. + public bool StopBehavior(bool pause = false) + { + return StopBehavior(m_World, m_Entity, pause); + } + + /// + /// Stops or pauses the behavior tree. + /// + /// The world that the entity exists in. + /// The entity that contains the behavior tree. + /// Should the behavior tree be paused? + /// True if the behavior tree was stopped or paused. + public bool StopBehavior(World world, Entity entity, bool pause = false) + { + if (world == null || !world.IsCreated || entity == Entity.Null) { + return false; + } + + // The tree could be stopped after it has been paused. + if (world.EntityManager.HasComponent(entity)) { + world.EntityManager.SetComponentEnabled(entity, false); + } + if (world.EntityManager.HasComponent(entity)) { + world.EntityManager.SetComponentEnabled(entity, false); + } + + if (!s_BehaviorTreeByEntity.ContainsKey(entity)) { + return false; + } + + // Notify those interested that the behavior tree has been stopped. + if (OnBehaviorTreeStopped != null) { + OnBehaviorTreeStopped(pause); + } + + // Tasks can implement a pause and end specific callback. + var tasks = Data.LogicNodes; + for (int i = 0; i < tasks.Length; ++i) { + if (pause) { + if (!(tasks[i] is IPausableTask pausableTask)) { + continue; + } + pausableTask.Pause(world, entity); + } else if (tasks[i] is Task task) { + task.OnEnd(); + } + } + + // Removing the EnabledFlag and EvaluationComponent is sufficient to pause the tree. + if (pause) { + return true; + } + + s_BehaviorTreeByEntity.Remove(entity); + + StopBehavior(world, entity); + + return true; + } + + /// + /// Stops the behavior tree. This method should only be called from an ECS system. + /// + /// The world that the entity exists in. + /// The entity that contains the behavior tree. + public static void StopBehavior(World world, Entity entity) + { + if (world == null || entity.Index == 0) { + return; + } + + var branchComponents = world.EntityManager.GetBuffer(entity); + var taskComponents = world.EntityManager.GetBuffer(entity); + for (int i = 0; i < branchComponents.Length; ++i) { + var branchComponent = branchComponents[i]; + if (branchComponent.ActiveIndex == ushort.MaxValue) { + continue; + } + + // Stop all of the active tasks within the branch. + var taskIndex = branchComponent.ActiveIndex; + while (taskIndex != ushort.MaxValue) { + var taskComponent = taskComponents[taskIndex]; + taskComponent.Status = TaskStatus.Inactive; + taskComponent.Reevaluate = false; + taskComponents[taskIndex] = taskComponent; + + taskIndex = taskComponent.ParentIndex; + } + + world.EntityManager.SetComponentEnabled(entity, branchComponent.ActiveFlagComponentType, false); + branchComponent.ActiveIndex = branchComponent.NextIndex = branchComponent.LastActiveIndex = ushort.MaxValue; + branchComponent.ActiveFlagComponentType = new ComponentType(); + branchComponent.InterruptType = InterruptType.None; + branchComponent.InterruptIndex = 0; + branchComponents[i] = branchComponent; + } + + // Stop all reevaluations. + if (world.EntityManager.HasBuffer(entity)) { + var reevaluateTaskComponents = world.EntityManager.GetBuffer(entity); + for (int i = 0; i < reevaluateTaskComponents.Length; ++i) { + if (reevaluateTaskComponents[i].ReevaluateStatus == ReevaluateStatus.Inactive) { + continue; + } + + var reevaluateTaskComponent = reevaluateTaskComponents[i]; + world.EntityManager.SetComponentEnabled(entity, reevaluateTaskComponent.ReevaluateFlagComponentType, false); + reevaluateTaskComponent.ReevaluateStatus = ReevaluateStatus.Inactive; + reevaluateTaskComponent.OriginalStatus = TaskStatus.Inactive; + + reevaluateTaskComponents[i] = reevaluateTaskComponent; + } + } + } + + /// + /// Restarts the behavior tree. + /// + /// True if the behavior tree was restarted. + public bool RestartBehavior() + { + if (!IsActive()) { + return false; + } + if (!StopBehavior()) { + return false; + } + return StartBehavior(); + } + + /// + /// Clears all of the tree components. + /// + private void ClearTree() + { + ClearTree(m_World, m_Entity); + } + + /// + /// Clears all of the tree components. + /// + /// The world that the entity exists in. + /// The entity that contains the behavior tree. + private void ClearTree(World world, Entity entity) + { + if (world == null || entity == Entity.Null || Data.LogicNodes == null) { + return; + } + + StopBehavior(world, entity, false); + + world.EntityManager.RemoveComponent(entity); + world.EntityManager.RemoveComponent(entity); + ComponentUtility.RemoveEvaluationComponent(world, entity); + + var branchComponents = world.EntityManager.GetBuffer(entity); + var taskComponents = world.EntityManager.GetBuffer(entity); + branchComponents.Clear(); + taskComponents.Clear(); + if (world.EntityManager.HasBuffer(entity)) { + var reevaluateTaskComponents = world.EntityManager.GetBuffer(entity); + reevaluateTaskComponents.Clear(); + } + + for (int i = 0; i < m_Data.LogicNodes.Length; ++i) { + if (m_Data.LogicNodes[i] is IAuthoringTask authoringTask) { + authoringTask.ClearBufferElement(world, entity); + if (world.EntityManager.HasComponent(entity, authoringTask.Flag)) { + world.EntityManager.RemoveComponent(entity, authoringTask.Flag); + } + if (m_Data.LogicNodes[i] is IReevaluateResponder reevaluateTask) { + if (world.EntityManager.HasComponent(entity, reevaluateTask.ReevaluateFlag)) { + world.EntityManager.RemoveComponent(entity, reevaluateTask.ReevaluateFlag); + } + } + } else if (m_Data.LogicNodes[i] is Task task) { + task.ClearBufferElement(world, entity); + if (m_Data.LogicNodes[i] is IConditional) { + if (world.EntityManager.HasComponent(entity, typeof(TaskObjectReevaluateFlag))) { + world.EntityManager.RemoveComponent(entity, typeof(TaskObjectReevaluateFlag)); + } + if (world.EntityManager.HasComponent(entity, typeof(InterruptFlag))) { + world.EntityManager.RemoveComponent(entity, typeof(InterruptFlag)); + } + } + if (world.EntityManager.HasComponent(entity, typeof(TaskObjectFlag))) { + world.EntityManager.RemoveComponent(entity, typeof(TaskObjectFlag)); + } + } + } + + for (int i = 0; i < m_Data.EventNodes.Length; ++i) { + if (m_Data.EventNodes[i] is IEventNodeEntityReceiver entityReceiver) { + entityReceiver.ClearBufferElement(world, entity); + } + } + + m_NodeIndexByRuntimeIndex.Clear(); + } + + /// + /// Returns the SharedVariable with the specified name. + /// + /// The name of the SharedVariable that should be retrieved. + /// The SharedVariable with the specified name (can be null). + public SharedVariable GetVariable(PropertyName name) + { + return GetVariable(name, SharedVariable.SharingScope.Graph); + } + + /// + /// Returns the SharedVariable with the specified name and scope. + /// + /// The name of the SharedVariable that should be retrieved. + /// The scope of the SharedVariable that should be retrieved. + /// The SharedVariable with the specified name (can be null). + public SharedVariable GetVariable(PropertyName name, SharedVariable.SharingScope scope) + { + Deserialize(); + + return m_Data.GetVariable(this, name, scope); + } + + /// + /// Returns the SharedVariable of the specified name. + /// + /// The name of the SharedVariable that should be retrieved. + /// The SharedVariable with the specified name (can be null). + public SharedVariable GetVariable(PropertyName name) + { + return GetVariable(name, SharedVariable.SharingScope.Graph); + } + + /// + /// Returns the SharedVariable of the specified name. + /// + /// The name of the SharedVariable that should be retrieved. + /// The scope of the SharedVariable that should be retrieved. + /// The SharedVariable with the specified name (can be null). + public SharedVariable GetVariable(PropertyName name, SharedVariable.SharingScope scope) + { + Deserialize(); + + return m_Data.GetVariable(this, name, scope); + } + + /// + /// Sets the value of the SharedVariable. + /// + /// The type of SharedVarible. + /// The name of the SharedVariable. + /// The value of the SharedVariable. + /// True if the value was set. + public bool SetVariableValue(PropertyName name, T value) + { + return SetVariableValue(name, value, SharedVariable.SharingScope.Graph); + } + + /// + /// Sets the value of the SharedVariable. + /// + /// The type of SharedVarible. + /// The name of the SharedVariable. + /// The value of the SharedVariable. + /// The scope of the SharedVariable that should be set. + /// True if the value was set. + public bool SetVariableValue(PropertyName name, T value, SharedVariable.SharingScope scope) + { + Deserialize(); + + return m_Data.SetVariableValue(this, name, value, scope); + } + + /// + /// Gets the behavior tree save data. + /// + /// Specifies which variables should be saved. Graph variables will automatically be saved. + /// The save data if the behavior tree can be saved. + public SaveManager.SaveData? Save(SaveManager.VariableSaveScope variableSaveScope = 0) + { + if (OnWillSave != null) { + OnWillSave(this); + } + var saveData = SaveManager.Save(new BehaviorTree[] { this }, variableSaveScope); + if (OnDidSave != null) { + OnDidSave(this, saveData.HasValue); + } + return saveData; + } + + /// + /// Saves the behavior tree at the specified file path. + /// + /// The file path to save the behavior tree at. The file will be replaced if it already exists. + /// Specifies which variables should be saved. Graph variables will automatically be saved. + /// True if the behavior tree was successfully saved. + public bool Save(string filePath, SaveManager.VariableSaveScope variableSaveScope = 0) + { + if (OnWillSave != null) { + OnWillSave(this); + } + var success = SaveManager.Save(new BehaviorTree[] { this }, filePath, variableSaveScope); + if (OnDidSave != null) { + OnDidSave(this, success); + } + return success; + } + + /// + /// Loads the behavior tree from the specified file path. + /// + /// The file path to load the behavior tree at. + /// Optional callback after the graph variables have been restored. + /// True if the behavior tree was successfully loaded. + public bool Load(string filePath, Action afterVariablesRestored = null) + { + if (OnWillLoad != null) { + OnWillLoad(this); + } + var success = SaveManager.Load(new BehaviorTree[] { this }, filePath, afterVariablesRestored); + if (OnDidLoad != null) { + OnDidLoad(this, success); + } + return success; + } + + /// + /// Loads the behavior tree from the specified save data. + /// + /// The data associated with the behavior tree. + /// Optional callback after the graph variables have been restored. + /// True if the behavior tree was successfully loaded. + public bool Load(SaveManager.SaveData saveData, Action afterVariablesRestored = null) + { + if (OnWillLoad != null) { + OnWillLoad(this); + } + var success = SaveManager.Load(new BehaviorTree[] { this }, saveData, afterVariablesRestored); + if (OnDidLoad != null) { + OnDidLoad(this, success); + } + return success; + } + + /// + /// Starts the task courtine with the specified name. + /// + /// The task that the coroutine belongs to. + /// The name of the coroutine method. + /// The created routine (can be null). + public Coroutine StartTaskCoroutine(Task task, string coroutineName) + { + var method = task.GetType().GetMethod(coroutineName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + if (method == null) { + Debug.LogError($"Error: The coroutine {coroutineName} cannot be started due to the method not being found on {task.GetType()}."); + return null; + } + + if (m_ActiveTaskCoroutines == null) { + m_ActiveTaskCoroutines = new Dictionary>(); + } + var taskCoroutine = new TaskCoroutine(this, (IEnumerator)method.Invoke(task, new object[] { }), coroutineName); + if (!m_ActiveTaskCoroutines.TryGetValue(coroutineName, out var taskCoroutines)) { + taskCoroutines = new List(); + m_ActiveTaskCoroutines.Add(coroutineName, taskCoroutines); + } + taskCoroutines.Add(taskCoroutine); + + return taskCoroutine.Coroutine; + } + + /// + /// Starts the task courtine with the specified name. + /// + /// The task that the coroutine belongs to. + /// The name of the coroutine method. + /// The input parameter to the coroutine. + /// The created routine (can be null). + public Coroutine StartTaskCoroutine(Task task, string coroutineName, object value) + { + var method = task.GetType().GetMethod(coroutineName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + if (method == null) { + Debug.LogError($"Error: The coroutine {coroutineName} cannot be started due to the method not being found on {task.GetType()}."); + return null; + } + + if (m_ActiveTaskCoroutines == null) { + m_ActiveTaskCoroutines = new Dictionary>(); + } + var taskCoroutine = new TaskCoroutine(this, (IEnumerator)method.Invoke(task, new object[] { value }), coroutineName); + if (!m_ActiveTaskCoroutines.TryGetValue(coroutineName, out var taskCoroutines)) { + taskCoroutines = new List(); + m_ActiveTaskCoroutines.Add(coroutineName, taskCoroutines); + } + taskCoroutines.Add(taskCoroutine); + + return taskCoroutine.Coroutine; + } + + /// + /// Stops the task courtine with the specified name. + /// + /// The name of the coroutine method. + public void StopTaskCoroutine(string coroutineName) + { + if (!m_ActiveTaskCoroutines.TryGetValue(coroutineName, out var taskCoroutines)) { + return; + } + + for (int i = 0; i < taskCoroutines.Count; ++i) { + taskCoroutines[i].Stop(); + } + } + + /// + /// Stops all of the task coroutines. + /// + public void StopAllTaskCoroutines() + { + if (m_ActiveTaskCoroutines == null) { + return; + } + + foreach (var entry in m_ActiveTaskCoroutines) { + var taskCoroutines = entry.Value; + for (int i = 0; i < taskCoroutines.Count; ++i) { + taskCoroutines[i].Stop(); + } + } + } + + /// + /// The TaskCoroutine has ended. + /// + /// The coroutine that has ended. + /// The name of the coroutine. + public void TaskCoroutineEnded(TaskCoroutine taskCoroutine, string coroutineName) + { + if (!m_ActiveTaskCoroutines.TryGetValue(coroutineName, out var taskCoroutines)) { + return; + } + + taskCoroutines.Remove(taskCoroutine); + if (taskCoroutines.Count == 0) { + m_ActiveTaskCoroutines.Remove(coroutineName); + } + } + + /// + /// OnCollisionEnter callback. + /// + /// The resulting collision. + private void OnCollisionEnter(Collision collision) + { + if (OnBehaviorTreeCollisionEnter != null) { + OnBehaviorTreeCollisionEnter(collision); + } + } + + /// + /// OnCollisionExit callback. + /// + /// The resulting collision. + private void OnCollisionExit(Collision collision) + { + if (OnBehaviorTreeCollisionExit != null) { + OnBehaviorTreeCollisionExit(collision); + } + } + + /// + /// OnCollisionEnter2D callback. + /// + /// The resulting collision. + private void OnCollisionEnter2D(Collision2D collision) + { + if (OnBehaviorTreeCollisionEnter2D != null) { + OnBehaviorTreeCollisionEnter2D(collision); + } + } + + /// + /// OnCollisionExit2D callback. + /// + /// The resulting collision. + private void OnCollisionExit2D(Collision2D collision) + { + if (OnBehaviorTreeCollisionExit2D != null) { + OnBehaviorTreeCollisionExit2D(collision); + } + } + + /// + /// OnTriggerEnter callback. + /// + /// The overlapping collider. + private void OnTriggerEnter(Collider other) + { + if (OnBehaviorTreeTriggerEnter != null) { + OnBehaviorTreeTriggerEnter(other); + } + } + + /// + /// OnTriggerExit callback. + /// + /// The collider that is no longer overlapping. + private void OnTriggerExit(Collider other) + { + if (OnBehaviorTreeTriggerExit != null) { + OnBehaviorTreeTriggerExit(other); + } + } + + /// + /// OnTriggerEnter2D callback. + /// + /// The overlapping collider. + private void OnTriggerEnter2D(Collider2D other) + { + if (OnBehaviorTreeTriggerEnter2D != null) { + OnBehaviorTreeTriggerEnter2D(other); + } + } + + /// + /// OnTriggerExit2D callback. + /// + /// The collider that is no longer overlapping. + private void OnTriggerExit2D(Collider2D other) + { + if (OnBehaviorTreeTriggerExit2D != null) { + OnBehaviorTreeTriggerExit2D(other); + } + } + + /// + /// OnControllerColliderHit callback. + /// + /// The hit result. + private void OnControllerColliderHit(ControllerColliderHit hit) + { + if (OnBehaviorTreeControllerColliderHit != null) { + OnBehaviorTreeControllerColliderHit(hit); + } + } + +#if UNITY_EDITOR + /// + /// OnDrawGizmos callback. + /// + private void OnDrawGizmos() + { + if (!enabled) { + return; + } + + if (m_Data != null && m_Data.LogicNodes != null) { + for (int i = 0; i < m_Data.LogicNodes.Length; ++i) { + if (m_Data.LogicNodes[i] is Task task) { + task.OnDrawGizmos(this); + } + } + } + } + + /// + /// OnDrawGizmos callback. + /// + private void OnDrawGizmosSelected() + { + if (!enabled) { + return; + } + + if (m_Data != null && m_Data.LogicNodes != null) { + for (int i = 0; i < m_Data.LogicNodes.Length; ++i) { + if (m_Data.LogicNodes[i] is Task task) { + task.OnDrawGizmosSelected(this); + } + } + } + } +#endif + + /// + /// The behavior tree has been disabled. + /// + private void OnDisable() + { + if (m_Entity == Entity.Null) { + return; + } + + StopBehavior(m_World, m_Entity, m_PauseWhenDisabled); + } + + /// + /// The behavior tree has been destroyed. + /// + private void OnDestroy() + { + if (m_Entity == Entity.Null) { + return; + } + + if (OnBehaviorTreeDestroyed != null) { + OnBehaviorTreeDestroyed(); + } + StopBehavior(m_World, m_Entity, false); + m_GameObject = null; + } + + /// + /// Is the node with the specified index enabled? + /// + /// Is the node a LogicNode? + /// The index of the node. + /// True if the node with the specified index is enabled. + public bool IsNodeEnabled(bool logicNode, int index) + { + return Data.IsNodeEnabled(logicNode, index); + } + + /// + /// Is the node with the specified index active? + /// + /// Is the node a LogicNode? + /// The index of the node. + /// True if the node with the specified index is active. + public bool IsNodeActive(bool logicNode, int index) + { + if (!Application.isPlaying || m_Entity == Entity.Null) { + return false; + } + + var taskComponents = m_World.EntityManager.GetBuffer(m_Entity); + var logicNodeIndex = index; + if (!logicNode && m_Data.EventNodes != null && index < m_Data.EventNodes.Length) { + // Find the logic node that the event node is connected to. + logicNodeIndex = m_Data.EventNodes[index].ConnectedIndex; + } + if (logicNodeIndex >= taskComponents.Length) { + return false; + } + var taskComponent = taskComponents[logicNodeIndex]; + return taskComponent.Status == TaskStatus.Running; + } + + /// + /// Returns true if the behavior tree is active. + /// + /// True if the behavior tree is active. + public bool IsActive() + { + return IsActive(m_Entity); + } + + /// + /// Returns true if the behavior tree is active. + /// + /// The entity that contains the behavior tree. + /// True if the behavior tree is active. + public bool IsActive(Entity entity) + { + if (entity == Entity.Null) { + return false; + } + return s_BehaviorTreeByEntity.ContainsKey(entity); + } + + /// + /// Returns true if the behavior tree is paused. + /// + /// True if the behavior tree is paused. + public bool IsPaused() + { + return IsPaused(m_World, m_Entity); + } + + /// + /// Returns true if the behavior tree is paused. + /// + /// The world that the entity exists in. + /// The entity that contains the behavior tree. + /// True if the behavior tree is paused. + public bool IsPaused(World world, Entity entity) + { + if (!IsActive(entity)) { + return false; + } + return world.EntityManager.HasComponent(entity) && !world.EntityManager.IsComponentEnabled(entity); + } + + /// + /// Copies the graph onto the current graph. + /// + /// The graph that should be copied. + public void Clone(IGraph other) + { + m_Data = new BehaviorTreeData(); + m_Data.EventNodes = other.EventNodes; + m_Data.LogicNodes = other.LogicNodes as ITreeLogicNode[]; + m_Data.SharedVariables = other.SharedVariables; + m_Data.DisabledLogicNodes = other.DisabledLogicNodes; + m_Data.DisabledEventNodes = other.DisabledEventNodes; + +#if UNITY_EDITOR + m_Data.EventNodeProperties = other.EventNodeProperties; + m_Data.LogicNodeProperties = other.LogicNodeProperties; + m_Data.GroupProperties = other.GroupProperties; + m_Data.SharedVariableGroups = other.SharedVariableGroups; +#endif + + m_Data.Serialize(); + } + + /// + /// Overrides ToString. + /// + /// The desired string value. + public override string ToString() + { + return $"{m_GraphName} (Index {m_Index})"; + } + + /// + /// Returns the hashcode of the graph. + /// + /// The hashcode of the graph. + public override int GetHashCode() + { + if (m_Subtree != null) { + return m_Subtree.GetHashCode(); + } + return base.GetHashCode(); + } + + /// + /// Callback when the domain should be reloaded. + /// + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] + private static void Reinitialize() + { + s_BehaviorTreeByEntity = new Dictionary(); + } + + /// + /// Enables the baked behavior tree system. + /// + /// The world that the system has been added to. + public static void EnableBakedBehaviorTreeSystem(World world) + { + if (world == null) { + return; + } + + EnableBakedBehaviorTreeSystem(world.Unmanaged); + } + + /// + /// Enables the baked behavior tree system. + /// + /// The unmanged world that the system has been added to. + public static void EnableBakedBehaviorTreeSystem(WorldUnmanaged world) + { + world.GetExistingSystemState().Enabled = true; + } + + /// + /// Converts the behavior tree to a DOTS entity. + /// + public class BehaviorTreeBaker : Baker + { + private static MethodInfo s_GetTypeOfSystemMethod; + + /// + /// Bakes the behavior tree to the DOTS entity. + /// + /// The authoring behavior tree. + public override void Bake(BehaviorTree behaviorTree) + { + if (!behaviorTree.StartWhenEnabled || !behaviorTree.enabled) { + return; + } + + var entity = GetEntity(behaviorTree, TransformUsageFlags.Dynamic); + var worlds = World.All; + for (int i = 0; i < worlds.Count; ++i) { + if (worlds[i].EntityManager.Exists(entity)) { + if (!behaviorTree.InitializeTree(worlds[i], entity)) { + continue; + } + + var connectedIndex = GetStartTaskConnectedIndex(behaviorTree); + if (connectedIndex == -1 || connectedIndex == ushort.MaxValue) { + return; + } + + var taskComponents = worlds[i].EntityManager.GetBuffer(entity); + var tagStableTypeHash = new ulong[taskComponents.Length]; + for (int j = 0; j < taskComponents.Length; ++j) { + tagStableTypeHash[j] = TypeManager.GetTypeInfo(taskComponents[j].FlagComponentType.TypeIndex).StableTypeHash; + } + ulong[] ReevaluateFlagStableTypeHash = null; + if (worlds[i].EntityManager.HasBuffer(entity)) { + var reevaluateTaskComponents = worlds[i].EntityManager.GetBuffer(entity); + ReevaluateFlagStableTypeHash = new ulong[reevaluateTaskComponents.Length]; + for (int j = 0; j < reevaluateTaskComponents.Length; ++j) { + ReevaluateFlagStableTypeHash[j] = TypeManager.GetTypeInfo(reevaluateTaskComponents[j].ReevaluateFlagComponentType.TypeIndex).StableTypeHash; + } + } + + AddComponentObject(entity, new BakedBehaviorTree + { + StartEventConnectedIndex = connectedIndex, + StartEvaluation = behaviorTree.UpdateMode == UpdateMode.EveryFrame, + ReevaluateTaskSystems = GetTaskSystems(worlds[i]), + InterruptTaskSystems = GetTaskSystems(worlds[i]), + TraversalTaskSystems = GetTaskSystems(worlds[i]), + TagStableTypeHashes = tagStableTypeHash, + ReevaluateFlagStableTypeHashes = ReevaluateFlagStableTypeHash, + }); + behaviorTree.Baked = true; + } + } + } + + /// + /// Returns the index of the node connection for the start event task. + /// + /// The interested behavior tree. + /// The index of the node connection for the start event task. + private int GetStartTaskConnectedIndex(BehaviorTree behaviorTree) + { + // The behavior tree has to first be initialized. + if (behaviorTree.World == null || behaviorTree.Entity == Entity.Null) { + Debug.LogError($"Error: Unable to retrieve the connected index on behavior tree {behaviorTree}. The behavior tree has to first be initialized."); + return -1; + } + + var data = behaviorTree.Data; + for (int i = 0; i < data.EventNodes.Length; ++i) { + if (data.EventNodes[i].GetType() == typeof(Start)) { + // The connected index may not be valid. + if (data.EventNodes[i].ConnectedIndex == ushort.MaxValue) { + return ushort.MaxValue; + } + + // The branch cannot start if it is disabled. + if (!behaviorTree.IsNodeEnabled(false, i)) { + return -1; + } + + return data.LogicNodes[data.EventNodes[i].ConnectedIndex].RuntimeIndex; + } + } + return -1; + } + + /// + /// Returns all of the system type indicies within the systems of the specified type. + /// + /// The world that the systems were added to. + /// The system type indicies within the systems of the specified type (can be null). + private string[] GetTaskSystems(World world) where T : ComponentSystemGroup + { + var systemGroup = world.GetExistingSystemManaged(); + if (systemGroup == null) { + return null; + } + + var systems = systemGroup.GetAllSystems(); + if (systems.Length == 0) { + systems.Dispose(); + return null; + } + + // Use reflection to call WorldUnmanaged.GetTypeOfSystem. This method is only called during baking at edit time so reflection is ok, though it would be better + // if this method was eventually made public. + if (s_GetTypeOfSystemMethod == null) { + s_GetTypeOfSystemMethod = typeof(WorldUnmanaged).GetMethod("GetTypeOfSystem", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); + if (s_GetTypeOfSystemMethod == null) { + Debug.LogError("Error: Unable to find WorldUnmanaged.GetTypeOfSystem. Please email support@opsive.com with your Unity version and Entity package version."); + return null; + } + } + + var systemTypes = new string[systems.Length]; + for (int i = 0; i < systems.Length; ++i) { + var systemTypeIndex = TypeManager.GetSystemTypeIndex((Type)s_GetTypeOfSystemMethod.Invoke(world.Unmanaged, new object[] { systems[i] })); + systemTypes[i] = systemTypeIndex.ToString(); + } + systems.Dispose(); + return systemTypes; + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/BehaviorTree.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/BehaviorTree.cs.meta new file mode 100644 index 0000000..cbdaf1c --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/BehaviorTree.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0cdaa3305fa954c45a80c9662aa6f425 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: e0a8f1df788b6274a9a24003859dfa7e, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/BehaviorTreeData.cs b/Packages/com.opsive.behaviordesigner/Runtime/BehaviorTreeData.cs new file mode 100644 index 0000000..b66f8de --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/BehaviorTreeData.cs @@ -0,0 +1,1674 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime +{ + using Opsive.BehaviorDesigner.Runtime.Tasks; + using Opsive.BehaviorDesigner.Runtime.Tasks.Events; + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Utility; + using Opsive.GraphDesigner.Runtime.Variables; + using Opsive.Shared.Utility; + using System; + using System.Collections; + using System.Collections.Generic; + using System.Reflection; + using UnityEngine; + + /// + /// Storage class for the graph data. + /// + [System.Serializable] + public partial class BehaviorTreeData + { + [Tooltip("The serialized Task data.")] + [SerializeField] private Serialization[] m_TaskData; + [Tooltip("The serialized EventTask data.")] + [SerializeField] private Serialization[] m_EventTaskData; + [Tooltip("The serialized SharedVariable data.")] + [SerializeField] private Serialization[] m_SharedVariableData; + [Tooltip("The serialized disabled event nodes data.")] + [SerializeField] private Serialization[] m_DisabledEventNodesData; + [Tooltip("The serialized disabled logic nodes data.")] + [SerializeField] private Serialization[] m_DisabledLogicNodesData; + [Tooltip("The unique ID of the data.")] + [SerializeField] private int m_UniqueID; + + private ITreeLogicNode[] m_Tasks; + private IEventNode[] m_EventTasks; + private SharedVariable[] m_SharedVariables; + private ushort[] m_DisabledLogicNodes; + private ushort[] m_DisabledEventNodes; + private Dictionary m_VariableByNameMap; + private int m_RuntimeUniqueID; + + public ITreeLogicNode[] LogicNodes + { + get => m_Tasks; + set { + if (value == null) { + m_Tasks = null; + } else { + if (m_Tasks == null) { + m_Tasks = new ITreeLogicNode[value.Length]; + } else if (m_Tasks.Length != value.Length) { + Array.Resize(ref m_Tasks, value.Length); + } + for (int i = 0; i < value.Length; ++i) { + m_Tasks[i] = value[i]; + } + } + } + } + public IEventNode[] EventNodes + { + get => m_EventTasks; + set { + if (value == null) { + m_EventTasks = null; + } else { + if (m_EventTasks == null) { + m_EventTasks = new IEventNode[value.Length]; + } else if (m_EventTasks.Length != value.Length) { + Array.Resize(ref m_EventTasks, value.Length); + } + for (int i = 0; i < value.Length; ++i) { + m_EventTasks[i] = value[i]; + } + } + } + } + public SharedVariable[] SharedVariables { get => m_SharedVariables; set => m_SharedVariables = value; } + public int UniqueID { get => m_RuntimeUniqueID != 0 ? m_RuntimeUniqueID : m_UniqueID; } + public ushort[] DisabledLogicNodes { get => m_DisabledLogicNodes; set => m_DisabledLogicNodes = value; } + public ushort[] DisabledEventNodes { get => m_DisabledEventNodes; set => m_DisabledEventNodes = value; } + internal Dictionary VariableByNameMap { get => m_VariableByNameMap; set => m_VariableByNameMap = value; } + internal int RuntimeUniqueID { set => m_RuntimeUniqueID = value; } + +#if UNITY_EDITOR + [Tooltip("The serialized logic node properties data.")] + [SerializeField] private Serialization[] m_LogicNodePropertiesData; + [Tooltip("The serialized event node properties data.")] + [SerializeField] private Serialization[] m_EventNodePropertiesData; + [Tooltip("The serialized group properties data.")] + [SerializeField] private Serialization[] m_GroupPropertiesData; + [Tooltip("The serialized shared variables group data.")] + [SerializeField] private Serialization[] m_SharedVariableGroupsData; + + private LogicNodeProperties[] m_LogicNodeProperties; + private NodeProperties[] m_EventNodeProperties; + private GroupProperties[] m_GroupProperties; + [System.NonSerialized] private SharedVariableGroup[] m_SharedVariableGroups; + + public LogicNodeProperties[] LogicNodeProperties { get => m_LogicNodeProperties; set { m_LogicNodeProperties = value; } } + public NodeProperties[] EventNodeProperties { get => m_EventNodeProperties; set { m_EventNodeProperties = value; } } + public GroupProperties[] GroupProperties { get => m_GroupProperties; set => m_GroupProperties = value; } + public SharedVariableGroup[] SharedVariableGroups { get => m_SharedVariableGroups; set => m_SharedVariableGroups = value; } +#endif + + private ResizableArray m_SubtreeNodesReference; + private ResizableArray m_VariableFields; + [System.NonSerialized] private bool m_Deserializing; + + internal ResizableArray SubtreeNodesReferences { get => m_SubtreeNodesReference; set => m_SubtreeNodesReference = value; } + + /// + /// Default constructor. + /// + public BehaviorTreeData() + { + m_UniqueID = Guid.NewGuid().GetHashCode(); + } + + /// + /// Adds the specified node. + /// + /// The node that should be added. + public void AddNode(ITreeLogicNode node) + { + if (m_Tasks == null) { + m_Tasks = new ITreeLogicNode[1]; + } else { + Array.Resize(ref m_Tasks, m_Tasks.Length + 1); + } + node.Index = (ushort)(m_Tasks.Length - 1); + node.ParentIndex = ushort.MaxValue; + node.SiblingIndex = ushort.MaxValue; + node.RuntimeIndex = ushort.MaxValue; + m_Tasks[m_Tasks.Length - 1] = node; + } + + /// + /// Removes the specified logic node. + /// + /// The node that should be removed. + /// True if the node was removed. + public bool RemoveNode(ITreeLogicNode node) + { + if (m_Tasks == null || node.Index >= m_Tasks.Length) { + return false; + } + + var dest = new ITreeLogicNode[m_Tasks.Length - 1]; + Array.Copy(m_Tasks, dest, node.Index); + Array.Copy(m_Tasks, node.Index + 1, dest, node.Index, m_Tasks.Length - node.Index - 1); + m_Tasks = dest; + return true; + } + + /// + /// Adds the specified event node. + /// + /// The event node that should be added. + public void AddNode(IEventNode eventNode) + { + if (m_EventTasks == null) { + m_EventTasks = new IEventNode[1]; + } else { + Array.Resize(ref m_EventTasks, m_EventTasks.Length + 1); + } + m_EventTasks[m_EventTasks.Length - 1] = eventNode; + } + + /// + /// Removes the specified event node. + /// + /// The event node that should be removed. + /// True if the event node was removed. + public bool RemoveNode(IEventNode eventNode) + { + if (m_EventTasks == null) { + return false; + } + + var index = m_EventTasks.IndexOf(eventNode); + if (index == -1) { + return false; + } + + var dest = new IEventNode[m_EventTasks.Length - 1]; + Array.Copy(m_EventTasks, dest, index); + Array.Copy(m_EventTasks, index + 1, dest, index, m_EventTasks.Length - index - 1); + m_EventTasks = dest; + return true; + } + + /// + /// Serializes the behavior tree. + /// + public void Serialize() + { + if (Application.isPlaying) { + return; + } + + m_TaskData = Serialization.Serialize(m_Tasks, ValidateSerializedObject); + m_EventTaskData = Serialization.Serialize(m_EventTasks, ValidateSerializedObject); + SerializeSharedVariables(); + m_DisabledEventNodesData = Serialization.Serialize(m_DisabledEventNodes); + m_DisabledLogicNodesData = Serialization.Serialize(m_DisabledLogicNodes); + m_UniqueID = Guid.NewGuid().GetHashCode(); + +#if UNITY_EDITOR + // Ensure the node data is up to date. + if (m_LogicNodeProperties != null && m_Tasks != null && m_LogicNodeProperties.Length <= m_Tasks.Length) { + for (int i = 0; i < m_LogicNodeProperties.Length; ++i) { + var nodeData = m_LogicNodeProperties[i].Data; + nodeData.ParentIndex = m_Tasks[i].ParentIndex; + nodeData.SiblingIndex = m_Tasks[i].SiblingIndex; + nodeData.IsParent = m_Tasks[i] is IParentNode; + m_LogicNodeProperties[i].Data = nodeData; + } + } + m_LogicNodePropertiesData = Serialization.Serialize(m_LogicNodeProperties); + m_EventNodePropertiesData = Serialization.Serialize(m_EventNodeProperties); + m_GroupPropertiesData = Serialization.Serialize(m_GroupProperties); +#endif + } + + /// + /// Validates the serialized object. + /// + /// The type of object. + /// The field that the object belongs to. + /// The value of the object + /// The validated object. + public static Serialization.ValidatedObject ValidateSerializedObject(Type type, FieldInfo field, object value) + { + if (value == null) { + return new Serialization.ValidatedObject() { Type = type, Obj = value }; + } + + // Replace ILogicNode with ushort index values. + if (typeof(IList).IsAssignableFrom(type)) { + var elementType = Serializer.GetElementType(type); + if (typeof(ILogicNode).IsAssignableFrom(elementType)) { + if (field == null || field.GetCustomAttribute() == null) { + var tasks = value as IList; + if (tasks == null) { + return new Serialization.ValidatedObject() { Type = type, Obj = value }; + } + + var indexValues = new ushort[tasks.Count]; + for (int i = 0; i < indexValues.Length; ++i) { + indexValues[i] = ((ILogicNode)tasks[i]).Index; + } + return new Serialization.ValidatedObject() { Type = typeof(ushort[]), Obj = indexValues }; + } + } else if (Application.isPlaying && (typeof(GameObject).IsAssignableFrom(elementType) || typeof(Component).IsAssignableFrom(elementType))) { // Scene objects cannot be serialized at runtime. + var listValue = value as IList; + if (listValue != null) { + IList objects; + if (type.IsArray) { + objects = Array.CreateInstance(elementType, listValue.Count); + } else { + if (type.IsGenericType) { + objects = Activator.CreateInstance(typeof(List<>).MakeGenericType(elementType)) as IList; + } else { + objects = Activator.CreateInstance(type) as IList; + } + } + for (int i = 0; i < listValue.Count; ++i) { + GameObject gameObjectValue = null; + if (listValue[i] is Component componentValue) { + gameObjectValue = componentValue.gameObject; + } else { + gameObjectValue = listValue[i] as GameObject; + } + if (gameObjectValue != null && gameObjectValue.scene.IsValid()) { + if (type.IsArray) { + objects[i] = null; + } else { + objects.Add(null); + } + } else { + if (type.IsArray) { + objects[i] = listValue[i]; + } else { + objects.Add(listValue[i]); + } + } + } + listValue = objects; + } + return new Serialization.ValidatedObject() { Type = type, Obj = listValue }; + } + } else if (typeof(ILogicNode).IsAssignableFrom(type)) { + if (field == null || field.GetCustomAttribute() == null) { + return new Serialization.ValidatedObject() { Type = typeof(ushort), Obj = ((ILogicNode)value).Index }; + } + } else if (Application.isPlaying && (typeof(GameObject).IsAssignableFrom(type) || typeof(Component).IsAssignableFrom(type))) { // Scene objects cannot be serialized at runtime. + GameObject gameObjectValue = null; + if (value is Component componentValue) { + gameObjectValue = componentValue.gameObject; + } else { + gameObjectValue = value as GameObject; + } + if (gameObjectValue != null && gameObjectValue.scene.IsValid()) { + return new Serialization.ValidatedObject() { Type = type, Obj = null }; + } + } + return new Serialization.ValidatedObject() { Type = type, Obj = value }; + } + + /// + /// Serializes the SharedVariables. This allows the SharedVariables to be serialized independently. + /// + public void SerializeSharedVariables() + { + if (Application.isPlaying) { + return; + } + + m_SharedVariableData = Serialization.Serialize(m_SharedVariables); +#if UNITY_EDITOR + m_SharedVariableGroupsData = Serialization.Serialize(m_SharedVariableGroups); +#endif + + // Update the mapping for any variable name changes. + if (m_VariableByNameMap == null) { + m_VariableByNameMap = new Dictionary(); + } else { + m_VariableByNameMap.Clear(); + } + if (m_SharedVariables != null) { + for (int i = 0; i < m_SharedVariables.Length; ++i) { + if (m_SharedVariables[i] == null) { + continue; + } + m_VariableByNameMap.Add(new VariableAssignment(m_SharedVariables[i].Name, m_SharedVariables[i].Scope), m_SharedVariables[i]); + } + } + } + + /// + /// Deserialize the behavior tree. + /// + /// The component that the graph is being deserialized from. + /// The graph that is being deserialized. + /// Should the behavior tree be force deserialized? + /// Should the shared variables be force deserialized? + /// Should the subtrees be injected into the behavior tree? + /// Can the SharedVariables be deep copied? + /// A list of SharedVariables that should override the current SharedVariable value. + /// True if the tree was deserialized. + public bool Deserialize(IGraphComponent graphComponent, IGraph graph, bool force, bool forceSharedVariables, bool injectSubtrees, bool canDeepCopyVariables = true, SharedVariableOverride[] sharedVariableOverrides = null) + { + // No need to deserialize if the data is already deserialized. + if (!force && ((m_Tasks != null && m_TaskData != null && m_Tasks.Length == m_TaskData.Length) || (m_EventTasks != null && m_EventTaskData != null && m_EventTasks.Length == m_EventTaskData.Length))) { + // SharedVariables may still need to be deserialized separately. + DeserializeSharedVariables(graph, false, canDeepCopyVariables, sharedVariableOverrides); + + if (Application.isPlaying && m_RuntimeUniqueID == 0) { + m_RuntimeUniqueID = m_UniqueID; + } + return true; + } + + return DeserializeInternal(graphComponent, graph, force, forceSharedVariables, injectSubtrees, canDeepCopyVariables, sharedVariableOverrides); + } + + /// + /// Internal method which deserialize the behavior tree. + /// + /// The component that the graph is being deserialized from. + /// The graph that is being deserialized. + /// Should the behavior tree be force deserialized? + /// Should the shared variables be force deserialized? + /// Should the subtrees be injected into the behavior tree? + /// Can the SharedVariables be deep copied? + /// A list of SharedVariables that should override the current SharedVariable value. + /// True if the tree was deserialized. + private bool DeserializeInternal(IGraphComponent graphComponent, IGraph graph, bool force, bool forceSharedVariables, bool injectSubtrees, bool canDeepCopyVariables, SharedVariableOverride[] sharedVariableOverrides = null) + { + // Prevent the tree from being deserialized recusrively. + if (m_Deserializing) { + Debug.LogError($"Error: Unable to deserialize {graph}. This can be caused by recursive subtree references."); + return false; + } + + m_Deserializing = true; + m_RuntimeUniqueID = Application.isPlaying ? m_UniqueID : 0; + m_VariableFields = null; + var errorState = false; +#if UNITY_EDITOR + // Deserialize the properties first so it can be used elsewhere. + if (m_LogicNodePropertiesData != null && m_LogicNodePropertiesData.Length > 0) { + m_LogicNodeProperties = new LogicNodeProperties[m_LogicNodePropertiesData.Length]; + for (int i = 0; i < m_LogicNodePropertiesData.Length; ++i) { + try { + m_LogicNodeProperties[i] = m_LogicNodePropertiesData[i].DeserializeFields(MemberVisibility.Public) as LogicNodeProperties; + } catch (Exception e) { + m_LogicNodeProperties[i] = new LogicNodeProperties(); + Debug.LogError($"Error: Unable to load task editor data at index {i} due to exception:\n{e}"); + } + } + } else { + m_LogicNodeProperties = null; + } + if (m_EventNodePropertiesData != null && m_EventNodePropertiesData.Length > 0) { + m_EventNodeProperties = new NodeProperties[m_EventNodePropertiesData.Length]; + for (int i = 0; i < m_EventNodePropertiesData.Length; ++i) { + m_EventNodeProperties[i] = m_EventNodePropertiesData[i].DeserializeFields(MemberVisibility.Public) as NodeProperties; + } + } else { + m_EventNodeProperties = null; + } + if (m_GroupPropertiesData != null && m_GroupPropertiesData.Length > 0) { + m_GroupProperties = new GroupProperties[m_GroupPropertiesData.Length]; + for (int i = 0; i < m_GroupPropertiesData.Length; ++i) { + m_GroupProperties[i] = m_GroupPropertiesData[i].DeserializeFields(MemberVisibility.Public) as GroupProperties; + } + } else { + m_GroupProperties = null; + } +#endif + DeserializeSharedVariables(graph, forceSharedVariables, canDeepCopyVariables, sharedVariableOverrides); + + // The disabled node indicies need to be deserialized before the nodes. + if (m_DisabledEventNodesData != null && m_DisabledEventNodesData.Length > 0 && m_EventTaskData != null) { + m_DisabledEventNodes = new ushort[m_DisabledEventNodesData.Length]; + var offset = 0; + for (int i = 0; i < m_DisabledEventNodesData.Length; ++i) { + m_DisabledEventNodes[i] = (ushort)m_DisabledEventNodesData[i].DeserializeFields(MemberVisibility.Public); + // The node index may no longer be valid. + if (m_DisabledEventNodes[i - offset] >= m_EventTaskData.Length) { + offset++; + } + } + if (offset > 0) { + Array.Resize(ref m_DisabledEventNodes, m_DisabledEventNodes.Length - offset); + } + } else { + m_DisabledEventNodes = null; + } + if (m_DisabledLogicNodesData != null && m_DisabledLogicNodesData.Length > 0 && m_TaskData != null) { + m_DisabledLogicNodes = new ushort[m_DisabledLogicNodesData.Length]; + var offset = 0; + for (int i = 0; i < m_DisabledLogicNodesData.Length; ++i) { + m_DisabledLogicNodes[i - offset] = (ushort)m_DisabledLogicNodesData[i].DeserializeFields(MemberVisibility.Public); + // The node index may no longer be valid. + if (m_DisabledLogicNodes[i - offset] >= m_TaskData.Length) { + offset++; + } + } + if (offset > 0) { + Array.Resize(ref m_DisabledLogicNodes, m_DisabledLogicNodes.Length - offset); + } + } else { + m_DisabledLogicNodes = null; + } + + ResizableArray taskReferences = null; + if (m_SubtreeNodesReference != null) { + m_SubtreeNodesReference.Clear(); + } + if (m_TaskData != null && m_TaskData.Length > 0) { + m_Tasks = new ITreeLogicNode[m_TaskData.Length]; + for (int i = 0; i < m_TaskData.Length; ++i) { + try { + var task = m_TaskData[i].DeserializeFields(MemberVisibility.Public, ValidateDeserializedTypeObject, (object fieldInfoObj, object task, object value) => + { + var validatedValue = ValidateDeserializedObject(fieldInfoObj, task, value, ref m_VariableByNameMap, ref taskReferences, sharedVariableOverrides); + if (validatedValue != null && validatedValue is SharedVariable sharedVariable && sharedVariable.Scope == SharedVariable.SharingScope.Graph) { + if (m_VariableFields == null) { m_VariableFields = new ResizableArray(); } + m_VariableFields.Add(new VariableField() { Field = fieldInfoObj as FieldInfo, Task = task, Name = sharedVariable.Name }); + } + return validatedValue; + }) as ILogicNode; + if (task is ITreeLogicNode treeLogicNode) { + m_Tasks[i] = treeLogicNode; + } else if (task is ILogicNode) { + Debug.LogError($"Error: The task {m_TaskData[i].ObjectType} at index {i} must implement ITreeLogicNode."); + } + } catch (Exception e) { + Debug.LogError($"Error: Unable to load task {m_TaskData[i].ObjectType} at index {i} due to exception:\n{e}"); + } + + // Account for tasks where the object no longer exists. + if (m_Tasks[i] == null) { +#if UNITY_EDITOR + if (m_LogicNodeProperties[i].Data.IsParent) { + m_Tasks[i] = new UnknownParentTaskNode(m_TaskData[i].ObjectType); + } else { + m_Tasks[i] = new UnknownTaskNode(m_TaskData[i].ObjectType); + } + m_Tasks[i].Index = (ushort)i; + m_Tasks[i].ParentIndex = m_LogicNodeProperties[i].Data.ParentIndex; + m_Tasks[i].SiblingIndex = m_LogicNodeProperties[i].Data.SiblingIndex; +#else + if (i + 1 < m_Tasks.Length && m_Tasks[i + 1] != null && m_Tasks[i + 1].ParentIndex == i) { + m_Tasks[i] = new UnknownParentTaskNode(m_TaskData[i].ObjectType); + } else { + m_Tasks[i] = new UnknownTaskNode(m_TaskData[i].ObjectType); + } + m_Tasks[i].Index = (ushort)i; +#endif + } + + // The RuntimeIndex is assigned later when the tree is initialized. + m_Tasks[i].RuntimeIndex = ushort.MaxValue; +#if UNITY_EDITOR + // Sanity checks. + if (m_Tasks[i].Index >= m_TaskData.Length) { m_Tasks[i].Index = (ushort)i; } + if (m_Tasks[i].ParentIndex != ushort.MaxValue && m_Tasks[i].ParentIndex >= m_TaskData.Length) { m_Tasks[i].ParentIndex = ushort.MaxValue; } + if (m_Tasks[i].SiblingIndex != ushort.MaxValue && m_Tasks[i].SiblingIndex >= m_TaskData.Length) { m_Tasks[i].SiblingIndex = ushort.MaxValue; } +#endif + + if (injectSubtrees) { + // If the previous task is a parent the current task has to be a child otherwise the tree is in an error state. The error will also occur + // if there is only one task and that task is a parent task. + if ((m_Tasks[i].ParentIndex != ushort.MaxValue && (i > 0 && m_Tasks[i - 1] is IParentNode && m_Tasks[i].ParentIndex != m_Tasks[i - 1].Index)) || (m_Tasks[i] is IParentNode && i + 1 == m_Tasks.Length)) { + Debug.LogError($"Error: {graph} contains the parent task {m_Tasks[i].GetType().Name} which does not have any children. All parent tasks must contain at least one child.", graph.Parent); + errorState = true; + continue; + } + + // Subtrees will be evaluated after all tasks are assigned. + if (m_Tasks[i] is ISubtreeReference subtreeReference) { + // Subtrees can be nested. + subtreeReference.EvaluateSubtrees(graphComponent); + var subtrees = subtreeReference.Subtrees; + if (subtrees != null) { + // The parent must be able to accept the number of subtrees that there are. + var parentIndex = m_Tasks[i].ParentIndex; + IParentNode parentNode = null; + if (parentIndex != ushort.MaxValue) { + parentNode = m_Tasks[parentIndex] as IParentNode; + } + + if ((parentNode == null && subtrees.Length > 1) || (parentNode != null && subtrees.Length > parentNode.MaxChildCount)) { + Debug.LogError($"Error: {graph} on object {graph.Parent} contains multiple subtrees as the starting task or as a child of a parent task which cannot contain so many children (such as a decorator).", graph.Parent); + errorState = true; + continue; + } + + var deserializedNodes = new ITreeLogicNode[subtrees.Length][]; + for (int j = 0; j < subtrees.Length; ++j) { + if (subtrees[j] == null) { + continue; + } + if (!subtrees[j].Deserialize(graphComponent, force && !subtrees[j].Pooled, forceSharedVariables && !subtrees[j].Pooled, true, true, subtreeReference.SharedVariableOverrides)) { + errorState = true; + break; + }; + if (subtrees[j].Data.m_VariableFields != null && subtrees[j].Data.m_VariableFields.Count > 0) { + if (m_VariableFields == null) { m_VariableFields = new ResizableArray(); ; } + m_VariableFields.AddRange(subtrees[j].Data.m_VariableFields); + } + // Keep a reference to the deserialized nodes. This will ensure they are unique and do not get overwritten. + deserializedNodes[j] = subtrees[j].TreeLogicNodes; + + // Add any new subtree variables to the current tree. + if (subtrees[j].SharedVariables != null) { + // In order to reduce allocations the first loop will determine the number of variables that need to be added. + var length = subtrees[j].SharedVariables.Length; + var variableCount = 0; + for (int k = 0; k < length; ++k) { + var subtreeVariable = subtrees[j].SharedVariables[k]; + if (GetVariable(graph, subtreeVariable.Name, SharedVariable.SharingScope.Graph) == null) { + variableCount++; + } + } + + // And the second loop will actually add the variables. + if (variableCount > 0) { + var insertIndex = 0; + if (m_SharedVariables == null) { + m_SharedVariables = new SharedVariable[variableCount]; + m_VariableByNameMap = new Dictionary(); + } else { + insertIndex = m_SharedVariables.Length; + Array.Resize(ref m_SharedVariables, m_SharedVariables.Length + variableCount); + } + for (int k = 0; k < length; ++k) { + var subtreeVariable = subtrees[j].SharedVariables[k]; + if (!m_VariableByNameMap.ContainsKey(new VariableAssignment(subtreeVariable.Name, SharedVariable.SharingScope.Graph))) { + m_SharedVariables[insertIndex] = subtreeVariable; + m_VariableByNameMap.Add(new VariableAssignment(subtreeVariable.Name, SharedVariable.SharingScope.Graph), subtreeVariable); + insertIndex++; + } + } + } + } + } + + // Do not add the subtree if it causes an error. + if (!errorState) { + if (m_SubtreeNodesReference == null) { m_SubtreeNodesReference = new ResizableArray(); } + m_SubtreeNodesReference.Add(new SubtreeNodesReference() + { + SubtreeReference = subtreeReference, + NodeIndex = (ushort)i, + Subtrees = subtrees, + Nodes = deserializedNodes + }); + } + } + } + } + } + } else { + m_Tasks = null; + } + + // Subtrees should be injected into the tree. + InjectSubtrees(); + + // Add the event tasks after the subtrees have been injected to ensure the connected index is correct. + if (m_EventTaskData != null && m_EventTaskData.Length > 0) { + m_EventTasks = new IEventNode[m_EventTaskData.Length]; + for (int i = 0; i < m_EventTaskData.Length; ++i) { + m_EventTasks[i] = m_EventTaskData[i].DeserializeFields(MemberVisibility.Public, ValidateDeserializedTypeObject, (object fieldInfoObj, object task, object value) => + { + var validatedValue = ValidateDeserializedObject(fieldInfoObj, task, value, ref m_VariableByNameMap, ref taskReferences, sharedVariableOverrides); + if (validatedValue != null && validatedValue is SharedVariable sharedVariable && sharedVariable.Scope == SharedVariable.SharingScope.Graph) { + if (m_VariableFields == null) { m_VariableFields = new ResizableArray(); } + m_VariableFields.Add(new VariableField() { Field = fieldInfoObj as FieldInfo, Task = task, Name = sharedVariable.Name }); + } + return validatedValue; + }) as IEventNode; + + if (m_SubtreeNodesReference != null) { + // A subtree may have injected nodes before the originally connected index. Modify the index to match the injection. + var offset = 0; + for (int j = 0; j < m_SubtreeNodesReference.Count; ++j) { + if (m_SubtreeNodesReference[j].NodeIndex >= m_EventTasks[i].ConnectedIndex) { + break; + } + offset += m_SubtreeNodesReference[j].NodeCount - 1; + } + if (offset > 0) { + m_EventTasks[i].ConnectedIndex += (ushort)offset; + } + } + + if (m_EventTasks[i] == null) { + m_EventTasks[i] = new UnknownEventTask(); + } + } + } else { + m_EventTasks = null; + } + + // After the tree has been deserialized the task references need to be assigned. + AssignTaskReferences(m_Tasks, taskReferences); + + m_Deserializing = false; + + return !errorState; + } + + /// + /// Validates the object type when deserializing. + /// + /// The type of object that should be validated. + /// The field that contains the object. + /// The validated type. + public static Type ValidateDeserializedTypeObject(Type type, FieldInfo field) + { + if (typeof(IList).IsAssignableFrom(type)) { + var elementType = Serializer.GetElementType(type); + if (typeof(ILogicNode).IsAssignableFrom(elementType) && (field == null || field.GetCustomAttribute() == null)) { + return typeof(ushort[]); + } + } else if (typeof(ILogicNode).IsAssignableFrom(type) && (field == null || field.GetCustomAttribute() == null)) { + return typeof(ushort); + } + return type; + } + + /// + /// Validates the object when deserializing. + /// + /// The FieldInfo that is being deserialized. + /// The object being deserialized. + /// The value of the field. + /// A reference to the map between the VariableAssignment and SharedVariable. + /// A reference to the list of task references that need to be resolved later. + /// A list of SharedVariables that should override the current SharedVariable value. + /// The validated object. + public static object ValidateDeserializedObject(object fieldInfoObj, object target, object value, ref Dictionary variableByNameMap, + ref ResizableArray taskReferences, SharedVariableOverride[] sharedVariableOverrides = null) + { + var fieldInfo = fieldInfoObj as FieldInfo; + if (fieldInfo == null) { + return value; + } + + var type = fieldInfo.FieldType; + if (value == null) { + // A SharedVariable object should always exist. + if (!type.IsAbstract && typeof(SharedVariable).IsAssignableFrom(type)) { + return Activator.CreateInstance(type); + } + return null; + } + + if (typeof(IList).IsAssignableFrom(type)) { + var elementType = Serializer.GetElementType(type); + if (typeof(ILogicNode).IsAssignableFrom(elementType) && fieldInfo.GetCustomAttribute() == null) { + // The task reference will be assigned after all of the tasks have been deserialized. + if (taskReferences == null) { taskReferences = new ResizableArray(); } + taskReferences.Add(new TaskAssignment() { Field = fieldInfo, Target = target, Value = value }); + } else if (typeof(SharedVariable).IsAssignableFrom(elementType)) { + var listValue = value as IList; + if (listValue != null) { + for (int i = 0; i < listValue.Count; ++i) { + var sharedVariableElement = listValue[i] as SharedVariable; + if (variableByNameMap != null && sharedVariableElement != null && !string.IsNullOrEmpty(sharedVariableElement.Name)) { + if (variableByNameMap.TryGetValue(new VariableAssignment(sharedVariableElement.Name, sharedVariableElement.Scope), out var mappedSharedVariable)) { + if (Application.isPlaying && sharedVariableElement.Scope == SharedVariable.SharingScope.Dynamic && sharedVariableElement.GetType() != mappedSharedVariable.GetType()) { + Debug.LogError($"Error: The dynamic variables with name {sharedVariableElement.Name} have different types. All dynamic variables must have the same type."); + listValue[i] = sharedVariableElement; + } else { + listValue[i] = GetOverrideVariable(sharedVariableOverrides, mappedSharedVariable, false); + } + } else if (sharedVariableElement.Scope == SharedVariable.SharingScope.Dynamic) { + // New dynamic variables should have the default value. + var sharedVariableValueType = sharedVariableElement.GetType().GetGenericArguments()[0]; + if (sharedVariableValueType.IsValueType) { + sharedVariableElement.SetValue(Activator.CreateInstance(sharedVariableValueType)); + } else { + sharedVariableElement.SetValue(null); + } + + // Dynamic variables are created when the task is deserialized. The variable needs to be added to the mapping so it can be reused. + variableByNameMap.Add(new VariableAssignment(sharedVariableElement.Name, sharedVariableElement.Scope), sharedVariableElement); + listValue[i] = sharedVariableElement; + } + } + + } + return listValue; + } + } + } else if (typeof(ILogicNode).IsAssignableFrom(type) && fieldInfo.GetCustomAttribute() == null) { + // The task reference will be assigned after all of the tasks have been deserialized. + if (taskReferences == null) { taskReferences = new ResizableArray(); } + taskReferences.Add(new TaskAssignment() { Field = fieldInfo, Target = target, Value = value }); + } else if (typeof(SharedVariable).IsAssignableFrom(type)) { + var sharedVariable = value as SharedVariable; + if (variableByNameMap != null && sharedVariable != null && !string.IsNullOrEmpty(sharedVariable.Name)) { + if (variableByNameMap.TryGetValue(new VariableAssignment(sharedVariable.Name, sharedVariable.Scope), out var mappedSharedVariable)) { + if (Application.isPlaying && sharedVariable.Scope == SharedVariable.SharingScope.Dynamic && sharedVariable.GetType() != mappedSharedVariable.GetType()) { + Debug.LogError($"Error: The dynamic variables with name {sharedVariable.Name} have different types. Dynamic variables with the same name must have the same type."); + return sharedVariable; + } + var val = GetOverrideVariable(sharedVariableOverrides, mappedSharedVariable, false); + return val; + } else if (Application.isPlaying && sharedVariable.Scope == SharedVariable.SharingScope.Dynamic) { + // New dynamic variables should have the default value. + var sharedVariableValueType = sharedVariable.GetType().GetGenericArguments()[0]; + if (sharedVariableValueType.IsValueType) { + sharedVariable.SetValue(Activator.CreateInstance(sharedVariableValueType)); + } else { + sharedVariable.SetValue(null); + } + + // Dynamic variables are created when the task is deserialized. The variable needs to be added to the mapping so it can be reused. + variableByNameMap.Add(new VariableAssignment(sharedVariable.Name, sharedVariable.Scope), sharedVariable); + return sharedVariable; + } + } + } + + return value; + } + + /// + /// Deserializes the SharedVariables. This allows the SharedVariables to be deserialized independently. + /// + /// The graph that is being deserialized. + /// Should the variables be forced deserialized? + /// Can the SharedVariables be deep copied? + /// A list of SharedVariables that should override the current SharedVariable value. + /// True if the SharedVariables were deserialized. + public bool DeserializeSharedVariables(IGraph graph, bool force, bool canDeepCopy, SharedVariableOverride[] sharedVariableOverrides = null) + { + // No need to deserialize if the data is already deserialized. + if (!force && (m_SharedVariables != null || m_VariableByNameMap != null +#if UNITY_EDITOR + || m_SharedVariableGroups != null +#endif + )) { + return false; + } + + if (m_SharedVariableData != null && m_SharedVariableData.Length > 0) { + m_SharedVariables = new SharedVariable[m_SharedVariableData.Length]; + for (int i = 0; i < m_SharedVariableData.Length; ++i) { + try { + m_SharedVariables[i] = m_SharedVariableData[i].DeserializeFields(MemberVisibility.Public) as SharedVariable; + } catch (Exception e) { + Debug.LogError($"Error: Unable to load variable {m_SharedVariableData[i].ObjectType} at index {i} due to exception:\n{e}"); + } + + if (m_SharedVariables[i] == null) { + var unknownSharedVariableData = m_SharedVariableData[i]; + unknownSharedVariableData.ObjectType = typeof(UnknownSharedVariable).FullName; + m_SharedVariables[i] = unknownSharedVariableData.DeserializeFields(MemberVisibility.Public) as SharedVariable; + + Debug.LogError($"Error: Unable to deserialize SharedVariable {m_SharedVariables[i].Name} of type {m_SharedVariableData[i].ObjectType}."); + } + + // The override variable can set a value specific for the subtree. + if (Application.isPlaying) { + m_SharedVariables[i].Initialize(); + + var overrideVariable = GetOverrideVariable(sharedVariableOverrides, m_SharedVariables[i], true); + // If the overridden scope is self then only the value should be overridden and not the SharedVariable reference. + if (overrideVariable != null && overrideVariable.Scope == SharedVariable.SharingScope.Self) { + m_SharedVariables[i].SetValue(overrideVariable.GetValue()); + } + } + } + } else { + m_SharedVariables = null; + } + m_VariableByNameMap = PopulateSharedVariablesMapping(graph, canDeepCopy); + +#if UNITY_EDITOR + if (m_SharedVariableGroupsData != null && m_SharedVariableGroupsData.Length > 0) { + m_SharedVariableGroups = new SharedVariableGroup[m_SharedVariableGroupsData.Length]; + for (int i = 0; i < m_SharedVariableGroupsData.Length; ++i) { + m_SharedVariableGroups[i] = m_SharedVariableGroupsData[i].DeserializeFields(MemberVisibility.Public) as SharedVariableGroup; + } + } else { + m_SharedVariableGroups = null; + } +#endif + + return true; + } + + /// + /// Returns the override SharedVariable from the source SharedVariable. + /// + /// The list of override SharedVariables. + /// The variable that should be overridden. + /// Is the method being called when the variables are being deserialized? + /// The override SharedVariable (can be null). + private static SharedVariable GetOverrideVariable(SharedVariableOverride[] sharedVariableOverrides, SharedVariable graphVariable, bool deserialize) + { + if (sharedVariableOverrides == null) { + return deserialize ? null : graphVariable; + } + + for (int i = 0; i < sharedVariableOverrides.Length; ++i) { + var overrideVariable = sharedVariableOverrides[i].Override; + // Empty variables indicate that the variable should not be overridden. + if (overrideVariable == null || overrideVariable.Scope == SharedVariable.SharingScope.Empty) { + continue; + } + + // The override variable should be used if the name and the type matches. + var sourceVariable = sharedVariableOverrides[i].Source; + if (sourceVariable.GetType() != graphVariable.GetType() || sourceVariable.Name != graphVariable.Name) { + continue; + } + + // If the scope is self then the graphVariable value should be updated instead of completely replaced. + if (overrideVariable.Scope == SharedVariable.SharingScope.Self) { + graphVariable.SetValue(overrideVariable.GetValue()); + return graphVariable; + } + + return overrideVariable; + } + + return graphVariable; + } + + /// + /// Populates the SharedVariable Mapping at runtime. + /// + /// The graph that is being deserialized. + /// Can the SharedVariables be deep copied? + /// A reference to the map between the VariableAssignment and SharedVariable. + public static Dictionary PopulateSharedVariablesMapping(IGraph graph, bool canDeepCopy) + { + var variableByNameMap = new Dictionary(); + PopulateSharedVariablesMapping(graph, graph.SharedVariables, SharedVariable.SharingScope.Graph, canDeepCopy, ref variableByNameMap); + + if (graph.Parent is GameObject parentGameObject) { + var gameObjectSharedVariablesContainer = parentGameObject.GetComponent(); + if (gameObjectSharedVariablesContainer != null) { + gameObjectSharedVariablesContainer.Deserialize(false); + PopulateSharedVariablesMapping(graph, gameObjectSharedVariablesContainer.SharedVariables, SharedVariable.SharingScope.GameObject, canDeepCopy, ref variableByNameMap); + } + } + + var sceneSharedVariablesContainer = SceneSharedVariables.Instance; + if (sceneSharedVariablesContainer != null) { + sceneSharedVariablesContainer.Deserialize(false); + PopulateSharedVariablesMapping(graph, sceneSharedVariablesContainer.SharedVariables, SharedVariable.SharingScope.Scene, canDeepCopy, ref variableByNameMap); + } + + var projectSharedVariablesContainer = ProjectSharedVariables.Instance; + if (projectSharedVariablesContainer != null) { + projectSharedVariablesContainer.Deserialize(false); + PopulateSharedVariablesMapping(graph, projectSharedVariablesContainer.SharedVariables, SharedVariable.SharingScope.Project, canDeepCopy, ref variableByNameMap); + } + return variableByNameMap; + } + + /// + /// Populates the name variables mapping with the specified SharedVariables. + /// + /// The graph that is being deserialized. + /// The SharedVariables that should be populated. + /// The scope of SharedVariables. + /// Can the SharedVariables be deep copied? + /// A reference to the map between the VariableAssignment and SharedVariable. + private static void PopulateSharedVariablesMapping(IGraph graph, SharedVariable[] sharedVariables, SharedVariable.SharingScope scope, bool canDeepCopy, ref Dictionary variableByNameMap) + { + if (sharedVariables == null) { + return; + } + + var deepCopy = canDeepCopy && graph is Subtree && scope == SharedVariable.SharingScope.Graph; // Deep copy variables so the instance is not bound to the subtree. + for (int i = 0; i < sharedVariables.Length; ++i) { + if (sharedVariables[i] == null) { + continue; + } + if (variableByNameMap.ContainsKey(new VariableAssignment(sharedVariables[i].Name, scope))) { +#if UNITY_EDITOR + Debug.LogWarning("Warning: Multiple SharedVariables with the same name have been added. Please email support@opsive.com with the steps to reproduce this warning. Thank you."); +#endif + continue; + } + var val = new VariableAssignment(sharedVariables[i].Name, scope); + variableByNameMap.Add(val, deepCopy ? CopyUtility.DeepCopy(sharedVariables[i]) as SharedVariable : sharedVariables[i]); + } + } + + /// + /// When the behavior tree loads not all tasks will be deserialized instantly. TaskA may reference TaskB but TaskB hasn't + /// been deserialized yet. The TaskAssignment data structure will store all of the references that need to be restored after + /// the behavior tree has fully been deserialized. + /// + /// The tasks that belong to the graph. + /// The tasks that should be referenced. + public static void AssignTaskReferences(ILogicNode[] tasks, ResizableArray taskReferences) + { + if (taskReferences == null) { + return; + } + + for (int i = 0; i < taskReferences.Count; ++i) { + var taskReference = taskReferences[i]; + var fieldType = taskReference.Field.FieldType; + object value = null; + + // The field can be a list or single value. + if (typeof(IList).IsAssignableFrom(fieldType)) { + var elements = (IList)taskReferences[i].Value; + if (fieldType.IsArray) { + // The field type is an array. Create a new array with all of the task instances. + var array = Array.CreateInstance(Serializer.GetElementType(fieldType), elements.Count) as ILogicNode[]; + for (int j = 0; j < array.Length; ++j) { + var index = (ushort)elements[j]; + if (index < tasks.Length) { + array[j] = tasks[index]; + } + } + value = array; + } else { + // The field type is a list. Create a new list with all of the task instances. + IList taskList; + if (fieldType.IsGenericType) { + taskList = Activator.CreateInstance(typeof(List<>).MakeGenericType(Serializer.GetElementType(fieldType))) as IList; + } else { + taskList = Activator.CreateInstance(fieldType) as IList; + } + + for (int j = 0; j < elements.Count; ++j) { + var index = (ushort)elements[j]; + if (index < tasks.Length) { + taskList.Add(tasks[index]); + } + } + value = taskList; + } + } else { // Single ILogicNode value. + var index = (ushort)taskReference.Value; + if (index < tasks.Length) { + value = tasks[index]; + } + } + if (value != null) { + taskReference.Field.SetValue(taskReference.Target, value); + } + } + } + + /// + /// Injects the subtree into the task list. + /// + private void InjectSubtrees() + { + if (m_SubtreeNodesReference == null || m_SubtreeNodesReference.Count == 0) { + return; + } + + // The behavior tree must generate a new ID when subtrees are injected. + m_RuntimeUniqueID = Guid.NewGuid().GetHashCode(); + + var taskCount = 0; + var subtreeReferenceCount = 0; + var subtreeAssignments = new ResizableArray(); + var lastParentIndex = m_Tasks[m_SubtreeNodesReference[0].NodeIndex].ParentIndex; + var parentIndexOffset = 0; + for (int i = 0; i < m_SubtreeNodesReference.Count; ++i) { + var subtreeReference = m_Tasks[m_SubtreeNodesReference[i].NodeIndex] as ISubtreeReference; + var subtrees = subtreeReference.Subtrees; + if (subtrees != null) { + var indexOffset = (ushort)0; // The index offset is relative to each individual ISubtreeReference task. + + // The parent index will change based on the number of tasks that have been added. + var parentIndex = m_Tasks[m_SubtreeNodesReference[i].NodeIndex].ParentIndex; + if (parentIndex != ushort.MaxValue && (parentIndex > lastParentIndex || (i > 0 && lastParentIndex == ushort.MaxValue))) { + parentIndexOffset = (ushort)(taskCount - subtreeReferenceCount); + lastParentIndex = parentIndex; + } else if (parentIndex < lastParentIndex) { + parentIndexOffset = 0; + lastParentIndex = parentIndex; + } + + // Calculate the parent index offset based on previously injected subtrees + for (int j = 0; j < subtrees.Length; ++j) { + if (subtrees[j] == null || subtrees[j].LogicNodes == null || subtrees[j].EventNodes == null) { + continue; + } + + // The subtree should start from the start node. + var startNode = subtrees[j].GetEventNode(typeof(Start)); // Returns (IEventNode, index). + if (startNode.Item1 == null || startNode.Item1.ConnectedIndex == ushort.MaxValue || !subtrees[j].IsNodeEnabled(false, startNode.Item2)) { + continue; + } + + var firstNode = m_SubtreeNodesReference[i].Nodes[j][startNode.Item1.ConnectedIndex]; + var subtreeNodeCount = GetChildCount(firstNode, m_SubtreeNodesReference[i].Nodes[j]) + 1; // firstNode should be included in addition to the children. + taskCount += subtreeNodeCount; + subtreeAssignments.Add(new SubtreeAssignment() + { + ReferenceIndex = i, + NodeIndex = m_SubtreeNodesReference[i].NodeIndex, + SubtreeIndex = j, + Subtree = subtrees[j], + NodeCount = (ushort)subtreeNodeCount, + IndexOffset = indexOffset, + ParentIndex = (ushort)(parentIndex + parentIndexOffset), + SiblingIndex = m_Tasks[m_SubtreeNodesReference[i].NodeIndex].SiblingIndex, +#if UNITY_EDITOR + NodePropertiesPosition = m_LogicNodeProperties[m_SubtreeNodesReference[i].NodeIndex].Position, + Collapsed = m_LogicNodeProperties[m_SubtreeNodesReference[i].NodeIndex].Collapsed +#endif + }); + indexOffset += (ushort)subtreeNodeCount; + } + + // Update the parent index offset for the next subtree reference + if (indexOffset > 0) { // Subtree References may not contain any valid subtrees. + subtreeReferenceCount++; + } + var subtreeNodesReferenceOrig = m_SubtreeNodesReference[i]; + subtreeNodesReferenceOrig.NodeCount = indexOffset; + m_SubtreeNodesReference[i] = subtreeNodesReferenceOrig; + } + } + + if (taskCount == 0) { + return; + } + + var targetCount = m_Tasks.Length + taskCount - subtreeReferenceCount; + var originalTaskCount = m_Tasks.Length; + if (m_Tasks.Length != targetCount) { + Array.Resize(ref m_Tasks, targetCount); +#if UNITY_EDITOR + Array.Resize(ref m_LogicNodeProperties, targetCount); +#endif + } + + // Make space for all of the subtree tasks. + var addedTasks = 0; + for (int i = 0; i < subtreeAssignments.Count; ++i) { + var subtreeIndex = (ushort)(subtreeAssignments[i].NodeIndex + addedTasks); + var subtreeTaskCount = subtreeAssignments[i].NodeCount - (subtreeAssignments[i].IndexOffset == 0 ? 1 : 0); + if (subtreeTaskCount > 0) { // subtreeTaskCount will be zero if a single task replaces the reference task. + for (int j = originalTaskCount - 1 + addedTasks; j > subtreeIndex; --j) { + var node = m_Tasks[j]; + node.Index += (ushort)subtreeTaskCount; + if (node.ParentIndex > subtreeIndex && node.ParentIndex != ushort.MaxValue) { + node.ParentIndex += (ushort)subtreeTaskCount; + } + if (node.SiblingIndex > subtreeIndex && node.SiblingIndex != ushort.MaxValue) { + node.SiblingIndex += (ushort)subtreeTaskCount; + } + m_Tasks[j + subtreeTaskCount] = node; + m_Tasks[j] = null; +#if UNITY_EDITOR + m_LogicNodeProperties[j + subtreeTaskCount] = m_LogicNodeProperties[j]; +#endif + } + + // The parents need to adjust their sibling index offsets for the newly added nodes. This should only be done with an index offset of 0 + // as grouped subtrees have the same parents. + if (subtreeAssignments[i].IndexOffset == 0) { + var parentIndex = m_Tasks[subtreeIndex].ParentIndex; + while (parentIndex != ushort.MaxValue) { + var parentNode = m_Tasks[parentIndex]; + if (parentNode.SiblingIndex != ushort.MaxValue) { + parentNode.SiblingIndex += (ushort)subtreeTaskCount; + m_Tasks[parentIndex] = parentNode; + } + parentIndex = parentNode.ParentIndex; + } + } + + // Any disabled nodes after the insertion needs to shift. + var lastDisabledNodeIndex = 0; + if (m_DisabledLogicNodes != null) { + for (int j = 0; j < m_DisabledLogicNodes.Length; ++j) { + if (m_DisabledLogicNodes[j] > subtreeIndex) { + m_DisabledLogicNodes[j] += (ushort)subtreeTaskCount; + } else { // Remember the last index that was greater than the subtree index so any disabled subtree nodes can be inserted. + lastDisabledNodeIndex = j + 1; + } + } + } + + // If the parent reference task is disabled then all subtree nodes should be disabled. + var subtreeDisabledLogicNodes = subtreeAssignments[i].Subtree.DisabledLogicNodes; + if (!IsNodeEnabled(true, m_SubtreeNodesReference[subtreeAssignments[i].ReferenceIndex].NodeIndex)) { + subtreeDisabledLogicNodes = new ushort[subtreeAssignments[i].NodeCount]; + for (ushort j = 0; j < subtreeDisabledLogicNodes.Length; ++j) { + subtreeDisabledLogicNodes[j] = j; + } + } + + // The subtree may have disabled tasks. + if (subtreeDisabledLogicNodes != null && subtreeDisabledLogicNodes.Length > 0) { + var subtreeDisabledLength = subtreeDisabledLogicNodes.Length; + // Ensure all of the disabled logic nodes have been transferred. + for (int j = subtreeDisabledLength - 1; j >= 0; --j) { + if (subtreeDisabledLogicNodes[j] > subtreeTaskCount) { + subtreeDisabledLength--; + } + } + + if (subtreeDisabledLength > 0) { + if (m_DisabledLogicNodes == null) { + m_DisabledLogicNodes = new ushort[subtreeDisabledLength]; + } else { + Array.Resize(ref m_DisabledLogicNodes, m_DisabledLogicNodes.Length + subtreeDisabledLength); + } + var originalLength = m_DisabledLogicNodes.Length - subtreeDisabledLength; + for (int j = lastDisabledNodeIndex; j < originalLength; ++j) { + m_DisabledLogicNodes[j + subtreeDisabledLength] = m_DisabledLogicNodes[j]; + } + for (int j = 0; j < subtreeDisabledLength; ++j) { + if (subtreeDisabledLogicNodes[j] > subtreeTaskCount) { + continue; + } + m_DisabledLogicNodes[lastDisabledNodeIndex + j] = (ushort)(subtreeIndex + subtreeDisabledLogicNodes[j]); + } + } + } + } + // Tasks were added to the tree. Update the tree to the correct indicies. + var subtreeAssignment = subtreeAssignments[i]; + subtreeAssignment.IndexOffset = (ushort)(addedTasks + (subtreeAssignments[i].IndexOffset == 0 ? 0 : 1)); + subtreeAssignments[i] = subtreeAssignment; + + addedTasks += subtreeTaskCount; + } + + // Populate the tasks with the subtree. + for (int i = 0; i < subtreeAssignments.Count; ++i) { + var subtreeIndex = (ushort)(subtreeAssignments[i].NodeIndex + subtreeAssignments[i].IndexOffset); + var subtreeParentIndex = subtreeAssignments[i].ParentIndex; +#if UNITY_EDITOR + var positionOffset = Vector2.zero; +#endif + for (int j = 0; j < subtreeAssignments[i].NodeCount; ++j) { + var node = m_SubtreeNodesReference[subtreeAssignments[i].ReferenceIndex].Nodes[subtreeAssignments[i].SubtreeIndex][j]; + // The node needs to be copied if it isn't pooled to prevent the same node from being used in multiple trees. + if (!m_SubtreeNodesReference[subtreeAssignments[i].ReferenceIndex].Subtrees[subtreeAssignments[i].SubtreeIndex].Pooled) { + var copiedNode = CopyUtility.DeepCopy(node) as ITreeLogicNode; + if (m_VariableFields != null && m_VariableFields.Count > 0) { + // Replace the old node reference with the updated reference. + var nodeMap = new Dictionary(); + nodeMap.Add(node, copiedNode); + if (node is IContainerNode containerNode) { + if (containerNode.Nodes != null) { + var copiedContainerNode = copiedNode as IContainerNode; + for (int k = 0; k < containerNode.Nodes.Length; ++k) { + nodeMap.Add(containerNode.Nodes[k], copiedContainerNode.Nodes[k]); + } + } + } + for (int k = 0; k < m_VariableFields.Count; ++k) { + if (nodeMap.TryGetValue(m_VariableFields[k].Task, out var copiedTask)) { + var variableField = m_VariableFields[k]; + variableField.Task = copiedTask; + m_VariableFields[k] = variableField; + } + } + } + node = copiedNode; + } + node.Index = (ushort)(subtreeIndex + j); + node.RuntimeIndex = ushort.MaxValue; + if (j == 0) { + node.ParentIndex = subtreeParentIndex; + subtreeParentIndex = node.Index; // The subsequent subtree tasks should use the first subtree task as the parent reference. + // If there's a next subtree from the same reference task, point to its first node. Otherwise, use the original SiblingIndex. + if (i + 1 < subtreeAssignments.Count && subtreeAssignments[i + 1].ReferenceIndex == subtreeAssignments[i].ReferenceIndex) { + // Point to the first node of the next subtree. + var nextSubtreeIndex = (ushort)(subtreeAssignments[i + 1].NodeIndex + subtreeAssignments[i + 1].IndexOffset); + node.SiblingIndex = nextSubtreeIndex; + } else { + // Use the original SiblingIndex from the reference task. + node.SiblingIndex = subtreeAssignments[i].SiblingIndex != ushort.MaxValue ? (ushort)(subtreeIndex + subtreeAssignments[i].NodeCount) : ushort.MaxValue; + } + } else { + // Adjust the subsequent subtree tasks by the location of the insertion. + node.ParentIndex += subtreeParentIndex; + if (node.SiblingIndex != ushort.MaxValue) { + node.SiblingIndex += subtreeIndex; + } + } + m_Tasks[subtreeIndex + j] = node; +#if UNITY_EDITOR + var nodeProperties = CopyUtility.DeepCopy(subtreeAssignments[i].Subtree.LogicNodeProperties[j]) as LogicNodeProperties; + nodeProperties.GuidString = Guid.NewGuid().ToString(); + if (j == 0) { + // Keep the tasks in the same relative position as the subtree reference. + positionOffset = subtreeAssignments[i].NodePropertiesPosition - subtreeAssignments[i].Subtree.LogicNodeProperties[j].Position; + } else { + // Apply a small offset for stacked subtrees so they are not directly overlapping. + positionOffset += new Vector2(2, 2); + } + nodeProperties.Position += positionOffset; + nodeProperties.Collapsed = subtreeAssignments[i].Collapsed; + m_LogicNodeProperties[subtreeIndex + j] = nodeProperties; +#endif + } + } + } + + /// + /// Returns the Node of the specified type. + /// + /// The type of Node that should be retrieved. + /// The Node of the specified type (can be null). + public ITreeLogicNode GetNode(Type type) + { + if (m_Tasks == null) { + return null; + } + + for (int i = 0; i < m_Tasks.Length; ++i) { + if (m_Tasks[i].GetType() == type) { + return m_Tasks[i]; + } + } + return null; + } + + /// + /// Returns the event node of the specified type. + /// + /// The type of EventNode that should be retrieved. + /// The EventNode of the specified type (can be null). If the node is found the index will also be returned. + public (IEventNode, ushort) GetEventNode(Type type) + { + if (m_EventTasks == null) { + return (null, ushort.MaxValue); + } + + for (ushort i = 0; i < m_EventTasks.Length; ++i) { + if (m_EventTasks[i].GetType() == type) { + return (m_EventTasks[i], i); + } + } + return (null, ushort.MaxValue); + } + + /// + /// Returns the total number of children belonging to the specified node. + /// + /// The node to retrieve the child count of. + /// All of the nodes that belong to the graph. + /// The total number of children belonging to the specified node. + public int GetChildCount(ITreeLogicNode node, ITreeLogicNode[] nodes) + { + if (node.SiblingIndex != ushort.MaxValue) { + return node.SiblingIndex - node.Index - 1; + } + + if (node.Index + 1 == nodes.Length) { + return 0; + } + + var child = nodes[node.Index + 1]; + if (child.ParentIndex != node.Index) { + return 0; + } + + // Determine the child count based off of the sibling index. + while (child.SiblingIndex != ushort.MaxValue) { + child = nodes[child.SiblingIndex]; + } + + return child.Index - node.Index + GetChildCount(child, nodes); + } + + /// + /// Reevaluates the SubtreeReferences by calling the EvaluateSubtrees method. + /// + /// The component that the graph is being deserialized from. + /// The graph that is being reevaluated. + /// Action that should be done before the tasks are swapped. + /// True if the subtree was reevaluated. + public bool ReevaluateSubtreeReferences(IGraphComponent graphComponent, IGraph graph, Action onBeforeReevaluationSwap) + { + // The tree must contain tasks. + if (!Application.isPlaying || m_Tasks == null || m_Tasks.Length == 0) { + return false; + } + + // Subtree references must exist. + if (m_SubtreeNodesReference == null || m_SubtreeNodesReference.Count == 0) { + return false; + } + + if (onBeforeReevaluationSwap != null) { + onBeforeReevaluationSwap(); + } + + // Find the new reevaluated nodes. + for (int i = m_SubtreeNodesReference.Count - 1; i >= 0; --i) { + var subtreeNodesReference = m_SubtreeNodesReference[i]; + var subtreeReference = m_SubtreeNodesReference[i].SubtreeReference; + subtreeReference.EvaluateSubtrees(graphComponent); + var reevaluatedSubtrees = subtreeReference.Subtrees; + ITreeLogicNode[][] reevaluatedNodes; + if (reevaluatedSubtrees == null) { + continue; + } + + // The parent must be able to accept the number of subtrees that there are. + var parentIndex = m_Tasks[m_SubtreeNodesReference[i].NodeIndex].ParentIndex; + IParentNode parentNode = null; + if (parentIndex != ushort.MaxValue) { + parentNode = m_Tasks[parentIndex] as IParentNode; + } + + if ((parentNode == null && reevaluatedSubtrees.Length > 1) || (parentNode != null && reevaluatedSubtrees.Length > parentNode.MaxChildCount)) { + Debug.LogError($"Error: the reevaluated graph contains multiple subtrees as the starting task or as a child of a parent task which cannot contain so many children (such as a decorator)."); + continue; + } + + reevaluatedNodes = new ITreeLogicNode[reevaluatedSubtrees.Length][]; + var errorState = false; + for (int j = 0; j < reevaluatedSubtrees.Length; ++j) { + if (reevaluatedSubtrees[j] == null) { + continue; + } + if (!reevaluatedSubtrees[j].Deserialize(graphComponent, true, true, true, true, subtreeReference.SharedVariableOverrides)) { + errorState = true; + break; + }; + // Keep a reference to the deserialized nodes. This will ensure they are unique and do not get overwritten. + reevaluatedNodes[j] = reevaluatedSubtrees[j].TreeLogicNodes; + } + if (errorState) { + continue; + } + + // The subtree index will be offsetted from the original index value if there are multiple subtree references. + var nodeOffset = 0; + for (int j = i - 1; j >= 0; --j) { + nodeOffset += m_SubtreeNodesReference[j].NodeCount - 1; + } + + // All of the reevaluated nodes have been determined. Remove the old subtree nodes. + var nodeCount = m_SubtreeNodesReference[i].NodeCount; + + // Replace the first node with the subtree reference, and remove the rest of the added nodes. + m_Tasks[m_SubtreeNodesReference[i].NodeIndex + nodeOffset] = m_SubtreeNodesReference[i].SubtreeReference as ITreeLogicNode; + for (int j = m_SubtreeNodesReference[i].NodeIndex + nodeOffset + 1; j < m_Tasks.Length - nodeCount + 1; ++j) { + m_Tasks[j] = m_Tasks[j + nodeCount - 1]; + m_Tasks[j].Index = (ushort)j; + if (m_Tasks[j].ParentIndex != ushort.MaxValue && m_Tasks[j].ParentIndex > m_SubtreeNodesReference[i].NodeIndex + nodeOffset) { + m_Tasks[j].ParentIndex -= (ushort)(nodeCount - 1); + } + if (m_Tasks[j].SiblingIndex != ushort.MaxValue && m_Tasks[j].SiblingIndex > m_SubtreeNodesReference[i].NodeIndex + nodeOffset) { + m_Tasks[j].SiblingIndex -= (ushort)(nodeCount - 1); + } + +#if UNITY_EDITOR + m_LogicNodeProperties[j] = m_LogicNodeProperties[j + nodeCount - 1]; +#endif + } + + // Restore the original sibling index value for parent nodes. + parentIndex = m_Tasks[m_SubtreeNodesReference[i].NodeIndex + nodeOffset].ParentIndex; + while (parentIndex != ushort.MaxValue) { + var parentTask = m_Tasks[parentIndex]; + if (parentTask.SiblingIndex != ushort.MaxValue) { + parentTask.SiblingIndex -= (ushort)(nodeCount - 1); + m_Tasks[parentIndex] = parentTask; + } + parentIndex = parentTask.ParentIndex; + } + + // Restore the original ConnectedIndex value. + if (m_EventTasks != null) { + for (int j = 0; j < m_EventTasks.Length; ++j) { + if (m_EventTasks[j].ConnectedIndex > m_SubtreeNodesReference[i].NodeIndex) { + m_EventTasks[j].ConnectedIndex -= (ushort)(nodeCount - 1); + } + } + } + Array.Resize(ref m_Tasks, m_Tasks.Length - nodeCount + 1); +#if UNITY_EDITOR + Array.Resize(ref m_LogicNodeProperties, m_LogicNodeProperties.Length - nodeCount + 1); +#endif + + // Replace the old nodes with the new nodes. + subtreeNodesReference.Nodes = reevaluatedNodes; + m_SubtreeNodesReference[i] = subtreeNodesReference; + + // The disabled nodes also need to be removed. + var subtrees = m_SubtreeNodesReference[i].Subtrees; + var disabledNodesCount = 0; + for (int j = 0; j < subtrees.Length; ++j) { + if (subtrees[j].DisabledLogicNodes == null || subtrees[j].DisabledLogicNodes.Length == 0) { + continue; + } + disabledNodesCount += subtrees[j].DisabledLogicNodes.Length; + } + if (disabledNodesCount > 0) { + if (m_DisabledLogicNodes.Length > disabledNodesCount) { // The local tree may not have any disabled nodes. + for (int j = 0; j < m_DisabledLogicNodes.Length - disabledNodesCount; ++j) { + if (m_DisabledLogicNodes[j] >= m_SubtreeNodesReference[i].NodeIndex + nodeOffset + 1) { + m_DisabledLogicNodes[j] = (ushort)(m_DisabledLogicNodes[j + disabledNodesCount] - nodeCount + 1); + } + } + } + Array.Resize(ref m_DisabledLogicNodes, m_DisabledLogicNodes.Length - disabledNodesCount); + } + } + + // The tasks array has been restored to the original set of nodes with the ISubtreeReference. Inject the new nodes. + InjectSubtrees(); + + // Modify the ConnectedIndex to match the injection. + if (m_EventTasks != null && m_SubtreeNodesReference != null) { + for (int i = 0; i < m_EventTasks.Length; ++i) { + var offset = 0; + for (int j = 0; j < m_SubtreeNodesReference.Count; ++j) { + if (m_SubtreeNodesReference[j].NodeIndex >= m_EventTasks[i].ConnectedIndex) { + break; + } + offset += m_SubtreeNodesReference[j].NodeCount - 1; + } + if (offset != 0) { + m_EventTasks[i].ConnectedIndex += (ushort)offset; + } + } + } + + return true; + } + + /// + /// Returns the SharedVariable with the specified name. + /// + /// The graph that the data belongs to. + /// The name of the SharedVariable that should be retrieved. + /// The scope of the SharedVariable that should be retrieved. + /// The SharedVariable with the specified name (can be null). + public SharedVariable GetVariable(IGraph graph, PropertyName name, SharedVariable.SharingScope scope) + { + if (m_VariableByNameMap == null) { + DeserializeSharedVariables(graph, false, true, null); + } + + if (m_VariableByNameMap != null && m_VariableByNameMap.TryGetValue(new VariableAssignment(name, scope), out var variable)) { + return variable; + } + + return null; + } + + /// + /// Returns the SharedVariable of the specified type. + /// + /// The graph that the data belongs to. + /// The name of the SharedVariable that should be retrieved. + /// The scope of the SharedVariable that should be retrieved. + /// The SharedVariable with the specified name (can be null). + public SharedVariable GetVariable(IGraph graph, PropertyName name, SharedVariable.SharingScope scope) + { + return GetVariable(graph, name, scope) as SharedVariable; + } + + /// + /// Sets the value of the SharedVariable. + /// + /// The type of SharedVarible. + /// The graph that the data belongs to. + /// The name of the SharedVariable. + /// The value of the SharedVariable. + /// The scope of the SharedVariable that should be set. + /// True if the value was set. + public bool SetVariableValue(IGraph graph, PropertyName name, T value, SharedVariable.SharingScope scope) + { + if (m_VariableByNameMap == null) { + DeserializeSharedVariables(graph, false, true, null); + } + + if (m_VariableByNameMap == null || !m_VariableByNameMap.TryGetValue(new VariableAssignment(name, scope), out var variable)) { + return false; + } + + (variable as SharedVariable).Value = value; + return true; + } + + /// + /// Overrides the SharedVariable binding. The name must match an exsting variable. + /// + /// The graph that the data belongs to. + /// The reference to the SharedVariable. + internal void OverrideVariableBinding(IGraph graph, SharedVariable variable) + { + if (string.IsNullOrEmpty(variable.Name)) { + return; + } + + DeserializeSharedVariables(graph, false, true, null); + var dirty = false; + if (m_SharedVariables != null) { + for (int i = 0; i < m_SharedVariables.Length; ++i) { + if (m_SharedVariables[i].Name == variable.Name) { + var variableType = variable.GetType(); + if (variableType.IsGenericType && variableType.GetGenericTypeDefinition().IsAssignableFrom(typeof(SharedVariableBinding<>))) { + m_SharedVariables[i] = variable.Clone() as SharedVariable; + dirty = true; + } + break; + } + } + } + + if (dirty) { + m_VariableByNameMap = PopulateSharedVariablesMapping(graph, true); + } + } + + /// + /// Replaces the data with the specified BehaviorTreeData. + /// + /// The graph that the current data belongs to. + /// The data that should be replaced. + /// The SharedVariables of the current graph. + internal void OverrideData(IGraph graph, BehaviorTreeData other, SharedVariable[] originalSharedVariables, bool updateFields) + { + EventNodes = other.EventNodes; + LogicNodes = other.LogicNodes; + SubtreeNodesReferences = other.SubtreeNodesReferences; + m_SharedVariables = other.SharedVariables; + m_SharedVariableData = other.m_SharedVariableData; + m_VariableByNameMap = PopulateSharedVariablesMapping(graph, false); + m_DisabledLogicNodes = other.DisabledLogicNodes; + m_DisabledEventNodes = other.DisabledEventNodes; + // The other tree may be pooled. Update the variable references to point to the local graph variables. + if (updateFields && other.m_VariableFields != null) { + for (int i = 0; i < other.m_VariableFields.Count; ++i) { + var variableField = other.m_VariableFields[i]; + var localVariable = GetVariable(graph, variableField.Name, SharedVariable.SharingScope.Graph); + if (localVariable != null) { + variableField.Field.SetValue(variableField.Task, localVariable); + } + } + } + // The original tree variable value should override the other variable value. + if (originalSharedVariables != null) { + for (int i = 0; i < originalSharedVariables.Length; ++i) { + OverrideVariableValue(graph, originalSharedVariables[i]); + } + } +#if UNITY_EDITOR + m_EventNodeProperties = other.EventNodeProperties; + m_LogicNodeProperties = other.LogicNodeProperties; + m_SharedVariableGroups = other.SharedVariableGroups; + m_SharedVariableGroupsData = other.m_SharedVariableGroupsData; + m_GroupProperties = other.GroupProperties; +#endif + } + + /// + /// Overrides the SharedVariable value. The name must match an exsting variable. + /// + /// The graph that the data belongs to. + /// The reference to the SharedVariable. + /// True if the value was overridden. + private bool OverrideVariableValue(IGraph graph, SharedVariable variable) + { + if (string.IsNullOrEmpty(variable.Name)) { + return false; + } + + var dirty = false; + if (m_SharedVariables != null) { + for (int i = 0; i < m_SharedVariables.Length; ++i) { + if (m_SharedVariables[i].Name == variable.Name) { + var variableType = variable.GetType(); + if (m_SharedVariables[i].GetType() == variableType) { + m_SharedVariables[i].SetValue(variable.GetValue()); + dirty = true; + } + break; + } + } + } + + return dirty; + } + + /// + /// Is the node with the specified index enabled? + /// + /// Is the node a LogicNode? + /// The index of the node. + /// True if the node with the specified index is enabled. + public bool IsNodeEnabled(bool logicNode, int index) + { + if (index == ushort.MaxValue) { + return true; + } + + var disabledNodes = logicNode ? m_DisabledLogicNodes : m_DisabledEventNodes; + if (disabledNodes == null) { + return true; + } + for (int i = 0; i < disabledNodes.Length; ++i) { + if (disabledNodes[i] == index) { + return false; + } + } + return true; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/BehaviorTreeData.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/BehaviorTreeData.cs.meta new file mode 100644 index 0000000..eb15828 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/BehaviorTreeData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b88607c73749e1f47b8bb1ed0b34a7a8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/BehaviorTreeDataStructures.cs b/Packages/com.opsive.behaviordesigner/Runtime/BehaviorTreeDataStructures.cs new file mode 100644 index 0000000..f2d76ff --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/BehaviorTreeDataStructures.cs @@ -0,0 +1,117 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime +{ + using Opsive.BehaviorDesigner.Runtime.Tasks; + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using Opsive.Shared.Utility; + using System.Collections.Generic; + using System.Reflection; + using UnityEngine; + + /// + /// Storage class for the graph data. + /// + public partial class BehaviorTreeData + { + /// + /// Data structure which contains the properties for a subtree that will be injected. + /// + private struct SubtreeAssignment + { + [Tooltip("The index of the SubtreeNodesReference element.")] + public int ReferenceIndex; + [Tooltip("The index of the ISubtreeReference task.")] + public ushort NodeIndex; + [Tooltip("The index of the Subtree.")] + public int SubtreeIndex; + [Tooltip("The subtree that the task references.")] + public Subtree Subtree; + [Tooltip("The offset of the index. This will change as subtrees are added.")] + public ushort IndexOffset; + [Tooltip("The original parent index of the ISubtreeReference task.")] + public ushort ParentIndex; + [Tooltip("The original sibling index of the ISubtreeReference task.")] + public ushort SiblingIndex; + [Tooltip("The number of nodes that are a child of the ISubtreeReference.")] + public ushort NodeCount; +#if UNITY_EDITOR + [Tooltip("The position of the ISubtreeReference task.")] + public Vector2 NodePropertiesPosition; + [Tooltip("Is the ISubtreeReference task collapsed?")] + public bool Collapsed; +#endif + } + + /// + /// Contains a reference to the subtree index and nodes. + /// + internal struct SubtreeNodesReference + { + [Tooltip("The ISubtreeReference.")] + public ISubtreeReference SubtreeReference; + [Tooltip("The index of the ISubtreeReference.")] + public ushort NodeIndex; + [Tooltip("The total number of nodes contained within the ISubtreeReference.")] + public ushort NodeCount; + [Tooltip("A reference to the subtrees that are loaded.")] + public Subtree[] Subtrees; + [Tooltip("The deserialized nodes.")] + public ITreeLogicNode[][] Nodes; + } + + /// + /// Keeps a reference to the graph variables allowing them to be overwritten if a subtree is set. + /// + private struct VariableField + { + [Tooltip("The field that the SharedVariable is assigned to.")] + public FieldInfo Field; + [Tooltip("The task that the SharedVariable is assigned to.")] + public object Task; + [Tooltip("The name of the SharedVariable.")] + public string Name; + } + + /// + /// Internal data structure for referencing a SharedVariable to its name/scope. + /// + public struct VariableAssignment + { + [Tooltip("The name of the SharedVariable.")] + public PropertyName Name; + [Tooltip("The scope of the SharedVariable.")] + public SharedVariable.SharingScope Scope; + + /// + /// VariableAssignment constructor. + /// + /// The name of the SharedVariable. + /// The scope of the SharedVariable. + public VariableAssignment(PropertyName name, SharedVariable.SharingScope scope) + { + Name = name; + Scope = scope; + } + } + + /// + /// Internal data structure for restoring a task reference after it has been deserialized. + /// + public struct TaskAssignment + { + [Tooltip("The field of the task.")] + public FieldInfo Field; + [Tooltip("The task that the field belongs to.")] + public object Target; + [Tooltip("The value of the field. This will be the task object that should be assigned after the tree has been loaded.")] + public object Value; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/BehaviorTreeDataStructures.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/BehaviorTreeDataStructures.cs.meta new file mode 100644 index 0000000..7aa7fe3 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/BehaviorTreeDataStructures.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0ca426c026a6a06469dc2d4a512ef855 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Components.meta b/Packages/com.opsive.behaviordesigner/Runtime/Components.meta new file mode 100644 index 0000000..87788c5 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Components.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3f13872ff04404c4da862a21fe89cac6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Components/BakedBehaviorTree.cs b/Packages/com.opsive.behaviordesigner/Runtime/Components/BakedBehaviorTree.cs new file mode 100644 index 0000000..ca4d22a --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Components/BakedBehaviorTree.cs @@ -0,0 +1,120 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Components +{ + using Opsive.BehaviorDesigner.Runtime.Groups; + using Opsive.BehaviorDesigner.Runtime.Systems; + using Unity.Entities; + using UnityEngine; + + /// + /// Indicates that the behavior tree was baked. + /// + public class BakedBehaviorTree : IComponentData + { + [Tooltip("The index of the connected start task.")] + public int StartEventConnectedIndex; + [Tooltip("Should the behavior tree be started after it has been baked?")] + public bool StartEvaluation; + [Tooltip("The indicies of the reevaluate task systems.")] + public string[] ReevaluateTaskSystems; + [Tooltip("The indicies of the interrupt task systems.")] + public string[] InterruptTaskSystems; + [Tooltip("The indicies of the traversal task systems.")] + public string[] TraversalTaskSystems; + [Tooltip("The hashes that correspond to the TaskComponent's ComponentType.")] + public ulong[] TagStableTypeHashes; + [Tooltip("The hashes that correspond to the ReevaluateTaskComponent's ComponentType.")] + public ulong[] ReevaluateFlagStableTypeHashes; + } + + /// + /// The behavior tree has been baked. Start the tree using the baked data. + /// + public partial struct StartBakedBehaviorTreeSystem : ISystem + { + /// + /// Restricts when the system should run. + /// + /// The current SystemState. + private void OnCreate(ref SystemState state) + { + state.RequireForUpdate(); + state.Enabled = false; + } + + /// + /// Starts the baked behavior tree. + /// + /// The current SystemState. + private void OnUpdate(ref SystemState state) + { + state.Enabled = false; + + // The components are baked, but systems are not baked. Create the required systems within the current world. + var reevaluateTaskSystemGroup = state.World.GetOrCreateSystemManaged(); + var interruptTaskSystemGroup = state.World.GetOrCreateSystemManaged(); + var traversalTaskSystemGroup = state.World.GetOrCreateSystemManaged(); + + // Add the necessary cleanup systems. + var behaviorTreeSystemGroup = state.World.GetOrCreateSystemManaged(); + behaviorTreeSystemGroup.AddSystemToUpdateList(state.World.GetOrCreateSystem()); + behaviorTreeSystemGroup.AddSystemToUpdateList(state.World.GetOrCreateSystem()); + + var canReevaluate = false; + var ecb = new EntityCommandBuffer(state.WorldUpdateAllocator); + foreach (var (bakedBehaviorTree, entity) in SystemAPI.Query().WithEntityAccess()) { + AddSystems(state.World, reevaluateTaskSystemGroup, bakedBehaviorTree.ReevaluateTaskSystems); + AddSystems(state.World, interruptTaskSystemGroup, bakedBehaviorTree.InterruptTaskSystems); + AddSystems(state.World, traversalTaskSystemGroup, bakedBehaviorTree.TraversalTaskSystems); + + // ComponentTypes cannot be serialized. Convert the StableTypeHash to a ComponentType. + var taskComponents = state.World.EntityManager.GetBuffer(entity); + for (int i = 0; i < taskComponents.Length; ++i) { + var taskComponent = taskComponents[i]; + taskComponent.FlagComponentType = ComponentType.FromTypeIndex(TypeManager.GetTypeIndexFromStableTypeHash(bakedBehaviorTree.TagStableTypeHashes[i])); + taskComponents[i] = taskComponent; + } + + if (state.World.EntityManager.HasBuffer(entity)) { + var reevaluateComponents = state.World.EntityManager.GetBuffer(entity); + canReevaluate = true; + for (int i = 0; i < reevaluateComponents.Length; ++i) { + var reevaluateComponent = reevaluateComponents[i]; + reevaluateComponent.ReevaluateFlagComponentType = ComponentType.FromTypeIndex(TypeManager.GetTypeIndexFromStableTypeHash(bakedBehaviorTree.ReevaluateFlagStableTypeHashes[i])); + reevaluateComponents[i] = reevaluateComponent; + } + } + + // All of the systems have been added. Start the behavior tree. + BehaviorTree.StartBranch(state.World, entity, (ushort)bakedBehaviorTree.StartEventConnectedIndex, bakedBehaviorTree.StartEvaluation); + ecb.RemoveComponent(entity); + } + if (canReevaluate) { + reevaluateTaskSystemGroup.AddSystemToUpdateList(state.World.GetOrCreateSystem()); + } + ecb.Playback(state.EntityManager); + ecb.Dispose(); + } + + /// + /// Adds the systems indicated by the SystemTypeIndex to the specified group. + /// + /// The current World. + /// The group that the systems should be added to. + /// The types of systems that should be added. + private void AddSystems(World world, ComponentSystemGroup group, string[] systemTypes) + { + if (systemTypes == null) { return; } + + for (int i = 0; i < systemTypes.Length; ++i) { + group.AddSystemToUpdateList(world.GetOrCreateSystem(Shared.Utility.TypeUtility.GetType(systemTypes[i]))); + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Components/BakedBehaviorTree.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Components/BakedBehaviorTree.cs.meta new file mode 100644 index 0000000..04a6b14 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Components/BakedBehaviorTree.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f68d4eca856988e4a8f4073516e7de57 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Components/BehaviorTreeComponents.cs b/Packages/com.opsive.behaviordesigner/Runtime/Components/BehaviorTreeComponents.cs new file mode 100644 index 0000000..7b5be0c --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Components/BehaviorTreeComponents.cs @@ -0,0 +1,261 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Components +{ + using Opsive.BehaviorDesigner.Runtime.Tasks; + using System.Runtime.InteropServices; + using Unity.Collections; + using Unity.Entities; + using UnityEngine; + + /// + /// The runtime DOTS data associated with a task. + /// + [System.Serializable] + public struct TaskComponent : IBufferElementData + { + [Tooltip("The index of the task within the behavior tree.")] + public ushort Index; + [Tooltip("The index of the parent task within the behavior tree.")] + public ushort ParentIndex; + //public ushort m_ParentIndex; + //public ushort ParentIndex { get { return m_ParentIndex; } set { UnityEngine.Debug.Log(Index + " parent: " + value); m_ParentIndex = value; } } + [Tooltip("The index of the sibling task within the behavior tree.")] + public ushort SiblingIndex; + //public ushort m_SiblingIndex; + //public ushort SiblingIndex { get { return m_SiblingIndex; } set { UnityEngine.Debug.Log(Index + " sibling: " + value); m_SiblingIndex = value; } } + [Tooltip("The index of the branch the task executes within.")] + public ushort BranchIndex; + //public ushort m_BranchIndex; + //public ushort BranchIndex { get { return m_BranchIndex; } set { UnityEngine.Debug.Log(Index + " branch: " + value); m_BranchIndex = value; } } + [Tooltip("The component type responsible for indicating that the task is active.")] + public ComponentType FlagComponentType; + [Tooltip("Is the task disabled?")] + [MarshalAs(UnmanagedType.U1)] + public bool Disabled; + [Tooltip("The current execution status of the task.")] + //public TaskStatus Status; + [SerializeField] private TaskStatus m_Status; + public TaskStatus Status { + get => m_Status; + set { + m_Status = value; + CanReevaluate = value != TaskStatus.Inactive; + //UnityEngine.Debug.Log(string.Format("{0} status: {1}", Index, value)); + } + } + [Tooltip("Can the task be reevaluated with conditional aborts?")] + [MarshalAs(UnmanagedType.U1)] + public bool CanReevaluate; + [Tooltip("Is the task being reevaluated with conditional aborts?")] + [MarshalAs(UnmanagedType.U1)] + public bool Reevaluate; + //public bool m_Reevaluate; + //public bool Reevaluate { get { return m_Reevaluate; } set { UnityEngine.Debug.Log(Index + " reevaluate: " + value + " " + GetHashCode()); m_Reevaluate = value; } } + } + + /// + /// Specifies when the behavior tree should be updated. + /// + public enum UpdateMode + { + EveryFrame, // The behavior tree should be updated every frame. + Manual // The behavior tree should be updated manually via a user script. + } + + /// + /// Specifies how many tasks should be evaluated. Evaluation will end if all branches return a status of TaskStatus.Running. + /// + public enum EvaluationType : byte + { + EntireTree, // Evaluates up to all of the tasks within the tree. + Count // Evaluates up to the specified MaxEvaluationCount. + } + + /// + /// Specifies if the tree should be evaluated. + /// + public struct EvaluationComponent32 : IComponentData + { + [Tooltip("Specifies how many tasks should be updated during a single tick.")] + public EvaluationType EvaluationType; + [Tooltip("The maximum number of tasks that can run if the evaluation type is set to EvaluationType.Count.")] + public ushort MaxEvaluationCount; + [Tooltip("A bitmask of the tasks that have been evaluated. For EvaluationType.Count, the last element stores the execution count.")] + public FixedList32Bytes EvaluatedTasks; + } + + /// + /// Specifies if the tree should be evaluated. + /// + public struct EvaluationComponent64 : IComponentData + { + [Tooltip("Specifies how many tasks should be updated during a single tick.")] + public EvaluationType EvaluationType; + [Tooltip("The maximum number of tasks that can run if the evaluation type is set to EvaluationType.Count.")] + public ushort MaxEvaluationCount; + [Tooltip("A bitmask of the tasks that have been evaluated. For EvaluationType.Count, the last element stores the execution count.")] + public FixedList64Bytes EvaluatedTasks; + } + + /// + /// Specifies if the tree should be evaluated. + /// + public struct EvaluationComponent128 : IComponentData + { + [Tooltip("Specifies how many tasks should be updated during a single tick.")] + public EvaluationType EvaluationType; + [Tooltip("The maximum number of tasks that can run if the evaluation type is set to EvaluationType.Count.")] + public ushort MaxEvaluationCount; + [Tooltip("A bitmask of the tasks that have been evaluated. For EvaluationType.Count, the last element stores the execution count.")] + public FixedList128Bytes EvaluatedTasks; + } + + /// + /// Specifies if the tree should be evaluated. + /// + public struct EvaluationComponent512 : IComponentData + { + [Tooltip("Specifies how many tasks should be updated during a single tick.")] + public EvaluationType EvaluationType; + [Tooltip("The maximum number of tasks that can run if the evaluation type is set to EvaluationType.Count.")] + public ushort MaxEvaluationCount; + [Tooltip("A bitmask of the tasks that have been evaluated. For EvaluationType.Count, the last element stores the execution count.")] + public FixedList512Bytes EvaluatedTasks; + } + + /// + /// Specifies if the tree should be evaluated. + /// + public struct EvaluationComponent4096 : IComponentData + { + [Tooltip("Specifies how many tasks should be updated during a single tick.")] + public EvaluationType EvaluationType; + [Tooltip("The maximum number of tasks that can run if the evaluation type is set to EvaluationType.Count.")] + public ushort MaxEvaluationCount; + [Tooltip("A bitmask of the tasks that have been evaluated. For EvaluationType.Count, the last element stores the execution count.")] + public FixedList4096Bytes EvaluatedTasks; + } + + /// + /// Specifies how the branch was interrupted. + /// + public enum InterruptType : byte + { + None, // No interrupt. + Branch, // A conditional abort or utility selector triggered the interruption. + ImmediateSuccess, // The branch was interrupted with a success status. + ImmediateFailure, // The branch was interrupted with a failure status. + } + + /// + /// The runtime DOTS data associated with a branch. + /// + public struct BranchComponent : IBufferElementData + { + [Tooltip("The index of the task that is currently active.")] + public ushort ActiveIndex; + //public ushort m_ActiveIndex; + //public ushort ActiveIndex { get { return m_ActiveIndex; } set { Debug.Log(string.Format("Active: {0}", value)); m_ActiveIndex = value; } } + [Tooltip("The index of the task that should execute next.")] + public ushort NextIndex; + //public ushort m_NextIndex; + //public ushort NextIndex { get { return m_NextIndex; } set { Debug.Log(string.Format("Next: {0}", value)); m_NextIndex = value; } } + [Tooltip("The index of the last active task.")] + public ushort LastActiveIndex; + [Tooltip("The component tag that is active.")] + public ComponentType ActiveFlagComponentType; + //public ComponentType m_ActiveFlagComponentType; + //public ComponentType ActiveFlagComponentType { get { return m_ActiveFlagComponentType; } set { Debug.Log(string.Format("Tag: {0}", value)); m_ActiveFlagComponentType = value; } } + [Tooltip("Specifies how the branch is interrupted.")] + public InterruptType InterruptType; + //public InterruptType m_InterruptType; + //public InterruptType InterruptType { get { return m_InterruptType; } set { m_InterruptType = value; Debug.Log("Interrupt Type " + value); } } + [Tooltip("The index of the task that caused an interruption. A value of 0 indicates no interruption.")] + public ushort InterruptIndex; + [Tooltip("Specifies if the branch can execute tasks. Set to false when all tasks in the branch have executed this tick.")] + public bool CanExecute; + //public bool m_CanExecute; + //public bool CanExecute { get { return m_CanExecute; } set { m_CanExecute = value; Debug.Log("Can Execute " + value); } } + } + + /// + /// Specifies if the tree can be evaluated. + /// + public struct EvaluateFlag : IComponentData, IEnableableComponent { } + + /// + /// Specifies if the tree is enabled. + /// + public struct EnabledFlag : IComponentData, IEnableableComponent { } + + /// + /// Flag used to indicate when the branch should be interrupted. + /// + public struct InterruptFlag : IComponentData, IEnableableComponent { } + + /// + /// Flag used to indicate that the branch has been interrupted. + /// + public struct InterruptedFlag : IComponentData, IEnableableComponent { } + + /// + /// Specifies the reevaluation status of the task. + /// + public enum ReevaluateStatus : byte + { + Inactive, // The task is not being reevaluated. + Active, // The task is currently being reevaluated. + Dirty // The task was reevaluated and triggered a change. + } + + /// + /// The runtime DOTS data associated with conditional aborts. + /// + public struct ReevaluateTaskComponent : IBufferElementData + { + [Tooltip("The index of the task.")] + public ushort Index; + [Tooltip("The type of conditional abort.")] + public ConditionalAbortType AbortType; + [Tooltip("The lower bound index of the next task if a lower priority abort is specified.")] + public ushort LowerPriorityLowerIndex; + [Tooltip("The upper bound index of the next task if a lower priority abort is specified.")] + public ushort LowerPriorityUpperIndex; + [Tooltip("The upper bound index of the next task if a self priority abort is specified.")] + public ushort SelfPriorityUpperIndex; + [Tooltip("The original status of the task.")] + public TaskStatus OriginalStatus; + [Tooltip("The tag specifiying the task should be reevaluated.")] + public ComponentType ReevaluateFlagComponentType; + [Tooltip("The current reevaluation status of the task.")] + public ReevaluateStatus ReevaluateStatus; + } + + /// + /// Runtime representation of IEventNodes that can run its own entity logic. + /// + public interface IEventNodeEntityReceiver + { + /// + /// Adds the IBufferElementData to the entity. + /// + /// The world that the entity exists in. + /// The entity that the IBufferElementData should be assigned to. + /// The GameObject that the entity is attached to. + /// The offset between the connected index and the runtime index. + void AddBufferElement(World world, Entity entity, GameObject gameObject, ushort taskOffset); + + /// + /// Clears the IBufferElementData from the entity. + /// + /// The world that the entity exists in. + /// The entity that the IBufferElementData should be cleared from. + void ClearBufferElement(World world, Entity entity); + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Components/BehaviorTreeComponents.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Components/BehaviorTreeComponents.cs.meta new file mode 100644 index 0000000..3ec4234 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Components/BehaviorTreeComponents.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 12b6df69a20daeb4ab4ce1ccaa7bc7ec +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Groups.meta b/Packages/com.opsive.behaviordesigner/Runtime/Groups.meta new file mode 100644 index 0000000..e0e6591 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Groups.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d9c918e9af659ea4fb420fd6af1433b7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Groups/BeforeTraversalSystemGroup.cs b/Packages/com.opsive.behaviordesigner/Runtime/Groups/BeforeTraversalSystemGroup.cs new file mode 100644 index 0000000..b1d926d --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Groups/BeforeTraversalSystemGroup.cs @@ -0,0 +1,46 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Groups +{ + using Opsive.BehaviorDesigner.Runtime.Systems; + using Unity.Entities; + + /// + /// Grouping for the systems that should before other systems. + /// + [UpdateInGroup(typeof(BehaviorTreeSystemGroup), OrderFirst = true)] + public partial class BeforeTraversalSystemGroup : ComponentSystemGroup + { + } + + /// + /// Grouping for the task systems that should reevaluate. + /// + [UpdateInGroup(typeof(BeforeTraversalSystemGroup))] + public partial class ReevaluateTaskSystemGroup : ComponentSystemGroup + { + } + + /// + /// Grouping for the systems that run before the tree execution. + /// + [UpdateInGroup(typeof(BehaviorTreeSystemGroup))] + public partial class InterruptSystemGroup : ComponentSystemGroup + { + } + + /// + /// Grouping for the task systems that can cause interrupts. + /// + [UpdateInGroup(typeof(InterruptSystemGroup))] + [UpdateAfter(typeof(InterruptSystem))] + [UpdateBefore(typeof(InterruptCleanupSystem))] + public partial class InterruptTaskSystemGroup : ComponentSystemGroup + { + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Groups/BeforeTraversalSystemGroup.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Groups/BeforeTraversalSystemGroup.cs.meta new file mode 100644 index 0000000..075d5be --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Groups/BeforeTraversalSystemGroup.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 83e6fa82f6125e140a3d0bd4737feeb3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Groups/BehaviorTreeSystemGroup.cs b/Packages/com.opsive.behaviordesigner/Runtime/Groups/BehaviorTreeSystemGroup.cs new file mode 100644 index 0000000..51b8ed8 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Groups/BehaviorTreeSystemGroup.cs @@ -0,0 +1,80 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Groups +{ + using Opsive.BehaviorDesigner.Runtime.Systems; + using Unity.Entities; + using UnityEngine; + + /// + /// System group which runs all of the behavior tree systems. + /// + [UpdateInGroup(typeof(SimulationSystemGroup))] + [UpdateAfter(typeof(BeginSimulationEntityCommandBufferSystem))] + public partial class BehaviorTreeSystemGroup : ComponentSystemGroup + { + private bool m_Alive; + + public bool Alive { get => m_Alive; } + + /// + /// Disable the group if there are no behavior trees. + /// + [RuntimeInitializeOnLoadMethod] + private static void Init() + { + if (BehaviorTree.BehaviorTreeCount > 0) { + return; + } + + var worlds = World.All; + for (int i = 0; i < worlds.Count; ++i) { + var systemGroup = worlds[i].GetExistingSystemManaged(); + if (systemGroup == null) { + continue; + } + systemGroup.Enabled = false; + } + } + + /// + /// The group has been created. + /// + protected override void OnCreate() + { + base.OnCreate(); + + m_Alive = true; + } + + /// + /// Update the system group. + /// + protected override void OnUpdate() + { + base.OnUpdate(); + + // Stop running if all trees have completed. + var systemHandle = World.GetExistingSystem(); + var system = EntityManager.WorldUnmanaged.GetUnsafeSystemRef(systemHandle); + if (!system.Active) { + Enabled = false; + } + } + + /// + /// The group has been destroyed. + /// + protected override void OnDestroy() + { + base.OnDestroy(); + + m_Alive = false; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Groups/BehaviorTreeSystemGroup.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Groups/BehaviorTreeSystemGroup.cs.meta new file mode 100644 index 0000000..182c14b --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Groups/BehaviorTreeSystemGroup.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 905219e69953a5e479911f095744ec54 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Groups/TaskSystemGroup.cs b/Packages/com.opsive.behaviordesigner/Runtime/Groups/TaskSystemGroup.cs new file mode 100644 index 0000000..5c0567a --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Groups/TaskSystemGroup.cs @@ -0,0 +1,41 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Groups +{ + using System; + using Unity.Entities; + using UnityEngine; + + /// + /// Group that executes all of the tasks. + /// + [UpdateInGroup(typeof(TraversalSystemGroup))] + public partial class TraversalTaskSystemGroup : ComponentSystemGroup + { + [Tooltip("Callback before the outher tasks are updated.")] + public Action OnPreUpdate; + [Tooltip("Callback after the outher tasks are updated.")] + public Action OnPostUpdate; + + /// + /// Updates the group. + /// + protected override void OnUpdate() + { + if (OnPreUpdate != null) { + OnPreUpdate(); + } + + base.OnUpdate(); + + if (OnPostUpdate != null) { + OnPostUpdate(); + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Groups/TaskSystemGroup.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Groups/TaskSystemGroup.cs.meta new file mode 100644 index 0000000..bbe78a1 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Groups/TaskSystemGroup.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f48a72a09e70b944a82639a4d549f090 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Groups/TraversalSystemGroup.cs b/Packages/com.opsive.behaviordesigner/Runtime/Groups/TraversalSystemGroup.cs new file mode 100644 index 0000000..5985cba --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Groups/TraversalSystemGroup.cs @@ -0,0 +1,76 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Groups +{ + using Opsive.BehaviorDesigner.Runtime.Systems; + using Unity.Entities; + + /// + /// Main group for the systems that are responsible for traversing the behavior tree. + /// + [UpdateInGroup(typeof(BehaviorTreeSystemGroup))] + [UpdateAfter(typeof(InterruptSystemGroup))] + public partial class TraversalSystemGroup : ComponentSystemGroup + { + private SystemHandle m_EvaluationSystemHandle; + private SystemHandle m_DetermineEvaluationSystemHandle; + + /// + /// The group has been created. + /// + protected override void OnCreate() + { + base.OnCreate(); + + m_EvaluationSystemHandle = World.GetExistingSystem(); + m_DetermineEvaluationSystemHandle = World.GetExistingSystem(); + } + + /// + /// Updates the systems. Determines if the systems need to keep being evaluated. + /// + protected override void OnUpdate() + { +#if UNITY_EDITOR + var count = 0; +#endif + bool evaluate; + do { + base.OnUpdate(); + + var determineEvaluationSystem = EntityManager.WorldUnmanaged.GetUnsafeSystemRef(m_DetermineEvaluationSystemHandle); + determineEvaluationSystem.Complete(EntityManager); + evaluate = determineEvaluationSystem.Evaluate; + + var evaluationSystem = EntityManager.WorldUnmanaged.GetUnsafeSystemRef(m_EvaluationSystemHandle); + evaluationSystem.Complete(EntityManager); + +#if UNITY_EDITOR + if (evaluate) { + count++; + if (count == ushort.MaxValue / 10) { + UnityEngine.Debug.LogWarning("An infinite loop would have been caused by the TraversalSystemGroup. Please email support@opsive.com with steps to reproduce this error."); + break; + } + } +#endif + } while (evaluate); + } + + /// + /// The group has stopped running. + /// + protected override void OnStopRunning() + { + base.OnStopRunning(); + + var evaluationSystem = EntityManager.WorldUnmanaged.GetUnsafeSystemRef(m_EvaluationSystemHandle); + evaluationSystem.Complete(EntityManager, true); + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Groups/TraversalSystemGroup.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Groups/TraversalSystemGroup.cs.meta new file mode 100644 index 0000000..c94ab49 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Groups/TraversalSystemGroup.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2c1ad397e3cdf7a44ae172b5ae92c2e4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Opsive.BehaviorDesigner.Runtime.asmdef b/Packages/com.opsive.behaviordesigner/Runtime/Opsive.BehaviorDesigner.Runtime.asmdef new file mode 100644 index 0000000..3427a47 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Opsive.BehaviorDesigner.Runtime.asmdef @@ -0,0 +1,29 @@ +{ + "name": "Opsive.BehaviorDesigner.Runtime", + "rootNamespace": "Opsive.BehaviorDesigner.Runtime", + "references": [ + "GUID:e9319bc8ab9315745bdf80aeffa01d6d", + "GUID:d8e89a79cd8df884b8d5b3356783eb74", + "GUID:734d92eba21c94caba915361bd5ac177", + "GUID:2665a8d13d1b3f18800f46e256720795", + "GUID:e0cd26848372d4e5c891c569017e11f1", + "GUID:d8b63aba1907145bea998dd612889d6b", + "GUID:a5baed0c9693541a5bd947d336ec7659", + "GUID:8819f35a0fc84499b990e90a4ca1911f" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [ + { + "name": "com.unity.entities", + "expression": "1.3.5", + "define": "UNITY_ENTITIES" + } + ], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Opsive.BehaviorDesigner.Runtime.asmdef.meta b/Packages/com.opsive.behaviordesigner/Runtime/Opsive.BehaviorDesigner.Runtime.asmdef.meta new file mode 100644 index 0000000..14d256c --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Opsive.BehaviorDesigner.Runtime.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f9fbcd65fc33f6847b0f124cf7e891b6 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Subtree.cs b/Packages/com.opsive.behaviordesigner/Runtime/Subtree.cs new file mode 100644 index 0000000..1dcc58a --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Subtree.cs @@ -0,0 +1,298 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using System; + using UnityEngine; + + /// + /// The behavior tree stored within a Scriptable Object. + /// + [CreateAssetMenu(fileName = "Subtree", menuName = "Opsive/Behavior Designer/Subtree", order = 1)] + public class Subtree : ScriptableObject, IGraph, ISharedVariableContainer + { + [Tooltip("The behavior tree data.")] + [SerializeField] private BehaviorTreeData m_Data = new BehaviorTreeData(); + + public string Name { get => name; set => name = value; } + public SharedVariable.SharingScope VariableScope { get => SharedVariable.SharingScope.Graph; } + public BehaviorTreeData Data { get => m_Data; } + public UnityEngine.Object Parent { get => this; } + public ILogicNode[] LogicNodes { get => m_Data?.LogicNodes; set => m_Data.LogicNodes = value as ITreeLogicNode[]; } + public ITreeLogicNode[] TreeLogicNodes { get => m_Data?.LogicNodes; set => m_Data.LogicNodes = value; } + public IEventNode[] EventNodes { get => m_Data?.EventNodes; set => m_Data.EventNodes = value; } + public SharedVariable[] SharedVariables { get => m_Data?.SharedVariables; set => m_Data.SharedVariables = value; } + public SharedVariableGroup[] SharedVariableGroups { +#if UNITY_EDITOR + get => Data?.SharedVariableGroups; + set => Data.SharedVariableGroups = value; +#else + get => null; + set { } +#endif + } + public ushort[] DisabledLogicNodes { get => m_Data.DisabledLogicNodes; set => m_Data.DisabledLogicNodes = value; } + public ushort[] DisabledEventNodes { get => m_Data.DisabledEventNodes; set => m_Data.DisabledEventNodes = value; } + + public LogicNodeProperties[] LogicNodeProperties + { +#if UNITY_EDITOR + get => m_Data.LogicNodeProperties; + set => m_Data.LogicNodeProperties = value; +#else + get => null; + set { } +#endif + } + public NodeProperties[] EventNodeProperties + { +#if UNITY_EDITOR + get => m_Data.EventNodeProperties; + set => m_Data.EventNodeProperties = value; +#else + get => null; + set { } +#endif + } + public GroupProperties[] GroupProperties + { +#if UNITY_EDITOR + get => m_Data.GroupProperties; + set => m_Data.GroupProperties = value; +#else + get => null; + set { } +#endif + } + + public int UniqueID { get => m_Data.UniqueID; } + public bool Pooled { get; set; } + + /// + /// Serializes the behavior tree. + /// + public void Serialize() + { + m_Data.Serialize(); + } + + /// + /// Deserialize the behavior tree. + /// + /// Should the behavior tree be force deserialized? + /// True if the tree was deserialized. + public bool Deserialize(bool force = false) + { + return Deserialize(null, force, force, false, true, null); + } + + /// + /// Deserialize the behavior tree. + /// + /// Should the behavior tree be force deserialized? + /// Should the shared variables be force deserialized? + /// Should the subtrees be injected into the behavior tree? + /// Can the SharedVariables be deep copied? + /// True if the tree was deserialized. + public bool Deserialize(bool force, bool forceSharedVariables, bool injectSubtrees, bool canDeepCopyVariables = true) + { + return Deserialize(null, force, forceSharedVariables, injectSubtrees, canDeepCopyVariables, null); + } + + /// + /// Deserialize the behavior tree. + /// + /// The component that the graph is being deserialized from. + /// Should the behavior tree be force deserialized? + /// Should the shared variables be force deserialized? + /// Should the subtrees be injected into the behavior tree? + /// Can the SharedVariables be deep copied? + /// A list of SharedVariables that should override the current SharedVariable value. + /// True if the tree was deserialized. + public bool Deserialize(IGraphComponent graphComponent, bool force, bool forceSharedVariables, bool injectSubtrees, bool canDeepCopyVariables, SharedVariableOverride[] sharedVariableOverrides) + { + if (m_Data == null) { + return false; + } + + return m_Data.Deserialize(graphComponent, this, force, forceSharedVariables, injectSubtrees, canDeepCopyVariables, sharedVariableOverrides); + } + + /// + /// Deserializes the SharedVariables. This allows the SharedVariables to be deserialized independently. + /// + /// Should the variables be forced deserialized? + /// True if the SharedVariables were deserialized. + public bool DeserializeSharedVariables(bool force) + { + if (m_Data == null) { + return false; + } + + return m_Data.DeserializeSharedVariables(this, force, false); + } + + /// + /// Adds the specified logic node. + /// + /// The node that should be added. + public void AddNode(ILogicNode node) + { + m_Data.AddNode(node as ITreeLogicNode); + } + + /// + /// Removes the specified logic node. + /// + /// The node that should be removed. + /// True if the node was removed. + public bool RemoveNode(ILogicNode node) + { + return m_Data.RemoveNode(node as ITreeLogicNode); + } + + /// + /// Adds the specified event node. + /// + /// The event node that should be added. + public void AddNode(IEventNode eventNode) + { + m_Data.AddNode(eventNode); + } + + /// + /// Removes the specified event node. + /// + /// The event node that should be removed. + /// True if the event node was removed. + public bool RemoveNode(IEventNode eventNode) + { + return m_Data.RemoveNode(eventNode); + } + + /// + /// Returns the Node of the specified type. + /// + /// The type of Node that should be retrieved. + /// The Node of the specified type (can be null). + public ILogicNode GetNode(Type type) + { + return m_Data.GetNode(type); + } + + /// + /// Returns the EventNode of the specified type. + /// + /// The type of EventNode that should be retrieved. + /// The EventNode of the specified type (can be null). If the node is found the index will also be returned. + public (IEventNode, ushort) GetEventNode(Type type) + { + return m_Data.GetEventNode(type); + } + + /// + /// Returns the SharedVariable with the specified name. + /// + /// The name of the SharedVariable that should be retrieved. + /// The SharedVariable with the specified name (can be null). + public SharedVariable GetVariable(PropertyName name) + { + Deserialize(); + + return m_Data.GetVariable(this, name, SharedVariable.SharingScope.Graph); + } + + /// + /// Returns the SharedVariable of the specified name. + /// + /// The name of the SharedVariable that should be retrieved. + /// The SharedVariable with the specified name (can be null). + public SharedVariable GetVariable(PropertyName name) + { + Deserialize(); + + return m_Data.GetVariable(this, name, SharedVariable.SharingScope.Graph); + } + + /// + /// Sets the value of the SharedVariable. + /// + /// The type of SharedVarible. + /// The name of the SharedVariable. + /// The value of the SharedVariable. + /// True if the value was set. + public bool SetVariableValue(PropertyName name, T value) + { + Deserialize(); + + return m_Data.SetVariableValue(this, name, value, SharedVariable.SharingScope.Graph); + } + + /// + /// Is the node with the specified index enabled? + /// + /// Is the node a LogicNode? + /// The index of the node. + /// True if the node with the specified index is enabled. + public bool IsNodeEnabled(bool logicNode, int index) + { + return m_Data.IsNodeEnabled(logicNode, index); + } + + /// + /// Is the node with the specified index active? + /// + /// Is the node a LogicNode? + /// The index of the node. + /// True if the node with the specified index is active. + public bool IsNodeActive(bool logicNode, int index) + { + return false; // The subtree node itself is never active. + } + + /// + /// Copies the graph onto the current graph. + /// + /// The graph that should be copied. + public void Clone(IGraph other) + { + m_Data = new BehaviorTreeData(); + m_Data.EventNodes = other.EventNodes; + m_Data.LogicNodes = other.LogicNodes as ITreeLogicNode[]; + m_Data.SharedVariables = other.SharedVariables; + +#if UNITY_EDITOR + m_Data.EventNodeProperties = other.EventNodeProperties; + m_Data.LogicNodeProperties = other.LogicNodeProperties; + m_Data.GroupProperties = other.GroupProperties; +#endif + + m_Data.Serialize(); + } + + /// + /// Overrides ToString. + /// + /// The desired string value. + public override string ToString() + { + return name; + } + } + + /// + /// Attribute indicating that a ReorderableList should be used for the Subtree array. + /// + [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)] + public class SubtreeListAttribute : System.Attribute + { + + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Subtree.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Subtree.cs.meta new file mode 100644 index 0000000..b2e463e --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Subtree.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0ab170e3869205449b993a35614c2084 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: e0a8f1df788b6274a9a24003859dfa7e, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Systems.meta b/Packages/com.opsive.behaviordesigner/Runtime/Systems.meta new file mode 100644 index 0000000..5b02575 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Systems.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a33ce2113e48ee54f946531482da6261 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Systems/BeforeTraversalSystems.cs b/Packages/com.opsive.behaviordesigner/Runtime/Systems/BeforeTraversalSystems.cs new file mode 100644 index 0000000..6638c21 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Systems/BeforeTraversalSystems.cs @@ -0,0 +1,412 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Systems +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.BehaviorDesigner.Runtime.Groups; + using Opsive.BehaviorDesigner.Runtime.Tasks; + using Opsive.BehaviorDesigner.Runtime.Utility; + using Unity.Burst; + using Unity.Collections; + using Unity.Entities; + using UnityEngine; + + /// + /// System which checks for any tasks that should be reevaluated with conditional aborts. This system only marks the tasks, it does not do + /// the actual reevaluation or interruption. + /// + [UpdateInGroup(typeof(BeforeTraversalSystemGroup), OrderFirst = true)] + [DisableAutoCreation] + public partial struct ReevaluateSystem : ISystem + { + private EntityQuery m_Query; + + /// + /// Builds the query. + /// + /// THe current SystemState. + private void OnCreate(ref SystemState state) + { + m_Query = SystemAPI.QueryBuilder().WithAllRW().WithAllRW().WithAll().WithAbsent().Build(); + } + + /// + /// Creates the ReevaluateJob. + /// + /// The current SystemState. + private void OnUpdate(ref SystemState state) + { + var ecb = new EntityCommandBuffer(Allocator.TempJob); + state.Dependency = new ReevaluateJob() + { + EntityCommandBuffer = ecb.AsParallelWriter(), + }.ScheduleParallel(m_Query, state.Dependency); + + // The job must run immediately for the next systems. + state.Dependency.Complete(); + ecb.Playback(state.EntityManager); + ecb.Dispose(); + } + + /// + /// Job which checks for any tasks that should be reevaluated with conditional aborts. This job only flags the tasks, it does not do + /// the actual reevaluation or interruption. + /// + [BurstCompile] + private partial struct ReevaluateJob : IJobEntity + { + [Tooltip("CommandBuffer which sets the component data.")] + public EntityCommandBuffer.ParallelWriter EntityCommandBuffer; + + /// + /// Executes the job. + /// + /// The entity that is being acted upon. + /// The index of the entity. + /// An array of branch components. + /// An array of task components. + /// An array of reevaluate task components. + [BurstCompile] + public void Execute(Entity entity, [EntityIndexInQuery] int entityIndex, in DynamicBuffer branchComponents, ref DynamicBuffer taskComponents, ref DynamicBuffer reevaluateTaskComponents) + { + for (int i = 0; i < reevaluateTaskComponents.Length; ++i) { + var reevaluateTaskComponent = reevaluateTaskComponents[i]; + // The task may not be able to reevaluate. + var taskComponent = taskComponents[reevaluateTaskComponent.Index]; + if (!taskComponent.CanReevaluate || taskComponent.Disabled) { + continue; + } + + // The branch may not be active. + var branchComponent = branchComponents[taskComponent.BranchIndex]; + if (branchComponent.ActiveIndex == ushort.MaxValue) { + if (taskComponent.Reevaluate) { + taskComponent.Reevaluate = false; + taskComponents[reevaluateTaskComponent.Index] = taskComponent; + + reevaluateTaskComponent.ReevaluateStatus = ReevaluateStatus.Inactive; + reevaluateTaskComponents[i] = reevaluateTaskComponent; + } + continue; + } + + var reevaluate = false; + if (reevaluateTaskComponent.AbortType == ConditionalAbortType.Self || reevaluateTaskComponent.AbortType == ConditionalAbortType.Both) { + if (branchComponent.ActiveIndex > taskComponent.Index && branchComponent.ActiveIndex <= reevaluateTaskComponent.SelfPriorityUpperIndex) { + // Reevaluate. + reevaluate = true; + if (reevaluateTaskComponent.ReevaluateStatus == ReevaluateStatus.Inactive) { + reevaluateTaskComponent.ReevaluateStatus = ReevaluateStatus.Active; + EntityCommandBuffer.SetComponentEnabled(entityIndex, entity, reevaluateTaskComponent.ReevaluateFlagComponentType, true); + } + } + } + if (!reevaluate && (reevaluateTaskComponent.AbortType == ConditionalAbortType.LowerPriority || reevaluateTaskComponent.AbortType == ConditionalAbortType.Both)) { + if (branchComponent.ActiveIndex > reevaluateTaskComponent.LowerPriorityLowerIndex && branchComponent.ActiveIndex <= reevaluateTaskComponent.LowerPriorityUpperIndex) { + // Reevaluate. + reevaluate = true; + if (reevaluateTaskComponent.ReevaluateStatus == ReevaluateStatus.Inactive) { + reevaluateTaskComponent.ReevaluateStatus = ReevaluateStatus.Active; + EntityCommandBuffer.SetComponentEnabled(entityIndex, entity, reevaluateTaskComponent.ReevaluateFlagComponentType, true); + } + } + } + + // The task should no longer reevaluate. + if (!reevaluate && (taskComponent.Reevaluate || reevaluateTaskComponent.ReevaluateStatus == ReevaluateStatus.Dirty)) { + // The system needs to be kept active if there are other tasks with the same reevaluate tag. + var keepSystemActive = false; + for (int j = 0; j < reevaluateTaskComponents.Length; ++j) { + if (i == j) { + continue; + } + + if ((reevaluateTaskComponents[j].ReevaluateStatus == ReevaluateStatus.Active || reevaluateTaskComponents[j].ReevaluateStatus == ReevaluateStatus.Dirty) && + reevaluateTaskComponent.ReevaluateFlagComponentType == reevaluateTaskComponents[j].ReevaluateFlagComponentType) { + keepSystemActive = true; + break; + } + } + + if (!keepSystemActive) { + EntityCommandBuffer.SetComponentEnabled(entityIndex, entity, reevaluateTaskComponent.ReevaluateFlagComponentType, false); + } + // The task should always disable itself. + taskComponent.Reevaluate = false; + reevaluateTaskComponent.ReevaluateStatus = ReevaluateStatus.Inactive; + } else { + // Store the current status of the task. This status will be compared after the task is reevaluated within DetermineInterruptSystem. + reevaluateTaskComponent.OriginalStatus = taskComponent.Status; + } + + reevaluateTaskComponents[i] = reevaluateTaskComponent; + + taskComponent.Reevaluate = reevaluate; + taskComponents[reevaluateTaskComponent.Index] = taskComponent; + } + } + } + } + + /// + /// The tasks have been reevaluated. Compare the status to determine if an interrupt should occur. + /// + [UpdateInGroup(typeof(InterruptSystemGroup))] + [UpdateBefore(typeof(InterruptSystem))] + public partial struct ConditionalAbortsInvokerSystem : ISystem + { + private EntityQuery m_Query; + + /// + /// Builds the query. + /// + /// THe current SystemState. + private void OnCreate(ref SystemState state) + { + m_Query = SystemAPI.QueryBuilder().WithAllRW().WithAllRW().WithAllRW().WithAbsent().Build(); + } + + /// + /// Creates the jobs necessary for conditional aborts. + /// + /// The current SystemState. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + var ecb = new EntityCommandBuffer(Allocator.TempJob); + state.Dependency = new ConditionalAbortsJob() + { + EntityCommandBuffer = ecb.AsParallelWriter() + }.ScheduleParallel(m_Query, state.Dependency); + + // The jobs must be run immediately for the next systems. + state.Dependency.Complete(); + ecb.Playback(state.EntityManager); + ecb.Dispose(); + } + + /// + /// Job which checks for any tasks that should be reevaluated with conditional aborts. This job only flags the tasks, it does not do + /// the actual reevaluation or interruption. + /// + [BurstCompile] + private partial struct ConditionalAbortsJob : IJobEntity + { + [Tooltip("CommandBuffer which sets the component data.")] + public EntityCommandBuffer.ParallelWriter EntityCommandBuffer; + + /// + /// Executes the job. + /// + /// The entity that is being acted upon. + /// The index of the entity. + /// An array of branch components. + /// An array of task components. + /// An array of reevaluate task components. + [BurstCompile] + public void Execute(Entity entity, [EntityIndexInQuery] int entityIndex, ref DynamicBuffer branchComponents, ref DynamicBuffer taskComponents, ref DynamicBuffer reevaluateTaskComponents) + { + for (int i = 0; i < reevaluateTaskComponents.Length; ++i) { + var reevaluateTaskComponent = reevaluateTaskComponents[i]; + var taskComponent = taskComponents[reevaluateTaskComponent.Index]; + + if (taskComponent.Reevaluate) { + if (reevaluateTaskComponent.OriginalStatus != taskComponent.Status) { + // The status is different. This will cause an interrupt. + var branchComponent = branchComponents[taskComponent.BranchIndex]; + // The task with the highest priority should cause the abort. + if (branchComponent.InterruptType == InterruptType.None || taskComponent.Index < branchComponent.InterruptIndex) { + branchComponent.InterruptIndex = taskComponent.Index; + branchComponent.InterruptType = InterruptType.Branch; + branchComponents[taskComponent.BranchIndex] = branchComponent; + } else { + taskComponent.Status = TaskStatus.Inactive; + } + + taskComponent.Reevaluate = false; + taskComponents[reevaluateTaskComponent.Index] = taskComponent; + EntityCommandBuffer.SetComponentEnabled(entityIndex, entity, true); + + reevaluateTaskComponent.ReevaluateStatus = ReevaluateStatus.Dirty; + var reevaluateTaskComponentsBuffer = reevaluateTaskComponents; + reevaluateTaskComponentsBuffer[i] = reevaluateTaskComponent; + } + } + } + } + } + } + + /// + /// Processes any interrupts. + /// + [UpdateInGroup(typeof(InterruptSystemGroup))] + [UpdateAfter(typeof(ConditionalAbortsInvokerSystem))] + public partial struct InterruptSystem : ISystem + { + private EntityQuery m_Query; + + /// + /// Builds the query. + /// + /// THe current SystemState. + private void OnCreate(ref SystemState state) + { + m_Query = SystemAPI.QueryBuilder().WithAllRW().WithAllRW().WithAll().Build(); + } + + /// + /// Creates the InterruptJob. + /// + /// The current SystemState. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + var ecb = new EntityCommandBuffer(Allocator.TempJob); + state.Dependency = new InterruptJob() + { + EntityCommandBuffer = ecb.AsParallelWriter(), + }.ScheduleParallel(m_Query, state.Dependency); + + // The job must run immediately for the next systems. + state.Dependency.Complete(); + ecb.Playback(state.EntityManager); + ecb.Dispose(); + } + + /// + /// Triggers the interrupts. + /// + [BurstCompile] + private partial struct InterruptJob : IJobEntity + { + [Tooltip("CommandBuffer which sets the component data.")] + public EntityCommandBuffer.ParallelWriter EntityCommandBuffer; + + /// + /// Executes the job. + /// + /// The entity that is being acted upon. + /// The index of the entity. + /// An array of branch components. + /// An array of task components. + [BurstCompile] + public void Execute(Entity entity, [EntityIndexInQuery] int entityIndex, DynamicBuffer branchComponents, DynamicBuffer taskComponents) + { + for (ushort i = 0; i < branchComponents.Length; ++i) { + var branchComponent = branchComponents[i]; + if (branchComponent.InterruptType != InterruptType.None) { + var targetTaskComponent = taskComponents[branchComponent.InterruptIndex]; + var parentIndex = targetTaskComponent.ParentIndex == ushort.MaxValue ? targetTaskComponent.Index : targetTaskComponent.ParentIndex; + TaskStatus prevActiveNewStatus; + if (branchComponent.InterruptType == InterruptType.Branch) { + branchComponent.NextIndex = branchComponent.InterruptIndex; + branchComponents[i] = branchComponent; + + // Start the target task. + targetTaskComponent.Status = TaskStatus.Running; + // Set the target branch tasks to running. Any parent that uses conditional aborts should implement IInterruptResponder. + while (parentIndex != ushort.MaxValue && taskComponents[parentIndex].Status != TaskStatus.Running) { + var parentTaskComponent = taskComponents[parentIndex]; + parentTaskComponent.Status = TaskStatus.Running; + taskComponents[parentIndex] = parentTaskComponent; + parentIndex = parentTaskComponent.ParentIndex; + } + + prevActiveNewStatus = TaskStatus.Failure; + } else { // InterruptType.ImmediateSuccess/Failure. + targetTaskComponent.Status = branchComponent.InterruptType == InterruptType.ImmediateSuccess ? TaskStatus.Success : TaskStatus.Failure; + var targetBranchComponent = branchComponents[targetTaskComponent.BranchIndex]; + targetBranchComponent.NextIndex = targetTaskComponent.ParentIndex; + branchComponents[targetTaskComponent.BranchIndex] = targetBranchComponent; + + prevActiveNewStatus = targetTaskComponent.Status; + } + + // Determine if any other branches need to be interrupted. + for (ushort j = i; j < branchComponents.Length; ++j) { + if (i == j || TraversalUtility.IsParent((ushort)branchComponents[j].ActiveIndex, parentIndex, ref taskComponents)) { + AbortChildren((ushort)branchComponents[j].ActiveIndex, parentIndex, ref taskComponents, prevActiveNewStatus); + + // Reset any queued children. + var taskComponentBuffer = taskComponents; + var childCount = TraversalUtility.GetChildCount(branchComponent.ActiveIndex, ref taskComponentBuffer); + for (int k = 0; k < childCount; ++k) { + var childTaskComponent = taskComponents[branchComponent.ActiveIndex + k + 1]; + if (childTaskComponent.Status == TaskStatus.Queued) { + childTaskComponent.Status = TaskStatus.Inactive; + taskComponentBuffer[branchComponent.ActiveIndex + k + 1] = childTaskComponent; + } + } + + // If the branch is a parallel branch then reset the NextIndex. The current branch (i) will be interrupted normally above. + var localBranchComponent = branchComponents[j]; + if (localBranchComponent.InterruptType == InterruptType.None) { + localBranchComponent.NextIndex = ushort.MaxValue; + branchComponents[j] = localBranchComponent; + } + EntityCommandBuffer.SetComponentEnabled(entityIndex, entity, true); + } + } + + taskComponents[targetTaskComponent.Index] = targetTaskComponent; + } + } + } + + /// + /// Aborts all of the children within the specified branch. + /// + /// The index of the active task within the branch. + /// Aborts the tasks up to the specified parent index. + /// All of the tasks. + /// The abort status. + [BurstCompile] + private void AbortChildren(ushort activeIndex, ushort parentIndex, ref DynamicBuffer taskComponents, TaskStatus status) + { + while (activeIndex != ushort.MaxValue && activeIndex != parentIndex) { + var activeTask = taskComponents[activeIndex]; + activeTask.Status = status; + taskComponents[activeIndex] = activeTask; + activeIndex = activeTask.ParentIndex; + } + } + } + } + + /// + /// Cleanup the interrupts after they have run. + /// + [UpdateInGroup(typeof(InterruptSystemGroup), OrderLast = true)] + public partial struct InterruptCleanupSystem : ISystem + { + /// + /// Executes the system. + /// + /// The current SystemState. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + foreach (var (branchComponents, entity) in + SystemAPI.Query>().WithAll().WithEntityAccess()) { + for (int i = 0; i < branchComponents.Length; ++i) { + var branchComponent = branchComponents[i]; + if (branchComponent.InterruptType != InterruptType.None) { + // Reset the interruption. + branchComponent.InterruptType = InterruptType.None; + branchComponent.InterruptIndex = 0; + var branchComponentBuffer = branchComponents; + branchComponentBuffer[i] = branchComponent; + + state.EntityManager.SetComponentEnabled(entity, false); + } + } + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Systems/BeforeTraversalSystems.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Systems/BeforeTraversalSystems.cs.meta new file mode 100644 index 0000000..4cc57b4 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Systems/BeforeTraversalSystems.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ffa99079a1d11e547943e43bd0446c86 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Systems/CleanupSystem.cs b/Packages/com.opsive.behaviordesigner/Runtime/Systems/CleanupSystem.cs new file mode 100644 index 0000000..40fbb36 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Systems/CleanupSystem.cs @@ -0,0 +1,176 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Systems +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.BehaviorDesigner.Runtime.Groups; + using Unity.Burst; + using Unity.Burst.Intrinsics; + using Unity.Collections; + using Unity.Entities; + + /// + /// Resets the evaluation status. + /// + [DisableAutoCreation] + [UpdateInGroup(typeof(BehaviorTreeSystemGroup), OrderLast = true)] + [BurstCompile] + public partial struct EvaluationCleanupSystem : ISystem + { + private EntityQuery m_EvaluateCleanupQuery; + private ComponentTypeHandle m_EnabledComponentHandle; + private ComponentTypeHandle m_EvaluateComponentHandle; + private BufferTypeHandle m_BranchComponentHandle; + + /// + /// Creates the required objects for use within the job system. + /// + /// The current SystemState. + [BurstCompile] + private void OnCreate(ref SystemState state) + { + m_EvaluateCleanupQuery = new EntityQueryBuilder(Allocator.Temp) + .WithAll() + .WithAllRW() + .WithOptions(EntityQueryOptions.IgnoreComponentEnabledState) + .Build(ref state); + m_EnabledComponentHandle = state.GetComponentTypeHandle(); + m_EvaluateComponentHandle = state.GetComponentTypeHandle(); + m_BranchComponentHandle = state.GetBufferTypeHandle(); + } + + /// + /// Updates the data object values for use within the job system. + /// + /// The current SystemState. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + state.Dependency.Complete(); + + // Reset the evaluation status. + m_EnabledComponentHandle.Update(ref state); + m_EvaluateComponentHandle.Update(ref state); + m_BranchComponentHandle.Update(ref state); + var evaluationCleanupJob = new EvaluationCleanupJob() + { + EnabledComponentHandle = m_EnabledComponentHandle, + EvaluateComponentHandle = m_EvaluateComponentHandle, + BranchComponentHandle = m_BranchComponentHandle, + }; + state.Dependency = evaluationCleanupJob.ScheduleParallel(m_EvaluateCleanupQuery, state.Dependency); + } + + /// + /// Job that resets the EvaluationComponent component value. + /// + [BurstCompile(CompileSynchronously = true)] + public struct EvaluationCleanupJob : IJobChunk + { + [UnityEngine.Tooltip("A reference to the Enabled Component Handle.")] + public ComponentTypeHandle EnabledComponentHandle; + [UnityEngine.Tooltip("A reference to the Evaluate Component Handle.")] + public ComponentTypeHandle EvaluateComponentHandle; + [UnityEngine.Tooltip("A reference to the Branch Component Handle.")] + public BufferTypeHandle BranchComponentHandle; + + /// + /// Resets the EvaluationComponent component value. + /// + /// Block of memory that contains the entity and components. + /// The index of the chunk. + /// Should the enabled mask be used? + /// The bitwise enabled mask. + [BurstCompile] + public void Execute(in ArchetypeChunk chunk, int unfilteredChunkIndex, bool useEnabledMask, in v128 chunkEnabledMask) + { + var branchAccessor = chunk.GetBufferAccessor(ref BranchComponentHandle); + for (int i = 0; i < chunk.Count; i++) { + // If the chunk is enabled then it should be evaluated. + if (chunk.IsComponentEnabled(ref EnabledComponentHandle, i)) { + chunk.SetComponentEnabled(ref EvaluateComponentHandle, i, true); + } + + // Reset CanExecute for all branches so they can execute in the next tick. + var branchComponents = branchAccessor[i]; + for (int j = 0; j < branchComponents.Length; j++) { + var branchComponent = branchComponents[j]; + branchComponent.CanExecute = true; + branchComponent.LastActiveIndex = ushort.MaxValue; + branchComponents[j] = branchComponent; + } + } + } + } + } + + /// + /// Resets the InterruptedFlag enabled value. + /// + [DisableAutoCreation] + [UpdateInGroup(typeof(BehaviorTreeSystemGroup), OrderLast = true)] + [BurstCompile] + public partial struct InterruptedCleanupSystem : ISystem + { + private EntityQuery m_InterruptedCleanupQuery; + private ComponentTypeHandle m_InterruptedComponentHandle; + + /// + /// Creates the required objects for use within the job system. + /// + /// The current SystemState. + [BurstCompile] + private void OnCreate(ref SystemState state) + { + m_InterruptedCleanupQuery = new EntityQueryBuilder(Allocator.Temp) + .WithAll() + .Build(ref state); + m_InterruptedComponentHandle = state.GetComponentTypeHandle(); + } + + /// + /// Updates the data object values for use within the job system. + /// + /// The current SystemState. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + // Clean up the interrupted tag. + m_InterruptedComponentHandle.Update(ref state); + var interruptedJob = new InterruptedCleanupJob() + { + InterruptedComponentHandle = m_InterruptedComponentHandle, + }; + state.Dependency = interruptedJob.ScheduleParallel(m_InterruptedCleanupQuery, state.Dependency); + } + + /// + /// Job that resets the InterruptedFlag value. + /// + [BurstCompile(CompileSynchronously = true)] + public partial struct InterruptedCleanupJob : IJobChunk + { + [UnityEngine.Tooltip("A reference to the Interrupted Component Handle.")] + public ComponentTypeHandle InterruptedComponentHandle; + + /// + /// Resets the InterruptedFlag value. + /// + /// The entity that is being acted upon. + /// The index of the entity. + [BurstCompile] + public void Execute(in ArchetypeChunk chunk, int unfilteredChunkIndex, bool useEnabledMask, in v128 chunkEnabledMask) + { + for (int i = 0; i < chunk.Count; i++) { + // Only chunks with the tag enabled will be returned so there's no need to check if the tag is enabled. + chunk.SetComponentEnabled(ref InterruptedComponentHandle, i, false); + } + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Systems/CleanupSystem.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Systems/CleanupSystem.cs.meta new file mode 100644 index 0000000..2f9a2cc --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Systems/CleanupSystem.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 36ac1accbf78b7344be0384fd1edf942 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Systems/TaskObjectSystem.cs b/Packages/com.opsive.behaviordesigner/Runtime/Systems/TaskObjectSystem.cs new file mode 100644 index 0000000..9050a69 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Systems/TaskObjectSystem.cs @@ -0,0 +1,217 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Systems +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.BehaviorDesigner.Runtime.Groups; + using Opsive.BehaviorDesigner.Runtime.Tasks; + using Opsive.BehaviorDesigner.Runtime.Utility; + using Opsive.GraphDesigner.Runtime; + using Unity.Entities; + using UnityEngine; + + /// + /// Specifies that the node is an object task which can specify the next child that should run. + /// + public interface ITaskObjectParentNode + { + /// + /// Returns the index of the next child that should run. Set to ushort.MaxValue to ignore. + /// + ushort NextChildIndex { get; } + } + + /// + /// The DOTS data structure for the TaskObject class. + /// + public struct TaskObjectComponent : IBufferElementData + { + [Tooltip("The index of the task.")] + public ushort Index; + } + + /// + /// A DOTS flag indicating when an TaskObject node is active. + /// + public struct TaskObjectFlag : IComponentData, IEnableableComponent { } + + /// + /// Runs the TaskObject logic. + /// + [DisableAutoCreation] + [UpdateInGroup(typeof(TraversalTaskSystemGroup), OrderLast = true)] + public partial struct TaskObjectSystem : ISystem + { + /// + /// Updates the logic. + /// + /// The current state of the system. + private void OnUpdate(ref SystemState state) + { + // When the task is interrupted there is no callback which prevents Task.OnEnd from being called. Track the status within the referenced task object and if the status is different then + // the task was aborted and OnEnd needs to be called. + foreach (var (taskObjectComponents, taskComponents, entity) in + SystemAPI.Query, DynamicBuffer>().WithAll().WithEntityAccess()) { + var behaviorTree = BehaviorTree.GetBehaviorTree(entity); + if (behaviorTree == null) { + continue; + } + + for (int i = 0; i < taskObjectComponents.Length; ++i) { + var taskObjectComponent = taskObjectComponents[i]; + var taskComponent = taskComponents[taskObjectComponent.Index]; + if (taskComponent.Status == TaskStatus.Success || taskComponent.Status == TaskStatus.Failure) { + var task = behaviorTree.GetTask(taskObjectComponent.Index) as Task; + if (task.Status != taskComponent.Status) { + task.OnEnd(); + task.Status = taskComponent.Status; + } + } + } + } + + // Update the task objects. + foreach (var (taskObjectComponents, taskComponents, branchComponents, entity) in + SystemAPI.Query, DynamicBuffer, DynamicBuffer>().WithAll().WithEntityAccess()) { + + var behaviorTree = BehaviorTree.GetBehaviorTree(entity); + if (behaviorTree == null) { + continue; + } + + for (int i = 0; i < taskObjectComponents.Length; ++i) { + var taskObjectComponent = taskObjectComponents[i]; + var taskComponent = taskComponents[taskObjectComponent.Index]; + var branchComponent = branchComponents[taskComponent.BranchIndex]; + if (!branchComponent.CanExecute || branchComponent.ActiveIndex != taskComponent.Index) { + continue; + } + + var task = behaviorTree.GetTask(taskObjectComponent.Index) as Task; + if (taskComponent.Status == TaskStatus.Queued) { + task.Status = taskComponent.Status = TaskStatus.Running; + var taskComponentBuffer = taskComponents; + taskComponentBuffer[taskComponent.Index] = taskComponent; + + task.OnStart(); + } + if (taskComponent.Status != TaskStatus.Running) { + continue; + } + + var status = task.OnUpdate(); + // Update the status if has changed. + if (status != taskComponent.Status) { + task.Status = taskComponent.Status = status; + var taskComponentBuffer = taskComponents; + taskComponentBuffer[taskComponent.Index] = taskComponent; + + // End the task if it is done running. + if (status != TaskStatus.Running) { + task.OnEnd(); + + branchComponent = branchComponents[taskComponent.BranchIndex]; + branchComponent.NextIndex = taskComponent.ParentIndex; + var branchComponentBuffer = branchComponents; + branchComponentBuffer[taskComponent.BranchIndex] = branchComponent; + } + } + + if (task is IParentNode && (task is ITaskObjectParentNode taskObjectParentNode)) { + if (status == TaskStatus.Running) { + // Parent object tasks do not have a direct way to set the next child. Use the ITaskObjectParentNode to switch the child task. + if (taskObjectParentNode.NextChildIndex != ushort.MaxValue && taskComponents[taskObjectParentNode.NextChildIndex].Status != TaskStatus.Running) { + branchComponent = branchComponents[taskComponent.BranchIndex]; + branchComponent.NextIndex = taskObjectParentNode.NextChildIndex; + var branchComponentBuffer = branchComponents; + branchComponentBuffer[taskComponent.BranchIndex] = branchComponent; + + var nextTaskComponent = taskComponents[taskObjectParentNode.NextChildIndex]; + nextTaskComponent.Status = TaskStatus.Queued; + var taskComponentBuffer = taskComponents; + taskComponentBuffer[taskObjectParentNode.NextChildIndex] = nextTaskComponent; + } + } else if (status == TaskStatus.Success || status == TaskStatus.Failure) { + // An interrupt should occur if the parent returns a success or failure status before the children. + var taskComponentBuffer = taskComponents; + var childCount = TraversalUtility.GetChildCount(taskComponent.Index, ref taskComponentBuffer); + var branchComponentBuffer = branchComponents; + var hasInterruptComponents = SystemAPI.HasComponent(entity); + var interruptedFlagEnabled = SystemAPI.IsComponentEnabled(entity); + for (ushort j = (ushort)(taskComponent.Index + 1); j < taskComponent.Index + 1 + childCount; ++j) { + var childTaskComponent = taskComponentBuffer[j]; + if (childTaskComponent.Status == TaskStatus.Running || childTaskComponent.Status == TaskStatus.Queued) { + childTaskComponent.Status = status; + taskComponentBuffer[j] = childTaskComponent; + + branchComponent = branchComponentBuffer[childTaskComponent.BranchIndex]; + if (!hasInterruptComponents) { + ComponentUtility.AddInterruptComponents(behaviorTree.World.EntityManager, entity); + hasInterruptComponents = true; + } + if (!interruptedFlagEnabled) { + SystemAPI.SetComponentEnabled(entity, true); + interruptedFlagEnabled = true; + } + if (branchComponent.ActiveIndex == childTaskComponent.Index) { + branchComponent.NextIndex = ushort.MaxValue; + branchComponentBuffer[childTaskComponent.BranchIndex] = branchComponent; + } + } + } + } + } + } + } + } + } + + /// + /// A DOTS tag indicating when an TaskObject node needs to be reevaluated. + /// + public struct TaskObjectReevaluateFlag : IComponentData, IEnableableComponent + { + } + + /// + /// Runs the TaskObject reevaluation logic. + /// + [DisableAutoCreation] + public partial struct TaskObjectReevaluateSystem : ISystem + { + /// + /// Updates the reevaluation logic. + /// + /// The current state of the system. + private void OnUpdate(ref SystemState state) + { + foreach (var (taskComponents, taskObjectComponents, entity) in + SystemAPI.Query, DynamicBuffer>().WithAll().WithEntityAccess()) { + for (int i = 0; i < taskObjectComponents.Length; ++i) { + var taskObjectComponent = taskObjectComponents[i]; + var taskComponent = taskComponents[taskObjectComponent.Index]; + if (!taskComponent.Reevaluate) { + continue; + } + var behaviorTree = BehaviorTree.GetBehaviorTree(entity); + if (behaviorTree == null) { + continue; + } + + var task = behaviorTree.GetTask(taskObjectComponent.Index) as IConditionalReevaluation; + var status = task.OnReevaluateUpdate(); + if (status != taskComponent.Status) { + taskComponent.Status = status; + var buffer = taskComponents; + buffer[taskComponent.Index] = taskComponent; + } + } + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Systems/TaskObjectSystem.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Systems/TaskObjectSystem.cs.meta new file mode 100644 index 0000000..e8c518a --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Systems/TaskObjectSystem.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 203f2349f12650c4f887e6a0a3925c04 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Systems/TraversalSystems.cs b/Packages/com.opsive.behaviordesigner/Runtime/Systems/TraversalSystems.cs new file mode 100644 index 0000000..7eb9b62 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Systems/TraversalSystems.cs @@ -0,0 +1,617 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Systems +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.BehaviorDesigner.Runtime.Groups; + using Opsive.BehaviorDesigner.Runtime.Tasks; + using Opsive.BehaviorDesigner.Runtime.Utility; + using Unity.Burst; + using Unity.Collections; + using Unity.Entities; + using Unity.Jobs; + using UnityEngine; + + /// + /// Traverses and ensures the correct tasks are active. + /// + [UpdateInGroup(typeof(TraversalSystemGroup))] + [UpdateAfter(typeof(TraversalTaskSystemGroup))] + public partial struct EvaluationSystem : ISystem + { + private bool m_JobScheduled; + private EntityQuery m_Query; + private JobHandle m_Dependency; + private EntityCommandBuffer m_EntityCommandBuffer; + + /// + /// The system has been created. + /// + /// The state of the system. + private void OnCreate(ref SystemState state) + { + m_JobScheduled = false; + m_Query = SystemAPI.QueryBuilder().WithAllRW().WithAbsent().Build(); + } + + /// + /// Starts the job which traverses the tree. + /// + /// The current state of the system. + private void OnUpdate(ref SystemState state) + { + m_JobScheduled = true; + + m_EntityCommandBuffer = new EntityCommandBuffer(state.WorldUpdateAllocator); + m_Dependency = state.Dependency = new EvaluationJob() + { + EntityCommandBuffer = m_EntityCommandBuffer.AsParallelWriter(), + }.ScheduleParallel(m_Query, state.Dependency); + } + + /// + /// Completes the job and releases any memory. + /// + /// The running EntityManager. + /// Has the system been stopped? + [BurstCompile] + public void Complete(EntityManager entityManager, bool stopRunning = false) + { + if (!m_JobScheduled) { + return; + } + + if (!stopRunning) { + m_Dependency.Complete(); + m_EntityCommandBuffer.Playback(entityManager); + m_EntityCommandBuffer.Dispose(); + } + + m_JobScheduled = false; + } + + /// + /// Job which traverses the tree. + /// + [BurstCompile] + public partial struct EvaluationJob : IJobEntity + { + [Tooltip("CommandBuffer which sets the component data.")] + public EntityCommandBuffer.ParallelWriter EntityCommandBuffer; + + /// + /// Executes the job. + /// + /// The entity that is being acted upon. + /// The index of the entity.An array of branch components. + /// An array of task components. + [BurstCompile] + public void Execute(Entity entity, [EntityIndexInQuery] int entityIndex, ref DynamicBuffer branchComponents, ref DynamicBuffer taskComponents) + { + for (int i = 0; i < branchComponents.Length; ++i) { + var branchComponent = branchComponents[i]; + if (branchComponent.ActiveIndex != ushort.MaxValue && branchComponent.ActiveIndex == branchComponent.NextIndex) { + var activeTask = taskComponents[branchComponent.ActiveIndex]; + if (activeTask.Status == TaskStatus.Success || activeTask.Status == TaskStatus.Failure) { + branchComponent.NextIndex = activeTask.ParentIndex; + } + } + if (branchComponent.ActiveIndex != branchComponent.NextIndex) { + // Do not switch into a disabled task. + if (branchComponent.NextIndex != ushort.MaxValue && taskComponents[branchComponent.NextIndex].Disabled) { + var taskComponent = taskComponents[branchComponent.NextIndex]; + taskComponent.Status = TaskStatus.Inactive; + var taskComponentBuffer = taskComponents; + taskComponentBuffer[branchComponent.NextIndex] = taskComponent; + + branchComponent.NextIndex = branchComponent.ActiveIndex; + } else { + // The status for all children should be reset back to their inactive state if the next task is within a new branch. This will prevent + // the return status from being reset when the task ends normally. + var taskComponentBuffer = taskComponents; + if (branchComponent.NextIndex != ushort.MaxValue && + !TraversalUtility.IsParent((ushort)branchComponent.ActiveIndex, (ushort)branchComponent.NextIndex, ref taskComponentBuffer)) { + var nextTaskComponent = taskComponents[branchComponent.NextIndex]; + if (branchComponent.ActiveIndex != ushort.MaxValue && nextTaskComponent.Status != TaskStatus.Running) { // If the next task is already running then an interrupt has already reset the children. + var childCount = TraversalUtility.GetChildCount(branchComponent.NextIndex, ref taskComponentBuffer); + for (int j = 0; j < childCount; ++j) { + var childTaskComponent = taskComponents[branchComponent.NextIndex + j + 1]; + childTaskComponent.Status = TaskStatus.Inactive; + taskComponentBuffer[branchComponent.NextIndex + j + 1] = childTaskComponent; + } + } + nextTaskComponent.Status = nextTaskComponent.Status == TaskStatus.Running ? TaskStatus.Running : TaskStatus.Queued; + taskComponentBuffer[branchComponent.NextIndex] = nextTaskComponent; + } + branchComponent.ActiveIndex = branchComponent.NextIndex; + + // Change the component tag if the task type is different. + var componentType = branchComponent.ActiveIndex != ushort.MaxValue ? taskComponents[branchComponent.ActiveIndex].FlagComponentType : new ComponentType(); + if (componentType != branchComponent.ActiveFlagComponentType) { + if (branchComponent.ActiveFlagComponentType.TypeIndex != TypeIndex.Null) { + var deactivateTag = true; + for (int j = 0; j < branchComponents.Length; ++j) { + // The tag should be deactivated if no other tasks have the same tag type. + if (i != j && branchComponents[j].ActiveIndex != ushort.MaxValue && + branchComponent.ActiveFlagComponentType == branchComponents[j].ActiveFlagComponentType) { + deactivateTag = false; + break; + } + } + + // The task of that type is no longer active - disable the system to prevent it from running. + if (deactivateTag) { + EntityCommandBuffer.SetComponentEnabled(entityIndex, entity, branchComponent.ActiveFlagComponentType, false); + } + } + // A new system type should start. + if (branchComponent.ActiveIndex != ushort.MaxValue) { + var taskComponent = taskComponents[branchComponent.ActiveIndex]; + EntityCommandBuffer.SetComponentEnabled(entityIndex, entity, taskComponent.FlagComponentType, true); + } + branchComponent.ActiveFlagComponentType = componentType; + } + } + var branchComponentBuffer = branchComponents; + branchComponentBuffer[i] = branchComponent; + } + } + } + } + } + + /// + /// Loops through the active tasks to determine if the system should stay active for the current tick. + /// + [UpdateInGroup(typeof(TraversalSystemGroup))] + [UpdateAfter(typeof(EvaluationSystem))] + public partial struct DetermineEvaluationSystem : ISystem + { + [Tooltip("Should the group stay active? An inactive tree does not run.")] + public bool Active { get; private set; } + [Tooltip("Should the group be evaluated? This bool indicates if the entire tree should be evaluated instead of the reevaluation" + + "concept for conditional aborts. The tree will be reevaluated if any of the leaf tasks have a status of running.")] + public bool Evaluate { get; private set; } + + private bool m_JobScheduled; + private JobHandle m_Dependency; + + private EntityQuery m_Query32; + private EntityQuery m_Query64; + private EntityQuery m_Query128; + private EntityQuery m_Query512; + private EntityQuery m_Query4096; + private EntityCommandBuffer m_EntityCommandBuffer32; + private EntityCommandBuffer m_EntityCommandBuffer64; + private EntityCommandBuffer m_EntityCommandBuffer128; + private EntityCommandBuffer m_EntityCommandBuffer512; + private EntityCommandBuffer m_EntityCommandBuffer4096; + + private NativeArray m_Results; + + /// + /// The system has been created. + /// + /// The state of the system. + private void OnCreate(ref SystemState state) + { + Active = Evaluate = true; + m_JobScheduled = false; + m_Query32 = SystemAPI.QueryBuilder().WithAllRW().WithAll().WithAbsent().Build(); + m_Query64 = SystemAPI.QueryBuilder().WithAllRW().WithAll().WithAbsent().Build(); + m_Query128 = SystemAPI.QueryBuilder().WithAllRW().WithAll().WithAbsent().Build(); + m_Query512 = SystemAPI.QueryBuilder().WithAllRW().WithAll().WithAbsent().Build(); + m_Query4096 = SystemAPI.QueryBuilder().WithAllRW().WithAll().WithAbsent().Build(); + } + + /// + /// Executes the job to determine if the system should stay active and evaluating. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + Active = Evaluate = true; + m_JobScheduled = true; + + m_EntityCommandBuffer32 = new EntityCommandBuffer(Allocator.TempJob); + m_EntityCommandBuffer64 = new EntityCommandBuffer(Allocator.TempJob); + m_EntityCommandBuffer128 = new EntityCommandBuffer(Allocator.TempJob); + m_EntityCommandBuffer512 = new EntityCommandBuffer(Allocator.TempJob); + m_EntityCommandBuffer4096 = new EntityCommandBuffer(Allocator.TempJob); + + m_Results = new NativeArray(3, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); + for (int i = 0; i < m_Results.Length; ++i) { + m_Results[i] = false; + } + + // Chain jobs sequentially since they all write to the shared Results array. + m_Dependency = new DetermineEvaluationJob32() + { + EntityCommandBuffer = m_EntityCommandBuffer32.AsParallelWriter(), + Results = m_Results + }.ScheduleParallel(m_Query32, state.Dependency); + m_Dependency = new DetermineEvaluationJob64() + { + EntityCommandBuffer = m_EntityCommandBuffer64.AsParallelWriter(), + Results = m_Results + }.ScheduleParallel(m_Query64, m_Dependency); + m_Dependency = new DetermineEvaluationJob128() + { + EntityCommandBuffer = m_EntityCommandBuffer128.AsParallelWriter(), + Results = m_Results + }.ScheduleParallel(m_Query128, m_Dependency); + m_Dependency = new DetermineEvaluationJob512() + { + EntityCommandBuffer = m_EntityCommandBuffer512.AsParallelWriter(), + Results = m_Results + }.ScheduleParallel(m_Query512, m_Dependency); + m_Dependency = new DetermineEvaluationJob4096() + { + EntityCommandBuffer = m_EntityCommandBuffer4096.AsParallelWriter(), + Results = m_Results + }.ScheduleParallel(m_Query4096, m_Dependency); + + state.Dependency = m_Dependency; + } + + /// + /// Completes the job and releases any memory. + /// + /// The running EntityManager. + [BurstCompile] + public void Complete(EntityManager entityManager) + { + if (!m_JobScheduled) { + return; + } + + m_Dependency.Complete(); + m_EntityCommandBuffer32.Playback(entityManager); + m_EntityCommandBuffer32.Dispose(); + m_EntityCommandBuffer64.Playback(entityManager); + m_EntityCommandBuffer64.Dispose(); + m_EntityCommandBuffer128.Playback(entityManager); + m_EntityCommandBuffer128.Dispose(); + m_EntityCommandBuffer512.Playback(entityManager); + m_EntityCommandBuffer512.Dispose(); + m_EntityCommandBuffer4096.Playback(entityManager); + m_EntityCommandBuffer4096.Dispose(); + + if (m_Results.IsCreated) { + if (m_Results[0]) { + Active = m_Results[1]; + Evaluate = m_Results[2]; + } else { + // If the first element is false then no trees executed. + Active = Evaluate = false; + } + m_Results.Dispose(); + } + m_JobScheduled = false; + } + + /// + /// The system has been destroyed. + /// + /// The current state of the system. + private void OnDestroy(ref SystemState state) + { + if (m_Dependency.IsCompleted) { + return; + } + + m_Results.Dispose(); + } + + /// + /// Job which determine if the system should stay active. If any behavior tree should stay active then the entire system must remain active. + /// + [BurstCompile] + public partial struct DetermineEvaluationJob32 : IJobEntity + { + [Tooltip("CommandBuffer which sets the component data.")] + public EntityCommandBuffer.ParallelWriter EntityCommandBuffer; + [Tooltip("The computed results.")] + [NativeDisableParallelForRestriction] public NativeArray Results; + + /// + /// Executes the job. + /// + /// The entity that is being acted upon. + /// The index of the entity. + /// An array of branch components. + /// An array of task components. + /// The EvaluationComponent that belongs to the entity. + [BurstCompile] + private void Execute(Entity entity, [EntityIndexInQuery] int entityIndex, ref DynamicBuffer branchComponents, in DynamicBuffer taskComponents, ref EvaluationComponent32 evaluationComponent) + { + var evaluatedTasks = evaluationComponent.EvaluatedTasks; + EvaluationUtility.DetermineEvaluation(entity, entityIndex, ref branchComponents, taskComponents, ref evaluatedTasks, evaluationComponent.EvaluationType, evaluationComponent.MaxEvaluationCount, EntityCommandBuffer, Results); + evaluationComponent.EvaluatedTasks = evaluatedTasks; + } + } + + /// + /// Job which determine if the system should stay active. If any behavior tree should stay active then the entire system must remain active. + /// + [BurstCompile] + public partial struct DetermineEvaluationJob64 : IJobEntity + { + [Tooltip("CommandBuffer which sets the component data.")] + public EntityCommandBuffer.ParallelWriter EntityCommandBuffer; + [Tooltip("The computed results.")] + [NativeDisableParallelForRestriction] public NativeArray Results; + + /// + /// Executes the job. + /// + /// The entity that is being acted upon. + /// The index of the entity. + /// An array of branch components. + /// An array of task components. + /// The EvaluationComponent that belongs to the entity. + [BurstCompile] + private void Execute(Entity entity, [EntityIndexInQuery] int entityIndex, ref DynamicBuffer branchComponents, in DynamicBuffer taskComponents, ref EvaluationComponent64 evaluationComponent) + { + var evaluatedTasks = evaluationComponent.EvaluatedTasks; + EvaluationUtility.DetermineEvaluation(entity, entityIndex, ref branchComponents, taskComponents, ref evaluatedTasks, evaluationComponent.EvaluationType, evaluationComponent.MaxEvaluationCount, EntityCommandBuffer, Results); + evaluationComponent.EvaluatedTasks = evaluatedTasks; + } + } + + /// + /// Job which determine if the system should stay active. If any behavior tree should stay active then the entire system must remain active. + /// + [BurstCompile] + public partial struct DetermineEvaluationJob128 : IJobEntity + { + [Tooltip("CommandBuffer which sets the component data.")] + public EntityCommandBuffer.ParallelWriter EntityCommandBuffer; + [Tooltip("The computed results.")] + [NativeDisableParallelForRestriction] public NativeArray Results; + + /// + /// Executes the job. + /// + /// The entity that is being acted upon. + /// The index of the entity. + /// An array of branch components. + /// An array of task components. + /// The EvaluationComponent that belongs to the entity. + [BurstCompile] + private void Execute(Entity entity, [EntityIndexInQuery] int entityIndex, ref DynamicBuffer branchComponents, in DynamicBuffer taskComponents, ref EvaluationComponent128 evaluationComponent) + { + var evaluatedTasks = evaluationComponent.EvaluatedTasks; + EvaluationUtility.DetermineEvaluation(entity, entityIndex, ref branchComponents, taskComponents, ref evaluatedTasks, evaluationComponent.EvaluationType, evaluationComponent.MaxEvaluationCount, EntityCommandBuffer, Results); + evaluationComponent.EvaluatedTasks = evaluatedTasks; + } + } + + + /// + /// Job which determine if the system should stay active. If any behavior tree should stay active then the entire system must remain active. + /// + [BurstCompile] + public partial struct DetermineEvaluationJob512 : IJobEntity + { + [Tooltip("CommandBuffer which sets the component data.")] + public EntityCommandBuffer.ParallelWriter EntityCommandBuffer; + [Tooltip("The computed results.")] + [NativeDisableParallelForRestriction] public NativeArray Results; + + /// + /// Executes the job. + /// + /// The entity that is being acted upon. + /// The index of the entity. + /// An array of branch components. + /// An array of task components. + /// The EvaluationComponent that belongs to the entity. + [BurstCompile] + private void Execute(Entity entity, [EntityIndexInQuery] int entityIndex, ref DynamicBuffer branchComponents, in DynamicBuffer taskComponents, ref EvaluationComponent512 evaluationComponent) + { + var evaluatedTasks = evaluationComponent.EvaluatedTasks; + EvaluationUtility.DetermineEvaluation(entity, entityIndex, ref branchComponents, taskComponents, ref evaluatedTasks, evaluationComponent.EvaluationType, evaluationComponent.MaxEvaluationCount, EntityCommandBuffer, Results); + evaluationComponent.EvaluatedTasks = evaluatedTasks; + } + } + + /// + /// Job which determine if the system should stay active. If any behavior tree should stay active then the entire system must remain active. + /// + [BurstCompile] + public partial struct DetermineEvaluationJob4096 : IJobEntity + { + [Tooltip("CommandBuffer which sets the component data.")] + public EntityCommandBuffer.ParallelWriter EntityCommandBuffer; + [Tooltip("The computed results.")] + [NativeDisableParallelForRestriction] public NativeArray Results; + + /// + /// Executes the job. + /// + /// The entity that is being acted upon. + /// The index of the entity. + /// An array of branch components. + /// An array of task components. + /// The EvaluationComponent that belongs to the entity. + [BurstCompile] + private void Execute(Entity entity, [EntityIndexInQuery] int entityIndex, ref DynamicBuffer branchComponents, in DynamicBuffer taskComponents, ref EvaluationComponent4096 evaluationComponent) + { + var evaluatedTasks = evaluationComponent.EvaluatedTasks; + EvaluationUtility.DetermineEvaluation(entity, entityIndex, ref branchComponents, taskComponents, ref evaluatedTasks, evaluationComponent.EvaluationType, evaluationComponent.MaxEvaluationCount, EntityCommandBuffer, Results); + evaluationComponent.EvaluatedTasks = evaluatedTasks; + } + } + } + + /// + /// Utility functions for the task evaluation. + /// + [BurstCompile] + public struct EvaluationUtility + { + /// + /// Is the task at the specified index a parent task. + /// + /// An array of task components. + /// The index to check if it is a parent. + /// True if the task at the specified index is a parent task. + [BurstCompile] + public static bool IsParentTask(ref DynamicBuffer taskComponents, int index) + { + // The last task cannot be a parent. + if (index == taskComponents.Length - 1) { + return false; + } + + // The next child will have a parent of the current task. + if (taskComponents[index + 1].ParentIndex == index) { + return true; + } + + // The parent index is different - the current task is not a parent. + return false; + } + + /// + /// Core evaluation logic that works with any FixedList type for EvaluatedTasks. + /// + /// The type of FixedList for EvaluatedTasks. + /// The entity that is being acted upon. + /// The index of the entity. + /// An array of branch components. + /// An array of task components. + /// The evaluated tasks list. + /// The evaluation type. + /// The maximum evaluation count. + /// The command buffer for setting component data. + /// The computed results array. + [BurstCompile] + public static void DetermineEvaluation(Entity entity, int entityIndex, ref DynamicBuffer branchComponents, DynamicBuffer taskComponents, ref TFixedList evaluatedTasks, EvaluationType evaluationType, ushort maxEvaluationCount, EntityCommandBuffer.ParallelWriter entityCommandBuffer, NativeArray results) where TFixedList : struct, INativeList + { + results[0] = true; // The first element indicates that the job has been executed. + + // No branches may be active. + var active = false; + var evaluate = false; + var evaluatedMask = new FixedList4096Bytes(); + for (int i = 0; i < branchComponents.Length; ++i) { + var branchComponent = branchComponents[i]; + if (branchComponent.ActiveIndex == ushort.MaxValue || !branchComponent.CanExecute) { + continue; + } + active = true; + + // Interrupts are processed in a separate system that is run outside of the task execution system. As a result the branch should not continue to evaluate. + if (branchComponent.InterruptType != InterruptType.None) { + continue; + } + + var taskComponent = taskComponents[branchComponent.ActiveIndex]; + var isParentTask = EvaluationUtility.IsParentTask(ref taskComponents, branchComponent.ActiveIndex); + // The branch can evaluate if the active task is an outer node (action or conditional) and is not running OR + // the task is an inner node (composite or decorator), is running, and is not a parallel task. Parent tasks cannot run without an active child. + if ((!isParentTask && taskComponent.Status != TaskStatus.Running && taskComponent.ParentIndex != ushort.MaxValue) || + (isParentTask && (taskComponent.Status == TaskStatus.Queued || taskComponent.Status == TaskStatus.Running))) { + + // Compute active task bit positions. + var bitIndex = branchComponent.ActiveIndex + 1; + var arrayIndex = bitIndex / ComponentUtility.ulongBitSize; + var bitInUlong = bitIndex % ComponentUtility.ulongBitSize; + while (evaluatedMask.Length <= arrayIndex) evaluatedMask.Add(0UL); + evaluatedMask[arrayIndex] |= (1UL << bitInUlong); + + // Prevent evaluating the same task again within the same tick. + if (branchComponent.ActiveIndex == branchComponent.LastActiveIndex) { + branchComponent.CanExecute = false; + branchComponents.ElementAt(i) = branchComponent; + continue; + } + + // Check if the task has already been evaluated this tick. + var alreadyEvaluated = (evaluatedTasks[arrayIndex] & (1UL << bitInUlong)) != 0; + + // Decision to evaluate: + // - For parent tasks: always evaluate. The parent task should never be the last executing task. + // - For non-parent tasks: evaluate if this task hasn't been evaluated yet. + if (isParentTask || !alreadyEvaluated) { + evaluate = true; + branchComponent.LastActiveIndex = branchComponent.ActiveIndex; + } else { + branchComponent.CanExecute = false; + } + branchComponents.ElementAt(i) = branchComponent; + + evaluatedTasks[arrayIndex] |= evaluatedMask[arrayIndex]; + } else { + branchComponent.CanExecute = false; + branchComponents.ElementAt(i) = branchComponent; + } + } + + // If a branch is active then at least one task within that branch is active. + if (active) { + results[1] = true; // Active result. + + if (evaluate) { + if (evaluationType == EvaluationType.Count) { + // Use the last element of EvaluatedTasks as the counter. + evaluatedTasks[evaluatedTasks.Length - 1]++; + if (evaluatedTasks[evaluatedTasks.Length - 1] >= maxEvaluationCount) { + // Reset the counter and bitmask elements. + for (int i = 0; i < evaluatedTasks.Length; ++i) { + evaluatedTasks[i] = 0; + } + entityCommandBuffer.SetComponentEnabled(entityIndex, entity, false); + // Set the bitmask for current active tasks to prevent one extra task from being executed on subsequent frames. + SetActiveBranchBits(ref branchComponents, ref evaluatedTasks); + } else { + results[2] = true; // Evaluate result. + } + } else { + results[2] = true; // Evaluate result - continue the loop. + } + } else { + entityCommandBuffer.SetComponentEnabled(entityIndex, entity, false); + // Reset the evaluated tasks bitmask. + for (int i = 0; i < evaluatedTasks.Length; ++i) { + evaluatedTasks[i] = 0; + } + // The system is going to stop evaluating this entity. It will be resumed immediately the next update. Because the DetermineEvaluationJob is run after the tasks + // update the EvaluatedTasks value should be set to the next active task. If this value is set to 0 then one extra task will always be executed with subsequent frames. + SetActiveBranchBits(ref branchComponents, ref evaluatedTasks); + } + } + } + + /// + /// Sets the bitmask bits for all active branches. This prevents one extra task from being executed on subsequent frames. + /// + /// An array of branch components. + /// The evaluated tasks list to update. + [BurstCompile] + private static void SetActiveBranchBits(ref DynamicBuffer branchComponents, ref TFixedList evaluatedTasks) where TFixedList : struct, INativeList + { + for (int i = 0; i < branchComponents.Length; ++i) { + var branchComponent = branchComponents[i]; + if (branchComponent.ActiveIndex == ushort.MaxValue) { + continue; + } + + // Compute active task bit positions. + var bitIndex = branchComponent.ActiveIndex + 1; + var arrayIndex = bitIndex / ComponentUtility.ulongBitSize; + var bitInUlong = bitIndex % ComponentUtility.ulongBitSize; + evaluatedTasks[arrayIndex] |= (1UL << bitInUlong); + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Systems/TraversalSystems.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Systems/TraversalSystems.cs.meta new file mode 100644 index 0000000..cc0ff28 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Systems/TraversalSystems.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4e38e2be36422f54fa65b67063d03366 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks.meta new file mode 100644 index 0000000..61befb4 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0b7936234bfdce042b052d68dd0136f1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions.meta new file mode 100644 index 0000000..ab1c731 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 72fd968959b610e4bb7994fedbaab0c9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Action.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Action.cs new file mode 100644 index 0000000..5423f29 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Action.cs @@ -0,0 +1,19 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions +{ + using Opsive.GraphDesigner.Runtime; + + /// + /// A TaskObject implementation of the Action task. + /// + [NodeIcon("3bbdfa553da4d554e9d74f8d88915aac", "6437308e972f99f48953f20198fd4e94")] + public abstract class Action : Task, IAction + { + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Action.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Action.cs.meta new file mode 100644 index 0000000..0887adb --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Action.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 24e232a868c7a0d439cb82feeb963c8e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/ActionNode.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/ActionNode.cs new file mode 100644 index 0000000..17ade82 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/ActionNode.cs @@ -0,0 +1,31 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions +{ + using Opsive.GraphDesigner.Runtime; + using UnityEngine; + + /// + /// A TaskObject implementation of the Action task. This class can be used when the task should not be grouped by the StackedAction task. + /// + [NodeIcon("3bbdfa553da4d554e9d74f8d88915aac", "6437308e972f99f48953f20198fd4e94")] + public abstract class ActionNode : Task, ITreeLogicNode, IAction + { + [Tooltip("The index of the node.")] + [SerializeField] ushort m_Index; + [Tooltip("The parent index of the node. ushort.MaxValue indicates no parent.")] + [SerializeField] ushort m_ParentIndex; + [Tooltip("The sibling index of the node. ushort.MaxValue indicates no sibling.")] + [SerializeField] ushort m_SiblingIndex; + + public ushort Index { get => m_Index; set => m_Index = value; } + public ushort ParentIndex { get => m_ParentIndex; set => m_ParentIndex = value; } + public ushort SiblingIndex { get => m_SiblingIndex; set => m_SiblingIndex = value; } + public ushort RuntimeIndex { get; set; } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/ActionNode.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/ActionNode.cs.meta new file mode 100644 index 0000000..5824520 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/ActionNode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f95ceadf4eaf7df499091158c2ba5178 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions.meta new file mode 100644 index 0000000..bc78407 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a57b0c8b5bd7c5142963151eb3723e6e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertBoolToFloat.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertBoolToFloat.cs new file mode 100644 index 0000000..cc957d2 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertBoolToFloat.cs @@ -0,0 +1,33 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Conversions +{ + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Converts a boolean value to a float value (true = 1.0, false = 0.0).")] + [Shared.Utility.Category("Conversions")] + public class ConvertBoolToFloat : Action + { + [Tooltip("The boolean value to convert.")] + [SerializeField] protected SharedVariable m_Value; + [Tooltip("The variable that should be set to the converted float value.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + m_StoreResult.Value = m_Value.Value ? 1.0f : 0.0f; + return TaskStatus.Success; + } + } +} +#endif + diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertBoolToFloat.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertBoolToFloat.cs.meta new file mode 100644 index 0000000..8e225f0 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertBoolToFloat.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 73c605544c0648e4bbf8dcfe72348337 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertBoolToInt.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertBoolToInt.cs new file mode 100644 index 0000000..e08b49b --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertBoolToInt.cs @@ -0,0 +1,33 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Conversions +{ + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Converts a boolean value to an integer value (true = 1, false = 0).")] + [Shared.Utility.Category("Conversions")] + public class ConvertBoolToInt : Action + { + [Tooltip("The boolean value to convert.")] + [SerializeField] protected SharedVariable m_Value; + [Tooltip("The variable that should be set to the converted integer value.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + m_StoreResult.Value = m_Value.Value ? 1 : 0; + return TaskStatus.Success; + } + } +} +#endif + diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertBoolToInt.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertBoolToInt.cs.meta new file mode 100644 index 0000000..5b35c1d --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertBoolToInt.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3955564edbd009346b730327375e3d48 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertBoolToString.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertBoolToString.cs new file mode 100644 index 0000000..daa94ac --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertBoolToString.cs @@ -0,0 +1,33 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Conversions +{ + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Converts a boolean value to a string value.")] + [Shared.Utility.Category("Conversions")] + public class ConvertBoolToString : Action + { + [Tooltip("The boolean value to convert.")] + [SerializeField] protected SharedVariable m_Value; + [Tooltip("The variable that should be set to the converted string value.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + m_StoreResult.Value = m_Value.Value.ToString(); + return TaskStatus.Success; + } + } +} +#endif + diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertBoolToString.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertBoolToString.cs.meta new file mode 100644 index 0000000..48dad45 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertBoolToString.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 888e5ecfd2f882346ad4879020c18283 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertFloatToBool.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertFloatToBool.cs new file mode 100644 index 0000000..cb090ee --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertFloatToBool.cs @@ -0,0 +1,33 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Conversions +{ + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Converts a float value to a boolean value (0.0 = false, non-zero = true).")] + [Shared.Utility.Category("Conversions")] + public class ConvertFloatToBool : Action + { + [Tooltip("The float value to convert.")] + [SerializeField] protected SharedVariable m_Value; + [Tooltip("The variable that should be set to the converted boolean value.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + m_StoreResult.Value = m_Value.Value != 0.0f; + return TaskStatus.Success; + } + } +} +#endif + diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertFloatToBool.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertFloatToBool.cs.meta new file mode 100644 index 0000000..b3c73f8 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertFloatToBool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 49e265c8db111534fab491cfc5672622 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertFloatToInt.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertFloatToInt.cs new file mode 100644 index 0000000..4e8d0c9 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertFloatToInt.cs @@ -0,0 +1,33 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Conversions +{ + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Converts a float value to an integer value.")] + [Shared.Utility.Category("Conversions")] + public class ConvertFloatToInt : Action + { + [Tooltip("The float value to convert.")] + [SerializeField] protected SharedVariable m_Value; + [Tooltip("The variable that should be set to the converted integer value.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + m_StoreResult.Value = Mathf.RoundToInt(m_Value.Value); + return TaskStatus.Success; + } + } +} +#endif + diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertFloatToInt.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertFloatToInt.cs.meta new file mode 100644 index 0000000..0aeb597 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertFloatToInt.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7e596c94da53a4a45ad9113b33a1aea4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertFloatToString.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertFloatToString.cs new file mode 100644 index 0000000..5443952 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertFloatToString.cs @@ -0,0 +1,33 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Conversions +{ + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Converts a float value to a string value.")] + [Shared.Utility.Category("Conversions")] + public class ConvertFloatToString : Action + { + [Tooltip("The float value to convert.")] + [SerializeField] protected SharedVariable m_Value; + [Tooltip("The variable that should be set to the converted string value.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + m_StoreResult.Value = m_Value.Value.ToString(); + return TaskStatus.Success; + } + } +} +#endif + diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertFloatToString.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertFloatToString.cs.meta new file mode 100644 index 0000000..258f476 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertFloatToString.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cc1ceef260c01c645b8b47ce20199dc6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertGameObjectToTransform.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertGameObjectToTransform.cs new file mode 100644 index 0000000..a529b1d --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertGameObjectToTransform.cs @@ -0,0 +1,37 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Conversions +{ + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Converts a GameObject value to a Transform value.")] + [Shared.Utility.Category("Conversions")] + public class ConvertGameObjectToTransform : Action + { + [Tooltip("The GameObject value to convert.")] + [SerializeField] protected SharedVariable m_Value; + [Tooltip("The variable that should be set to the converted Transform value.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + if (m_Value.Value != null) { + m_StoreResult.Value = m_Value.Value.transform; + return TaskStatus.Success; + } + m_StoreResult.Value = null; + return TaskStatus.Failure; + } + } +} +#endif + diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertGameObjectToTransform.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertGameObjectToTransform.cs.meta new file mode 100644 index 0000000..6227ffc --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertGameObjectToTransform.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a297e510d0a945c449c2d125813fe9d9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertIntToBool.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertIntToBool.cs new file mode 100644 index 0000000..9944f36 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertIntToBool.cs @@ -0,0 +1,33 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Conversions +{ + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Converts an integer value to a boolean value (0 = false, non-zero = true).")] + [Shared.Utility.Category("Conversions")] + public class ConvertIntToBool : Action + { + [Tooltip("The integer value to convert.")] + [SerializeField] protected SharedVariable m_Value; + [Tooltip("The variable that should be set to the converted boolean value.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + m_StoreResult.Value = m_Value.Value != 0; + return TaskStatus.Success; + } + } +} +#endif + diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertIntToBool.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertIntToBool.cs.meta new file mode 100644 index 0000000..a0d2bc0 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertIntToBool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 67e0599636ba3b7419611ae159070c04 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertIntToFloat.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertIntToFloat.cs new file mode 100644 index 0000000..effca97 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertIntToFloat.cs @@ -0,0 +1,33 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Conversions +{ + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Converts an integer value to a float value.")] + [Shared.Utility.Category("Conversions")] + public class ConvertIntToFloat : Action + { + [Tooltip("The integer value to convert.")] + [SerializeField] protected SharedVariable m_Value; + [Tooltip("The variable that should be set to the converted float value.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + m_StoreResult.Value = m_Value.Value; + return TaskStatus.Success; + } + } +} +#endif + diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertIntToFloat.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertIntToFloat.cs.meta new file mode 100644 index 0000000..e576fd1 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertIntToFloat.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 07440ccf7d92b14498b7e4c7b9e08e5e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertIntToString.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertIntToString.cs new file mode 100644 index 0000000..feac7d1 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertIntToString.cs @@ -0,0 +1,33 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Conversions +{ + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Converts an integer value to a string value.")] + [Shared.Utility.Category("Conversions")] + public class ConvertIntToString : Action + { + [Tooltip("The integer value to convert.")] + [SerializeField] protected SharedVariable m_Value; + [Tooltip("The variable that should be set to the converted string value.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + m_StoreResult.Value = m_Value.Value.ToString(); + return TaskStatus.Success; + } + } +} +#endif + diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertIntToString.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertIntToString.cs.meta new file mode 100644 index 0000000..c43439e --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertIntToString.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eeadd74b13bc65d45af983c98b9f3e01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertStringToBool.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertStringToBool.cs new file mode 100644 index 0000000..063eb8c --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertStringToBool.cs @@ -0,0 +1,36 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Conversions +{ + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Converts a string value to a boolean value.")] + [Shared.Utility.Category("Conversions")] + public class ConvertStringToBool : Action + { + [Tooltip("The string value to convert.")] + [SerializeField] protected SharedVariable m_Value; + [Tooltip("The variable that should be set to the converted boolean value.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + if (bool.TryParse(m_Value.Value, out bool result)) { + m_StoreResult.Value = result; + return TaskStatus.Success; + } + return TaskStatus.Failure; + } + } +} +#endif + diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertStringToBool.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertStringToBool.cs.meta new file mode 100644 index 0000000..8b556cc --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertStringToBool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 336754ea3fd33e44e91733089662ebd7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertStringToFloat.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertStringToFloat.cs new file mode 100644 index 0000000..f79e721 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertStringToFloat.cs @@ -0,0 +1,36 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Conversions +{ + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Converts a string value to a float value.")] + [Shared.Utility.Category("Conversions")] + public class ConvertStringToFloat : Action + { + [Tooltip("The string value to convert.")] + [SerializeField] protected SharedVariable m_Value; + [Tooltip("The variable that should be set to the converted float value.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + if (float.TryParse(m_Value.Value, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out float result)) { + m_StoreResult.Value = result; + return TaskStatus.Success; + } + return TaskStatus.Failure; + } + } +} +#endif + diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertStringToFloat.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertStringToFloat.cs.meta new file mode 100644 index 0000000..b8b7ca7 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertStringToFloat.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d22d87f8a2847f34185c0ff330b89209 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertStringToInt.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertStringToInt.cs new file mode 100644 index 0000000..b6f329d --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertStringToInt.cs @@ -0,0 +1,36 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Conversions +{ + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Converts a string value to an integer value.")] + [Shared.Utility.Category("Conversions")] + public class ConvertStringToInt : Action + { + [Tooltip("The string value to convert.")] + [SerializeField] protected SharedVariable m_Value; + [Tooltip("The variable that should be set to the converted integer value.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + if (int.TryParse(m_Value.Value, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture, out int result)) { + m_StoreResult.Value = result; + return TaskStatus.Success; + } + return TaskStatus.Failure; + } + } +} +#endif + diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertStringToInt.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertStringToInt.cs.meta new file mode 100644 index 0000000..0d1bbad --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertStringToInt.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e2d95d3a42e27184da971d47c792ff72 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertTransformToGameObject.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertTransformToGameObject.cs new file mode 100644 index 0000000..10bb152 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertTransformToGameObject.cs @@ -0,0 +1,37 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Conversions +{ + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Converts a Transform value to a GameObject value.")] + [Shared.Utility.Category("Conversions")] + public class ConvertTransformToGameObject : Action + { + [Tooltip("The Transform value to convert.")] + [SerializeField] protected SharedVariable m_Value; + [Tooltip("The variable that should be set to the converted GameObject value.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + if (m_Value.Value != null) { + m_StoreResult.Value = m_Value.Value.gameObject; + return TaskStatus.Success; + } + m_StoreResult.Value = null; + return TaskStatus.Failure; + } + } +} +#endif + diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertTransformToGameObject.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertTransformToGameObject.cs.meta new file mode 100644 index 0000000..9cfc1a6 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Conversions/ConvertTransformToGameObject.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 36617d392cb63e24184a825b05f4f78a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList.meta new file mode 100644 index 0000000..d79aed9 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 31447ed8785ef5146bbb37d6466c1954 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/AddGameObjectToArray.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/AddGameObjectToArray.cs new file mode 100644 index 0000000..4120ebe --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/AddGameObjectToArray.cs @@ -0,0 +1,45 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.UnityObjects +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using Opsive.Shared.Utility; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Adds the GameObject to the array.")] + [Shared.Utility.Category("Lists")] + public class AddGameObjectToArray : TargetGameObjectAction + { + [Tooltip("The list of possible GameObjects.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + [Tooltip("Are duplicates allowed to be added?")] + [SerializeField] protected SharedVariable m_AllowDuplicates = true; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + if (!m_AllowDuplicates.Value && m_StoreResult.Value.Contains(m_ResolvedGameObject)) { + return TaskStatus.Failure; + } + + var array = m_StoreResult.Value; + if (array == null) { + array = new GameObject[1]; + } else { + System.Array.Resize(ref array, array.Length + 1); + } + + m_StoreResult.Value = array; + return TaskStatus.Success; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/AddGameObjectToArray.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/AddGameObjectToArray.cs.meta new file mode 100644 index 0000000..e50a633 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/AddGameObjectToArray.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0e15921d659313647b2d4d2b3c76c6ec +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/AddGameObjectToList.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/AddGameObjectToList.cs new file mode 100644 index 0000000..ea25b08 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/AddGameObjectToList.cs @@ -0,0 +1,37 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.UnityObjects +{ + using Opsive.GraphDesigner.Runtime.Variables; + using System.Collections.Generic; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Adds the GameObject to the list.")] + [Shared.Utility.Category("Lists")] + public class AddGameObjectToList : TargetGameObjectAction + { + [Tooltip("The list of possible GameObjects.")] + [RequireShared] [SerializeField] protected SharedVariable> m_StoreResult; + [Tooltip("Are duplicates allowed to be added?")] + [SerializeField] protected SharedVariable m_AllowDuplicates = true; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + if (!m_AllowDuplicates.Value && m_StoreResult.Value.Contains(m_ResolvedGameObject)) { + return TaskStatus.Failure; + } + + m_StoreResult.Value.Add(m_ResolvedGameObject); + return TaskStatus.Success; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/AddGameObjectToList.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/AddGameObjectToList.cs.meta new file mode 100644 index 0000000..6c99f7c --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/AddGameObjectToList.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 771474f9417f55641b0b1a23028e05d0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/RandomGameObjectFromArray.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/RandomGameObjectFromArray.cs new file mode 100644 index 0000000..539c968 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/RandomGameObjectFromArray.cs @@ -0,0 +1,49 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.UnityObjects +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Sets a random GameObject value from the GameObject array.")] + [Shared.Utility.Category("Lists")] + public class RandomGameObjectFromArray : Action + { + [Tooltip("The list of possible GameObjects.")] + [SerializeField] protected SharedVariable m_GameObjects; + [Tooltip("The variable that should be set.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + [Tooltip("The seed of the random number generator. Set to 0 to disable.")] + [SerializeField] protected int m_Seed; + + /// + /// Callback when the behavior tree is initialized. + /// + public override void OnAwake() + { + if (m_Seed != 0) { + Random.InitState(m_Seed); + } + } + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + if (m_GameObjects.Value == null || m_GameObjects.Value.Length == 0) { + return TaskStatus.Failure; + } + + m_StoreResult.Value = m_GameObjects.Value[Random.Range(0, m_GameObjects.Value.Length)]; + return TaskStatus.Success; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/RandomGameObjectFromArray.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/RandomGameObjectFromArray.cs.meta new file mode 100644 index 0000000..cf00752 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/RandomGameObjectFromArray.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a32475ebd3e6d3145bd238c01607ea15 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/RandomGameObjectFromList.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/RandomGameObjectFromList.cs new file mode 100644 index 0000000..768ec3a --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/RandomGameObjectFromList.cs @@ -0,0 +1,50 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.UnityObjects +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + using System.Collections.Generic; + + [Opsive.Shared.Utility.Description("Sets a random GameObject value from the GameObject list.")] + [Shared.Utility.Category("Lists")] + public class RandomGameObjectFromList : Action + { + [Tooltip("The list of possible GameObjects.")] + [SerializeField] protected SharedVariable> m_GameObjects; + [Tooltip("The variable that should be set.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + [Tooltip("The seed of the random number generator. Set to 0 to disable.")] + [SerializeField] protected int m_Seed; + + /// + /// Callback when the behavior tree is initialized. + /// + public override void OnAwake() + { + if (m_Seed != 0) { + Random.InitState(m_Seed); + } + } + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + if (m_GameObjects.Value == null || m_GameObjects.Value.Count == 0) { + return TaskStatus.Failure; + } + + m_StoreResult.Value = m_GameObjects.Value[Random.Range(0, m_GameObjects.Value.Count)]; + return TaskStatus.Success; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/RandomGameObjectFromList.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/RandomGameObjectFromList.cs.meta new file mode 100644 index 0000000..f02d940 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/RandomGameObjectFromList.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b7809ab5aee37184c9a3f0c4b013ab0a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/RemoveGameObjectFromArray.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/RemoveGameObjectFromArray.cs new file mode 100644 index 0000000..85bcec0 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/RemoveGameObjectFromArray.cs @@ -0,0 +1,57 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.UnityObjects +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Removes the GameObject from the array.")] + [Shared.Utility.Category("Lists")] + public class RemoveGameObjectFromArray : TargetGameObjectAction + { + [Tooltip("The list of possible GameObjects.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + var array = m_StoreResult.Value; + if (array == null) { + return TaskStatus.Failure; + } + + // Find the index of the GameObject to remove. + var indexToRemove = -1; + for (int i = 0; i < array.Length; i++) { + if (array[i] == m_ResolvedGameObject) { + indexToRemove = i; + break; + } + } + if (indexToRemove == -1) { + return TaskStatus.Failure; + } + + // Create a new array with the GameObject removed. + var newArray = new GameObject[array.Length - 1]; + for (int i = 0, j = 0; i < array.Length; ++i) { + if (i != indexToRemove) { + newArray[j] = array[i]; + ++j; + } + } + + m_StoreResult.Value = newArray; + return TaskStatus.Success; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/RemoveGameObjectFromArray.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/RemoveGameObjectFromArray.cs.meta new file mode 100644 index 0000000..d23881a --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/RemoveGameObjectFromArray.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 29d1b655a839c324c9ca4b12f3af0351 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/RemoveGameObjectFromList.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/RemoveGameObjectFromList.cs new file mode 100644 index 0000000..e47c525 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/RemoveGameObjectFromList.cs @@ -0,0 +1,31 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.UnityObjects +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using System.Collections.Generic; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Removes the GameObject from the list.")] + [Shared.Utility.Category("Lists")] + public class RemoveGameObjectFromList : TargetGameObjectAction + { + [Tooltip("The list of possible GameObjects.")] + [RequireShared] [SerializeField] protected SharedVariable> m_StoreResult; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + return m_StoreResult.Value.Remove(m_ResolvedGameObject) ? TaskStatus.Success : TaskStatus.Failure; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/RemoveGameObjectFromList.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/RemoveGameObjectFromList.cs.meta new file mode 100644 index 0000000..a36532f --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/RemoveGameObjectFromList.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 89e178d0be1b41b4b933d144dc32aef1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/SelectGameObjectFromArray.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/SelectGameObjectFromArray.cs new file mode 100644 index 0000000..4324a43 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/SelectGameObjectFromArray.cs @@ -0,0 +1,39 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.UnityObjects +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Selects the GameObject from the array.")] + [Shared.Utility.Category("Lists")] + public class SelectGameObjectFromArray : Action + { + [Tooltip("The list of possible GameObjects.")] + [SerializeField] protected SharedVariable m_GameObjects; + [Tooltip("The index of the GameObject that should be selected.")] + [SerializeField] protected SharedVariable m_ElementIndex; + [Tooltip("The selected GameObject.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + if (m_GameObjects.Value == null || m_ElementIndex.Value < 0 || m_ElementIndex.Value > m_GameObjects.Value.Length) { + return TaskStatus.Failure; + } + + m_StoreResult.Value = m_GameObjects.Value[m_ElementIndex.Value]; + return TaskStatus.Success; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/SelectGameObjectFromArray.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/SelectGameObjectFromArray.cs.meta new file mode 100644 index 0000000..2126f83 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/SelectGameObjectFromArray.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d082de8064bdd7c4dada3c5a48e46fef +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/SelectGameObjectFromList.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/SelectGameObjectFromList.cs new file mode 100644 index 0000000..7fedc0c --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/SelectGameObjectFromList.cs @@ -0,0 +1,40 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.UnityObjects +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using System.Collections.Generic; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Selects the GameObject from the list.")] + [Shared.Utility.Category("Lists")] + public class SelectGameObjectFromList : Action + { + [Tooltip("The list of possible GameObjects.")] + [SerializeField] protected SharedVariable> m_GameObjects; + [Tooltip("The index of the GameObject that should be selected.")] + [SerializeField] protected SharedVariable m_ElementIndex; + [Tooltip("The selected GameObject.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + if (m_GameObjects.Value == null || m_ElementIndex.Value < 0 || m_ElementIndex.Value > m_GameObjects.Value.Count) { + return TaskStatus.Failure; + } + + m_StoreResult.Value = m_GameObjects.Value[m_ElementIndex.Value]; + return TaskStatus.Success; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/SelectGameObjectFromList.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/SelectGameObjectFromList.cs.meta new file mode 100644 index 0000000..9646ef7 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/IList/SelectGameObjectFromList.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e0dab44acdb589c4a8d2966c9ddc73a0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Idle.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Idle.cs new file mode 100644 index 0000000..e501392 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Idle.cs @@ -0,0 +1,96 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.GraphDesigner.Runtime; + using Unity.Entities; + using Unity.Burst; + using UnityEngine; + + /// + /// A node representation of the idle task. + /// + [NodeIcon("fc4d1b83384913b4abfbd8455db6df5b", "79a6985a753bb244fb5b32dc0f26addb")] + [Opsive.Shared.Utility.Description("Returns a TaskStatus of running. The task will only stop when interrupted or a conditional abort is triggered.")] + public class Idle : ECSActionTask + { + /// + /// The type of tag that should be enabled when the task is running. + /// + public override ComponentType Flag { get => typeof(IdleFlag); } + + /// + /// Returns a new TBufferElement for use by the system. + /// + /// A new TBufferElement for use by the system. + public override IdleComponent GetBufferElement() + { + return new IdleComponent() { + Index = RuntimeIndex + }; + } + } + + /// + /// The DOTS data structure for the Idle class. + /// + public struct IdleComponent : IBufferElementData + { + [Tooltip("The index of the node.")] + public ushort Index; + } + + /// + /// A DOTS tag indicating when a Idle node is active. + /// + public struct IdleFlag : IComponentData, IEnableableComponent { } + + /// + /// Runs the Idle logic. + /// + [DisableAutoCreation] + public partial struct IdleTaskSystem : ISystem + { + /// + /// Creates the job. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + var query = SystemAPI.QueryBuilder().WithAllRW().WithAll().Build(); + state.Dependency = new IdleJob().ScheduleParallel(query, state.Dependency); + } + + /// + /// Job which executes the task logic. + /// + [BurstCompile] + private partial struct IdleJob : IJobEntity + { + /// + /// Executes the idle logic. + /// + /// An array of TaskComponents. + /// An array of IdleComponents. + [BurstCompile] + public void Execute(ref DynamicBuffer taskComponents, ref DynamicBuffer idleComponents) + { + for (int i = 0; i < idleComponents.Length; ++i) { + var idleComponent = idleComponents[i]; + var taskComponent = taskComponents[idleComponent.Index]; + if (taskComponent.Status == TaskStatus.Queued) { + taskComponent.Status = TaskStatus.Running; + taskComponents[idleComponent.Index] = taskComponent; + } + } + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Idle.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Idle.cs.meta new file mode 100644 index 0000000..4b8f4a0 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Idle.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3cbbfc0d48db475498ad454651507929 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Log.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Log.cs new file mode 100644 index 0000000..5a96987 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Log.cs @@ -0,0 +1,34 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + /// + /// Logs the specified string. + /// + [NodeIcon("c97bee71424b3e247a161d1279643506", "138439e3588de5d449b7949d68d32ad8")] + [Opsive.Shared.Utility.Description("A simple task which will output the specified text and return success. It can be used for debugging.")] + public class Log : Action + { + [Tooltip("The string that should be outputted to the console.")] + [SerializeField] protected SharedVariable m_Text; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + Debug.Log(m_Text.Value); + return TaskStatus.Success; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Log.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Log.cs.meta new file mode 100644 index 0000000..3e13be7 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Log.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 74a01e8c621648b44bb6cf0cff363e59 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/LogValue.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/LogValue.cs new file mode 100644 index 0000000..74f9d33 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/LogValue.cs @@ -0,0 +1,38 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + /// + /// Logs the specified value. + /// + [NodeIcon("c97bee71424b3e247a161d1279643506", "138439e3588de5d449b7949d68d32ad8")] + public class LogValue : Action + { + [Tooltip("The value that should be outputted to the console.")] + [RequireShared] [SerializeField] protected SharedVariable m_Value; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + if (m_Value == null || m_Value.Scope == SharedVariable.SharingScope.Empty) { + Debug.LogWarning("Warning: The LogValue.Value variable must be set."); + return TaskStatus.Failure; + } + + Debug.Log(m_Value.GetValue()); + return TaskStatus.Success; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/LogValue.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/LogValue.cs.meta new file mode 100644 index 0000000..e3c49bd --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/LogValue.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0e6b3f8ede31f634ea1aa5727a7df673 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math.meta new file mode 100644 index 0000000..7280262 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7177abfd9732b2d45aec5e96e4415d68 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/BoolFlip.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/BoolFlip.cs new file mode 100644 index 0000000..26acbdd --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/BoolFlip.cs @@ -0,0 +1,31 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Math +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Flips the value of the boolean.")] + [Shared.Utility.Category("Math")] + public class BoolFlip : Action + { + [Tooltip("The bool that should be flipped.")] + [SerializeField] protected SharedVariable m_Bool; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + m_Bool.Value = !m_Bool.Value; + return TaskStatus.Success; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/BoolFlip.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/BoolFlip.cs.meta new file mode 100644 index 0000000..e0dfedc --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/BoolFlip.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a6654554de66a1340bff69fd22ffcacf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/BoolOperator.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/BoolOperator.cs new file mode 100644 index 0000000..1ce972a --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/BoolOperator.cs @@ -0,0 +1,61 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Math +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Performs a math operation on the two booleans.")] + [Shared.Utility.Category("Math")] + public class BoolOperator : Action + { + /// + /// Specifies the type of bool operation that should be performed. + /// + protected enum Operation + { + AND, // Returns the AND between two booleans. + OR, // Returns the OR between two booleans. + NAND, // Returns the NAND between two booleans. + XOR, // Returns the XOR between two booleans. + } + + [Tooltip("The operation to perform.")] + [SerializeField] protected SharedVariable m_Operation; + [Tooltip("The first boolean.")] + [SerializeField] protected SharedVariable m_Bool1; + [Tooltip("The second boolean.")] + [SerializeField] protected SharedVariable m_Bool2; + [Tooltip("The variable to store the result.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + switch (m_Operation.Value) { + case Operation.AND: + m_StoreResult.Value = m_Bool1.Value && m_Bool2.Value; + break; + case Operation.OR: + m_StoreResult.Value = m_Bool1.Value || m_Bool2.Value; + break; + case Operation.NAND: + m_StoreResult.Value = !(m_Bool1.Value && m_Bool2.Value); + break; + case Operation.XOR: + m_StoreResult.Value = (m_Bool1.Value ^ m_Bool2.Value); + break; + } + return TaskStatus.Success; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/BoolOperator.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/BoolOperator.cs.meta new file mode 100644 index 0000000..3f2fd93 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/BoolOperator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bf243997f53145143915ba48268817b4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/FloatOperator.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/FloatOperator.cs new file mode 100644 index 0000000..c57f03b --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/FloatOperator.cs @@ -0,0 +1,73 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Math +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Performs a math operation on the two floats.")] + [Shared.Utility.Category("Math")] + public class FloatOperator : Action + { + /// + /// Specifies the type of float operation that should be performed. + /// + protected enum Operation + { + Add, // Returns the addition between two floats. + Subtract, // Returns the division between two floats. + Multiply, // Returns the multiplication between two floats. + Divide, // Returns the division between two floats. + Modulo, // Returns the modulo between two floats. + Min, // Returns the minimum of two floats. + Max, // Returns the maximum of two floats. + } + + [Tooltip("The operation to perform.")] + [SerializeField] protected SharedVariable m_Operation; + [Tooltip("The first float.")] + [SerializeField] protected SharedVariable m_Float1; + [Tooltip("The second float.")] + [SerializeField] protected SharedVariable m_Float2; + [Tooltip("The variable to store the result.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + switch (m_Operation.Value) { + case Operation.Add: + m_StoreResult.Value = m_Float1.Value + m_Float2.Value; + break; + case Operation.Subtract: + m_StoreResult.Value = m_Float1.Value - m_Float2.Value; + break; + case Operation.Multiply: + m_StoreResult.Value = m_Float1.Value * m_Float2.Value; + break; + case Operation.Divide: + m_StoreResult.Value = m_Float1.Value / m_Float2.Value; + break; + case Operation.Modulo: + m_StoreResult.Value = m_Float1.Value % m_Float2.Value; + break; + case Operation.Min: + m_StoreResult.Value = Mathf.Min(m_Float1.Value, m_Float2.Value); + break; + case Operation.Max: + m_StoreResult.Value = Mathf.Max(m_Float1.Value, m_Float2.Value); + break; + } + return TaskStatus.Success; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/FloatOperator.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/FloatOperator.cs.meta new file mode 100644 index 0000000..244aa0d --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/FloatOperator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fd85a074520c85b4aac9a2e02a37fe47 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/IntOperator.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/IntOperator.cs new file mode 100644 index 0000000..0ddfc8f --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/IntOperator.cs @@ -0,0 +1,73 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Math +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Performs a math operation on the two integers.")] + [Shared.Utility.Category("Math")] + public class IntOperator : Action + { + /// + /// Specifies the type of int operation that should be performed. + /// + protected enum Operation + { + Add, // Returns the addition between two integers. + Subtract, // Returns the division between two integers. + Multiply, // Returns the multiplication between two integers. + Divide, // Returns the division between two integers. + Modulo, // Returns the modulo between two integers. + Min, // Returns the minimum of two integers. + Max, // Returns the maximum of two integers. + } + + [Tooltip("The operation to perform.")] + [SerializeField] protected SharedVariable m_Operation; + [Tooltip("The first integer.")] + [SerializeField] protected SharedVariable m_Integer1; + [Tooltip("The second integer.")] + [SerializeField] protected SharedVariable m_Integer2; + [Tooltip("The variable to store the result.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + switch (m_Operation.Value) { + case Operation.Add: + m_StoreResult.Value = m_Integer1.Value + m_Integer2.Value; + break; + case Operation.Subtract: + m_StoreResult.Value = m_Integer1.Value - m_Integer2.Value; + break; + case Operation.Multiply: + m_StoreResult.Value = m_Integer1.Value * m_Integer2.Value; + break; + case Operation.Divide: + m_StoreResult.Value = m_Integer1.Value / m_Integer2.Value; + break; + case Operation.Modulo: + m_StoreResult.Value = m_Integer1.Value % m_Integer2.Value; + break; + case Operation.Min: + m_StoreResult.Value = Mathf.Min(m_Integer1.Value, m_Integer2.Value); + break; + case Operation.Max: + m_StoreResult.Value = Mathf.Max(m_Integer1.Value, m_Integer2.Value); + break; + } + return TaskStatus.Success; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/IntOperator.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/IntOperator.cs.meta new file mode 100644 index 0000000..25b23e9 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/IntOperator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 77d11b9520f296b43a19d4a987844d73 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/RandomBool.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/RandomBool.cs new file mode 100644 index 0000000..b74c7f3 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/RandomBool.cs @@ -0,0 +1,45 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Tasks.Actions.Math +{ + using Opsive.BehaviorDesigner.Runtime.Tasks; + using Opsive.BehaviorDesigner.Runtime.Tasks.Actions; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Tooltip("Returns a random bool value.")] + [Shared.Utility.Category("Math")] + public class RandomBool : Action + { + [Tooltip("The stored random bool value.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + [Tooltip("The seed of the random number generator. Set to 0 to disable.")] + [SerializeField] protected int m_Seed; + + /// + /// Callback when the behavior tree is initialized. + /// + public override void OnAwake() + { + if (m_Seed != 0) { + Random.InitState(m_Seed); + } + } + + /// + /// Executes the task logic. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + m_StoreResult.Value = Random.value > 0.5; + return base.OnUpdate(); + } + + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/RandomBool.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/RandomBool.cs.meta new file mode 100644 index 0000000..e923b00 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/RandomBool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e39f6d31610d07b4ca1c977ce86198bd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/RandomFloat.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/RandomFloat.cs new file mode 100644 index 0000000..5b59095 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/RandomFloat.cs @@ -0,0 +1,49 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Tasks.Actions.Math +{ + using Opsive.BehaviorDesigner.Runtime.Tasks; + using Opsive.BehaviorDesigner.Runtime.Tasks.Actions; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Tooltip("Returns a random float between the specified values (inclusive).")] + [Shared.Utility.Category("Math")] + public class RandomFloat : Action + { + [Tooltip("The minimum float value (inclusive).")] + [SerializeField] protected SharedVariable m_MinimumFloat; + [Tooltip("The maximum float value (inclusive).")] + [SerializeField] protected SharedVariable m_MaximumFloat; + [Tooltip("The stored random float value.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + [Tooltip("The seed of the random number generator. Set to 0 to disable.")] + [SerializeField] protected int m_Seed; + + /// + /// Callback when the behavior tree is initialized. + /// + public override void OnAwake() + { + if (m_Seed != 0) { + Random.InitState(m_Seed); + } + } + + /// + /// Executes the task logic. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + m_StoreResult.Value = Random.Range(m_MinimumFloat.Value, m_MaximumFloat.Value); + return base.OnUpdate(); + } + + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/RandomFloat.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/RandomFloat.cs.meta new file mode 100644 index 0000000..a6d1b20 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/RandomFloat.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e4cd0328bf01f2a46a89268dcaf0cd26 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/RandomInteger.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/RandomInteger.cs new file mode 100644 index 0000000..1d3bc24 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/RandomInteger.cs @@ -0,0 +1,49 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Tasks.Actions.Math +{ + using Opsive.BehaviorDesigner.Runtime.Tasks; + using Opsive.BehaviorDesigner.Runtime.Tasks.Actions; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Tooltip("Returns a random integer between the specified values (inclusive).")] + [Shared.Utility.Category("Math")] + public class RandomInteger : Action + { + [Tooltip("The minimum integer value (inclusive).")] + [SerializeField] protected SharedVariable m_MinimumInteger; + [Tooltip("The maximum integer value (inclusive).")] + [SerializeField] protected SharedVariable m_MaximumInteger; + [Tooltip("The stored random integer value.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + [Tooltip("The seed of the random number generator. Set to 0 to disable.")] + [SerializeField] protected int m_Seed; + + /// + /// Callback when the behavior tree is initialized. + /// + public override void OnAwake() + { + if (m_Seed != 0) { + Random.InitState(m_Seed); + } + } + + /// + /// Executes the task logic. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + m_StoreResult.Value = Random.Range(m_MinimumInteger.Value, m_MaximumInteger.Value); + return base.OnUpdate(); + } + + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/RandomInteger.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/RandomInteger.cs.meta new file mode 100644 index 0000000..4fdfd7c --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/RandomInteger.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bf8b675bf82b06f44a19056eedc9e3f6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetBool.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetBool.cs new file mode 100644 index 0000000..b1d351d --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetBool.cs @@ -0,0 +1,33 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Math +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Set the boolean value.")] + [Shared.Utility.Category("Math")] + public class SetBool : Action + { + [Tooltip("The bool value to set.")] + [SerializeField] protected SharedVariable m_Value; + [Tooltip("The variable that should be set.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + m_StoreResult.Value = m_Value.Value; + return TaskStatus.Success; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetBool.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetBool.cs.meta new file mode 100644 index 0000000..8aa6708 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetBool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 77b177a61d9c7c94889fe58326045014 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetFloat.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetFloat.cs new file mode 100644 index 0000000..3d24d1d --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetFloat.cs @@ -0,0 +1,33 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Math +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Set the float value.")] + [Shared.Utility.Category("Math")] + public class SetFloat : Action + { + [Tooltip("The float value to set.")] + [SerializeField] protected SharedVariable m_Value; + [Tooltip("The variable that should be set.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + m_StoreResult.Value = m_Value.Value; + return TaskStatus.Success; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetFloat.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetFloat.cs.meta new file mode 100644 index 0000000..ff8dbc3 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetFloat.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7114039f3b7a3ff439a901637ba04235 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetInt.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetInt.cs new file mode 100644 index 0000000..5fd97f6 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetInt.cs @@ -0,0 +1,32 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Math +{ + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Set the integer value.")] + [Shared.Utility.Category("Math")] + public class SetInt : Action + { + [Tooltip("The int value to set.")] + [SerializeField] protected SharedVariable m_Value; + [Tooltip("The variable that should be set.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + m_StoreResult.Value = m_Value.Value; + return TaskStatus.Success; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetInt.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetInt.cs.meta new file mode 100644 index 0000000..c0b7ae9 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetInt.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eed961f4064f9024f8e51b3ddb69020a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetString.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetString.cs new file mode 100644 index 0000000..afa3bae --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetString.cs @@ -0,0 +1,33 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Math +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Set the string value.")] + [Shared.Utility.Category("Math")] + public class SetString : Action + { + [Tooltip("The string value to set.")] + [SerializeField] protected SharedVariable m_Value; + [Tooltip("The variable that should be set.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + m_StoreResult.Value = m_Value.Value; + return TaskStatus.Success; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetString.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetString.cs.meta new file mode 100644 index 0000000..c7a1fdb --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetString.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 450ec74688a332e42a42173708a621c1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetVector2.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetVector2.cs new file mode 100644 index 0000000..cf92be8 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetVector2.cs @@ -0,0 +1,33 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Math +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Set the Vector2 value.")] + [Shared.Utility.Category("Math")] + public class SetVector2 : Action + { + [Tooltip("The Vector2 value to set.")] + [SerializeField] protected SharedVariable m_Value; + [Tooltip("The variable that should be set.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + m_StoreResult.Value = m_Value.Value; + return TaskStatus.Success; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetVector2.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetVector2.cs.meta new file mode 100644 index 0000000..05fe7ec --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetVector2.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1507af45b59e2d642a8372f952ef5bec +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetVector3.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetVector3.cs new file mode 100644 index 0000000..306721c --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetVector3.cs @@ -0,0 +1,33 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.Math +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Set the Vector3 value.")] + [Shared.Utility.Category("Math")] + public class SetVector3 : Action + { + [Tooltip("The Vector3 value to set.")] + [SerializeField] protected SharedVariable m_Value; + [Tooltip("The variable that should be set.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + m_StoreResult.Value = m_Value.Value; + return TaskStatus.Success; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetVector3.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetVector3.cs.meta new file mode 100644 index 0000000..8e67c42 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Math/SetVector3.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8fd35c62b935e674da0ed3b7d450a049 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/PerformInterruption.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/PerformInterruption.cs new file mode 100644 index 0000000..d321927 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/PerformInterruption.cs @@ -0,0 +1,160 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.BehaviorDesigner.Runtime.Utility; + using Opsive.GraphDesigner.Runtime; + using Unity.Entities; + using Unity.Burst; + using UnityEngine; + using Unity.Collections; + + [NodeIcon("7c0aba0d8377aac48966d8e3f817a2a8", "90105f40f82a30e45b08d150c1928950")] + [Opsive.Shared.Utility.Description("Performs the actual interruption. This will immediately stop the specified tasks from running and will return success or failure depending on the value of interrupt success.")] + public class PerformInterruption : ECSActionTask + { + [Tooltip("The task that should be interrupted.")] + [SerializeField] ILogicNode[] m_InterruptTasks; + [Tooltip("Should the interrupted task return success?")] + [SerializeField] bool m_InterruptSuccess; + + /// + /// The type of tag that should be enabled when the task is running. + /// + public override ComponentType Flag { get => typeof(PerformInterruptionFlag); } + + /// + /// Returns a new TBufferElement for use by the system. + /// + /// A new TBufferElement for use by the system. + public override PerformInterruptionComponent GetBufferElement() + { + if (m_InterruptTasks == null || m_InterruptTasks.Length == 0) { + UnityEngine.Debug.LogError("Error: At least one interrupt task must be specified."); + return new PerformInterruptionComponent(); + } + + var indicies = new ushort[m_InterruptTasks.Length]; + var nullTaskCount = 0; + for (int i = 0; i < m_InterruptTasks.Length; ++i) { + if (m_InterruptTasks[i] == null) { + nullTaskCount++; + continue; + } + indicies[i - nullTaskCount] = m_InterruptTasks[i].Index; + } + if (nullTaskCount > 0) { + System.Array.Resize(ref indicies, indicies.Length - nullTaskCount); + } + + var builder = new BlobBuilder(Allocator.Temp); + ref var root = ref builder.ConstructRoot(); + var indicesArray = builder.Allocate(ref root.Indicies, indicies.Length); + for (int i = 0; i < indicies.Length; i++) { + indicesArray[i] = indicies[i]; + } + var blobAsset = builder.CreateBlobAssetReference(Allocator.Persistent); + builder.Dispose(); + + return new PerformInterruptionComponent() { + Index = RuntimeIndex, + InterruptIndicies = blobAsset, + InterruptSuccess = m_InterruptSuccess + }; + } + + /// + /// Adds the IBufferElementData to the entity. + /// + /// The world that the entity exists in. + /// The entity that the IBufferElementData should be assigned to. + /// The GameObject that the entity is attached to. + /// The index of the element within the buffer. + public override int AddBufferElement(World world, Entity entity, GameObject gameObject) + { + var index = base.AddBufferElement(world, entity, gameObject); + ComponentUtility.AddInterruptComponents(world.EntityManager, entity); + return index; + } + } + + /// + /// The DOTS data structure for the PerformInterruption class. + /// + public struct PerformInterruptionComponent : IBufferElementData + { + [Tooltip("The index of the node.")] + [SerializeField] public ushort Index; + [Tooltip("The indicies of the tasks that should be interrupted.")] + [SerializeField] public BlobAssetReference InterruptIndicies; + [Tooltip("Should the interrupted tasks return success?")] + [SerializeField] public bool InterruptSuccess; + } + + /// + /// A DOTS flag indicating when a PerformInterruption node is active. + /// + public struct PerformInterruptionFlag : IComponentData, IEnableableComponent { } + + /// + /// Runs the PerformInterruption logic. + /// + [DisableAutoCreation] + public partial struct PerformInterruptionTaskSystem : ISystem + { + /// + /// Updates the logic. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + foreach (var (branchComponents, taskComponents, performInterruptionComponents, entity) in + SystemAPI.Query, DynamicBuffer, DynamicBuffer>().WithAll().WithEntityAccess()) { + for (int i = 0; i < performInterruptionComponents.Length; ++i) { + var performInterruptionComponent = performInterruptionComponents[i]; + var taskComponent = taskComponents[performInterruptionComponent.Index]; + + if (taskComponent.Status == TaskStatus.Queued) { + taskComponent.Status = TaskStatus.Success; + var taskComponentsBuffer = taskComponents; + taskComponentsBuffer[taskComponent.Index] = taskComponent; + + var branchComponentsBuffer = branchComponents; + for (int j = 0; j < performInterruptionComponent.InterruptIndicies.Value.Indicies.Length; ++j) { + var interruptTaskComponent = taskComponents[performInterruptionComponent.InterruptIndicies.Value.Indicies[j]]; + var interruptBranchComponent = branchComponents[interruptTaskComponent.BranchIndex]; + interruptBranchComponent.InterruptType = performInterruptionComponent.InterruptSuccess ? InterruptType.ImmediateSuccess : InterruptType.ImmediateFailure; + interruptBranchComponent.InterruptIndex = interruptTaskComponent.Index; + branchComponentsBuffer[interruptTaskComponent.BranchIndex] = interruptBranchComponent; + } + + state.EntityManager.SetComponentEnabled(entity, true); + } + } + } + } + + /// + /// The task has been destroyed. + /// + /// The current state of the system. + private void OnDestroy(ref SystemState state) + { + foreach (var performInterruptionComponents in SystemAPI.Query>()) { + for (int i = 0; i < performInterruptionComponents.Length; ++i) { + var performInterruptionComponent = performInterruptionComponents[i]; + if (performInterruptionComponent.InterruptIndicies.IsCreated) { + performInterruptionComponent.InterruptIndicies.Dispose(); + } + } + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/PerformInterruption.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/PerformInterruption.cs.meta new file mode 100644 index 0000000..1791c3f --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/PerformInterruption.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9407f1f7d7a4efc43928e2885fbd047d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/RestartBehaviorTree.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/RestartBehaviorTree.cs new file mode 100644 index 0000000..b8fc8dc --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/RestartBehaviorTree.cs @@ -0,0 +1,60 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions +{ + using Opsive.GraphDesigner.Runtime; + using System.Collections; + using UnityEngine; + + [NodeIcon("e0a8f1df788b6274a9a24003859dfa7e")] + [Opsive.Shared.Utility.Description("Restarts the specified behavior tree.")] + public class RestartBehaviorTree : TargetBehaviorTreeAction + { + private TaskStatus m_Status; + + /// + /// The task has started. + /// + public override void OnStart() + { + m_Status = TaskStatus.Queued; + } + + /// + /// Executes the task logic. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + // The coroutine has already been started if the status is not queued. + if (m_Status != TaskStatus.Queued) { + return m_Status; + } + + if (m_ResolvedBehaviorTree == null) { + return TaskStatus.Failure; + } + + m_Status = TaskStatus.Running; + StartCoroutine(RestartBehavior()); + return m_Status; + } + + /// + /// Restarts the behavior tree using a coroutine to allow structural changes. + /// + private IEnumerator RestartBehavior() + { + yield return new WaitForEndOfFrame(); + + m_Status = m_ResolvedBehaviorTree.RestartBehavior() ? TaskStatus.Success : TaskStatus.Failure; + } + + + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/RestartBehaviorTree.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/RestartBehaviorTree.cs.meta new file mode 100644 index 0000000..8f5b521 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/RestartBehaviorTree.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1240560819407764d95369a091d6f5e9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/ReturnStatus.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/ReturnStatus.cs new file mode 100644 index 0000000..bcb13a6 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/ReturnStatus.cs @@ -0,0 +1,121 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.GraphDesigner.Runtime; + using Unity.Entities; + using Unity.Burst; + using UnityEngine; + using System; + + /// + /// A node representation of the return status task. + /// + [Opsive.Shared.Utility.Description("The return status task will immediately return sucess or failure.")] + public class ReturnStatus : ECSActionTask, ICloneable + { + [Tooltip("Should a success status be returned? If false then failure will be returned.")] + [SerializeField] bool m_Success; + + public bool Success { get => m_Success; set => m_Success = value; } + + /// + /// The type of tag that should be enabled when the task is running. + /// + public override ComponentType Flag { get => typeof(ReturnStatusFlag); } + + /// + /// Returns a new TBufferElement for use by the system. + /// + /// A new TBufferElement for use by the system. + public override ReturnStatusComponent GetBufferElement() + { + return new ReturnStatusComponent() { + Index = RuntimeIndex, + Success = m_Success + }; + } + + /// + /// Creates a deep clone of the component. + /// + /// A deep clone of the component. + public object Clone() + { + var clone = Activator.CreateInstance(); + clone.Index = Index; + clone.ParentIndex = ParentIndex; + clone.SiblingIndex = SiblingIndex; + clone.Success = Success; + return clone; + } + } + + /// + /// The DOTS data structure for the ReturnStatus class. + /// + public struct ReturnStatusComponent : IBufferElementData + { + [Tooltip("The index of the node.")] + [SerializeField] ushort m_Index; + [Tooltip("Should a success status be returned? If false then failure will be returned.")] + [SerializeField] bool m_Success; + public ushort Index { get => m_Index; set => m_Index = value; } + public bool Success { get => m_Success; set => m_Success = value; } + } + + /// + /// A DOTS tag indicating when a ReturnStatus node is active. + /// + public struct ReturnStatusFlag : IComponentData, IEnableableComponent { } + + /// + /// Runs the ReturnStatus logic. + /// + [DisableAutoCreation] + public partial struct ReturnStatusTaskSystem : ISystem + { + /// + /// Creates the job. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + var query = SystemAPI.QueryBuilder().WithAllRW().WithAllRW().WithAll().Build(); + state.Dependency = new ReturnStatusJob().ScheduleParallel(query, state.Dependency); + } + + /// + /// Job which executes the task logic. + /// + [BurstCompile] + private partial struct ReturnStatusJob : IJobEntity + { + /// + /// Executes the return status logic. + /// + /// An array of TaskComponents. + /// An array of ReturnStatusComponents. + [BurstCompile] + public void Execute(ref DynamicBuffer taskComponents, ref DynamicBuffer returnStatusComponents) + { + for (int i = 0; i < returnStatusComponents.Length; ++i) { + var returnStatusComponent = returnStatusComponents[i]; + var taskComponent = taskComponents[returnStatusComponent.Index]; + if (taskComponent.Status != TaskStatus.Queued) { + continue; + } + taskComponent.Status = returnStatusComponent.Success ? TaskStatus.Success : TaskStatus.Failure; + taskComponents[returnStatusComponent.Index] = taskComponent; + } + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/ReturnStatus.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/ReturnStatus.cs.meta new file mode 100644 index 0000000..47d1b8d --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/ReturnStatus.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 837791748c4f57c4293429e8e94fd32c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/SendEvent.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/SendEvent.cs new file mode 100644 index 0000000..c79af29 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/SendEvent.cs @@ -0,0 +1,81 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using Opsive.Shared.Events; + using UnityEngine; + + /// + /// Executes the specified event. + /// + [NodeIcon("bde76446ddfbd234488e8d591bc75e2f", "6d03b96c0f79bee4ab2e14fc82aa0031")] + [Opsive.Shared.Utility.Description("Sends an event to the behavior tree, returns success after sending the event.")] + public class SendEvent : TargetBehaviorTreeAction + { + [Tooltip("The name of the event.")] + [SerializeField] protected SharedVariable m_EventName; + [Tooltip("Is the event a global event?")] + [SerializeField] protected SharedVariable m_GlobalEvent; + [Tooltip("Optionally specify a first argument to send.")] + [RequireShared] [SerializeField] protected SharedVariable m_Argument1; + [Tooltip("Optionally specify a second argument to send.")] + [RequireShared] [SerializeField] protected SharedVariable m_Argument2; + [Tooltip("Optionally specify a third argument to send.")] + [RequireShared] [SerializeField] protected SharedVariable m_Argument3; + + /// + /// Executes the event. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + if (m_ResolvedBehaviorTree == null) { + return TaskStatus.Failure; + } + + if (string.IsNullOrEmpty(m_EventName.Value)) { + Debug.LogError("Error: Unable to send event. The event name is empty."); + return TaskStatus.Failure; + } + + if (m_Argument1 == null || !m_Argument1.IsShared) { + if (m_GlobalEvent.Value) { + EventHandler.ExecuteEvent(m_EventName.Value); + } else { + EventHandler.ExecuteEvent(m_ResolvedBehaviorTree, m_EventName.Value); + } + } else { + if (m_Argument2 == null || !m_Argument2.IsShared) { + if (m_GlobalEvent.Value) { + EventHandler.ExecuteEvent(m_EventName.Value, m_Argument1.GetValue()); + } else { + EventHandler.ExecuteEvent(m_ResolvedBehaviorTree, m_EventName.Value, m_Argument1.GetValue()); + } + } else { + if (m_Argument3 == null || !m_Argument3.IsShared) { + if (m_GlobalEvent.Value) { + EventHandler.ExecuteEvent(m_EventName.Value, m_Argument1.GetValue(), m_Argument2.GetValue()); + } else { + EventHandler.ExecuteEvent(m_ResolvedBehaviorTree, m_EventName.Value, m_Argument1.GetValue(), m_Argument2.GetValue()); + } + } else { + if (m_GlobalEvent.Value) { + EventHandler.ExecuteEvent(m_EventName.Value, m_Argument1.GetValue(), m_Argument2.GetValue(), m_Argument3.GetValue()); + } else { + EventHandler.ExecuteEvent(m_ResolvedBehaviorTree, m_EventName.Value, m_Argument1.GetValue(), m_Argument2.GetValue(), m_Argument3.GetValue()); + } + } + } + } + + return TaskStatus.Success; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/SendEvent.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/SendEvent.cs.meta new file mode 100644 index 0000000..d9b5948 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/SendEvent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6af31db67c14aba458ffd11cd0b671aa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/SetSubtree.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/SetSubtree.cs new file mode 100644 index 0000000..99f3e8c --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/SetSubtree.cs @@ -0,0 +1,68 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions +{ + using Opsive.GraphDesigner.Runtime; + using System.Collections; + using UnityEngine; + + [NodeIcon("e0a8f1df788b6274a9a24003859dfa7e")] + [Opsive.Shared.Utility.Description("Sets the specified subtree.")] + public class SetSubtree : TargetBehaviorTreeAction + { + [Tooltip("The subtree that should be set.")] + [SerializeField] protected Subtree m_Subtree; + [Tooltip("Should the behavior tree be started after the subtree is set?")] + [SerializeField] protected bool m_StartBehavior = true; + + private TaskStatus m_Status; + + /// + /// The task has started. + /// + public override void OnStart() + { + m_Status = TaskStatus.Queued; + } + + /// + /// Executes the task logic. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + // The coroutine has already been started if the status is not queued. + if (m_Status != TaskStatus.Queued) { + return m_Status; + } + + if (m_ResolvedBehaviorTree == null) { + return TaskStatus.Failure; + } + + m_Status = TaskStatus.Running; + StartCoroutine(DoSetSubtree()); + return m_Status; + } + + /// + /// Sets the subtree using a coroutine to allow structural changes. + /// + private IEnumerator DoSetSubtree() + { + yield return new WaitForEndOfFrame(); + + m_ResolvedBehaviorTree.Subgraph = m_Subtree; + m_Status = TaskStatus.Success; + + if (m_StartBehavior) { + m_ResolvedBehaviorTree.StartBehavior(); + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/SetSubtree.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/SetSubtree.cs.meta new file mode 100644 index 0000000..0f25923 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/SetSubtree.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 881cf86206c0dfa458723d1cde9e0e13 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/StackedAction.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/StackedAction.cs new file mode 100644 index 0000000..6427a06 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/StackedAction.cs @@ -0,0 +1,20 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions +{ + using Opsive.GraphDesigner.Runtime; + + /// + /// The StackedAction task allows for multiple actions to be added to the same node. + /// + [NodeIcon("dacf20a036b1f5e41886d84ac4a47779", "2df1cb3efc025214cbab4df573bb3515")] + [Opsive.Shared.Utility.Description("Allows multiple action tasks to be added to a single node.")] + public class StackedAction : StackedTask, IAction + { + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/StackedAction.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/StackedAction.cs.meta new file mode 100644 index 0000000..558ca6d --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/StackedAction.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4342d213dec4aa5458c9e9969ef98fc7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/StartBehaviorTree.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/StartBehaviorTree.cs new file mode 100644 index 0000000..9fb9792 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/StartBehaviorTree.cs @@ -0,0 +1,58 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions +{ + using Opsive.GraphDesigner.Runtime; + using System.Collections; + using UnityEngine; + + [NodeIcon("e0a8f1df788b6274a9a24003859dfa7e")] + [Opsive.Shared.Utility.Description("Starts the specified behavior tree.")] + public class StartBehaviorTree : TargetBehaviorTreeAction + { + private TaskStatus m_Status; + + /// + /// The task has started. + /// + public override void OnStart() + { + m_Status = TaskStatus.Queued; + } + + /// + /// Executes the task logic. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + // The coroutine has already been started if the status is not queued. + if (m_Status != TaskStatus.Queued) { + return m_Status; + } + + if (m_ResolvedBehaviorTree == null || m_ResolvedBehaviorTree.IsActive()) { + return TaskStatus.Failure; + } + + m_Status = TaskStatus.Running; + StartCoroutine(StartBehavior()); + return m_Status; + } + + /// + /// Starts the behavior tree using a coroutine to allow structural changes. + /// + private IEnumerator StartBehavior() + { + yield return new WaitForEndOfFrame(); + + m_Status = m_ResolvedBehaviorTree.StartBehavior() ? TaskStatus.Success : TaskStatus.Failure; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/StartBehaviorTree.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/StartBehaviorTree.cs.meta new file mode 100644 index 0000000..a09c38a --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/StartBehaviorTree.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a308f84e10d3f9b4e89c16ea755e4120 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/StopBehaviorTree.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/StopBehaviorTree.cs new file mode 100644 index 0000000..635cf49 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/StopBehaviorTree.cs @@ -0,0 +1,32 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [NodeIcon("e0a8f1df788b6274a9a24003859dfa7e")] + [Opsive.Shared.Utility.Description("Stops the specified behavior tree.")] + public class StopBehaviorTree : TargetBehaviorTreeAction + { + [SerializeField] protected SharedVariable m_PauseBehaviorTree; + /// + /// Executes the task logic. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + if (m_ResolvedBehaviorTree == null || !m_ResolvedBehaviorTree.IsActive()) { + return TaskStatus.Failure; + } + + return m_ResolvedBehaviorTree.StopBehavior(m_PauseBehaviorTree.Value) ? TaskStatus.Success : TaskStatus.Failure; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/StopBehaviorTree.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/StopBehaviorTree.cs.meta new file mode 100644 index 0000000..4620ec3 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/StopBehaviorTree.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ff712b458703ec440a858c41edeca111 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/SubtreeReference.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/SubtreeReference.cs new file mode 100644 index 0000000..d985b38 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/SubtreeReference.cs @@ -0,0 +1,50 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + /// + /// Allows for subtrees to be loaded at runtime into the tree. + /// + [NodeIcon("e0a8f1df788b6274a9a24003859dfa7e")] + [Opsive.Shared.Utility.Description("Loads the specified subtrees in at runtime.")] + public class SubtreeReference : ActionNode, ISubtreeReference + { + [Tooltip("The subtrees that should be loaded.")] + [SubtreeListAttribute] + [SerializeField] protected Subtree[] m_Subtrees; + [Tooltip("The variables that should override the subtree variables.")] + [SharedVariableOverridesListAttribute] + [SerializeField] protected SharedVariableOverride[] m_Variables; + + public virtual Subtree[] Subtrees { get { return m_Subtrees; } } + + /// + /// A list of mapped SharedVariables. These variables can override the subtree. + /// + public virtual SharedVariableOverride[] SharedVariableOverrides { get => m_Variables; set => m_Variables = value; } + + /// + /// Performs any runtime operations to evaluate the array of subtrees that should be returned. + /// + /// The component that the node is attached to. + public virtual void EvaluateSubtrees(IGraphComponent graphComponent) { } + + /// + /// If the task exists at runtime then the subtree didn't load. Return failure. + /// + /// The failure TaskStatus. + public override TaskStatus OnUpdate() + { + return TaskStatus.Failure; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/SubtreeReference.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/SubtreeReference.cs.meta new file mode 100644 index 0000000..903ee47 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/SubtreeReference.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 176873898443d5643badfdcaa50ddfdb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/SubtreeReferenceSelector.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/SubtreeReferenceSelector.cs new file mode 100644 index 0000000..0be69e8 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/SubtreeReferenceSelector.cs @@ -0,0 +1,42 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions +{ + using Opsive.BehaviorDesigner.Runtime; + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + /// + /// Allows for subtrees to be loaded at runtime into the tree. + /// + [Opsive.Shared.Utility.Description("Selects a subtree based on the index value.")] + public class SubtreeReferenceSelector : SubtreeReference + { + [Tooltip("The index of the subtree that should be selected.")] + [SerializeField] protected SharedVariable m_Index; + + private Subtree[] m_Selection; + + public override Subtree[] Subtrees => m_Selection != null ? m_Selection : m_Subtrees; + + /// + /// Performs any runtime operations to evaluate the array of subtrees that should be returned. + /// + /// The component that the node is attached to. + public override void EvaluateSubtrees(IGraphComponent graphComponent) + { + if (m_Index.Value < 0 || m_Index.Value >= m_Subtrees.Length) { + return; + } + + m_Selection = new Subtree[] { m_Subtrees[m_Index.Value] }; + } + } +} + +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/SubtreeReferenceSelector.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/SubtreeReferenceSelector.cs.meta new file mode 100644 index 0000000..f232d21 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/SubtreeReferenceSelector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 501228e2e706ea841a290cb3863f6f38 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/TargetBehaviorTreeAction.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/TargetBehaviorTreeAction.cs new file mode 100644 index 0000000..5eb7289 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/TargetBehaviorTreeAction.cs @@ -0,0 +1,71 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions +{ + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + /// + /// A TaskObject Action task which implements the shared TargetGameObject/TreeUserID objects. + /// + public abstract class TargetBehaviorTreeAction : Action + { + [Tooltip("The GameObject of the target behavior tree. If the value is null the current GameObject will be used.")] + [SerializeField] protected SharedVariable m_TargetGameObject; + [Tooltip("The index of the tree if there are multiple behavior trees on the same GameObject.")] + [SerializeField] protected SharedVariable m_TreeIndex; + + protected BehaviorTree m_ResolvedBehaviorTree; + + /// + /// Initializes the task. + /// + public override void OnAwake() + { + m_TargetGameObject.OnValueChange += InitializeTarget; + m_TreeIndex.OnValueChange += InitializeTarget; + + InitializeTarget(); + } + + /// + /// Initializes the target behavior tree. + /// + protected virtual void InitializeTarget() + { + if (m_TargetGameObject.Value == null) { + m_ResolvedBehaviorTree = m_BehaviorTree; + } else { + var behaviorTrees = m_TargetGameObject.Value.GetComponents(); + if (behaviorTrees.Length == 1) { + m_ResolvedBehaviorTree = behaviorTrees[0]; + } else if (behaviorTrees.Length > 1) { + for (int i = 0; i < behaviorTrees.Length; ++i) { + if (behaviorTrees[i].Index == m_TreeIndex.Value) { + m_ResolvedBehaviorTree = behaviorTrees[i]; + break; + } + } + // If the UserID can't be found then use the first behavior tree. + if (m_ResolvedBehaviorTree == null) { + m_ResolvedBehaviorTree = behaviorTrees[0]; + } + } + } + } + + /// + /// The behavior tree has been destroyed. + /// + public override void OnDestroy() + { + m_TargetGameObject.OnValueChange -= InitializeTarget; + m_TreeIndex.OnValueChange -= InitializeTarget; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/TargetBehaviorTreeAction.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/TargetBehaviorTreeAction.cs.meta new file mode 100644 index 0000000..2df2a2d --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/TargetBehaviorTreeAction.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ea8fab3de7105aa4497485f5934c06d9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/TargetGameObjectAction.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/TargetGameObjectAction.cs new file mode 100644 index 0000000..2e7cebe --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/TargetGameObjectAction.cs @@ -0,0 +1,54 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions +{ + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + /// + /// A TaskObject Action task which returns the current GameObject if the target is null. + /// + public abstract class TargetGameObjectAction : Action + { + [Tooltip("The GameObject of the target behavior tree. If the value is null the current GameObject will be used.")] + [SerializeField] protected SharedVariable m_TargetGameObject; + + protected override GameObject gameObject => m_ResolvedGameObject; + protected override Transform transform => m_ResolvedTransform; + + protected GameObject m_ResolvedGameObject; + protected Transform m_ResolvedTransform; + + /// + /// Initializes the task. + /// + public override void OnAwake() + { + m_TargetGameObject.OnValueChange += InitializeTarget; + + InitializeTarget(); + } + + /// + /// Initializes the target GameObject. + /// + protected virtual void InitializeTarget() + { + m_ResolvedGameObject = (m_TargetGameObject.Value == null || m_TargetGameObject.Value.Equals(null)) ? m_GameObject : m_TargetGameObject.Value; + m_ResolvedTransform = m_ResolvedGameObject.transform; + } + + /// + /// The behavior tree has been destroyed. + /// + public override void OnDestroy() + { + m_TargetGameObject.OnValueChange -= InitializeTarget; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/TargetGameObjectAction.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/TargetGameObjectAction.cs.meta new file mode 100644 index 0000000..6fe0d18 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/TargetGameObjectAction.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3025700b92fd09d4d86b26d7213de9ab +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/UnityObjects.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/UnityObjects.meta new file mode 100644 index 0000000..8401830 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/UnityObjects.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1e88e229aee9deb4596b688718c14806 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/UnityObjects/SetEnabled.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/UnityObjects/SetEnabled.cs new file mode 100644 index 0000000..a880bfd --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/UnityObjects/SetEnabled.cs @@ -0,0 +1,36 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.UnityObjects +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Enables or disables the specified MonoBehaviour.")] + [Shared.Utility.Category("Unity")] + public class SetEnabled : Action + { + [Tooltip("Should the MonoBehaviour be enabled?")] + [SerializeField] protected SharedVariable m_Enable; + [Tooltip("The MonoBehaviour that should be enabled or disabled.")] + [SerializeField] protected SharedVariable m_MonoBehaviour; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + if (m_MonoBehaviour.Value == null) { + return TaskStatus.Failure; + } + m_MonoBehaviour.Value.enabled = m_Enable.Value; + return TaskStatus.Success; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/UnityObjects/SetEnabled.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/UnityObjects/SetEnabled.cs.meta new file mode 100644 index 0000000..8b25396 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/UnityObjects/SetEnabled.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8f30ae346f704e446942d6cdb1c4adfa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/UnityObjects/SetGameObject.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/UnityObjects/SetGameObject.cs new file mode 100644 index 0000000..dd3f513 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/UnityObjects/SetGameObject.cs @@ -0,0 +1,33 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.UnityObjects +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Set the GameObject value.")] + [Shared.Utility.Category("Unity")] + public class SetGameObject : TargetGameObjectAction + { + [Tooltip("The variable that should be set.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoreResult; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + InitializeTarget(); + + m_StoreResult.Value = m_ResolvedGameObject; + return TaskStatus.Success; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/UnityObjects/SetGameObject.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/UnityObjects/SetGameObject.cs.meta new file mode 100644 index 0000000..a622403 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/UnityObjects/SetGameObject.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: acfe874544935e64f80eeb34681141c1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/UnityObjects/WaitForAnimatorState.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/UnityObjects/WaitForAnimatorState.cs new file mode 100644 index 0000000..c41308e --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/UnityObjects/WaitForAnimatorState.cs @@ -0,0 +1,58 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions.UnityObjects +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Returns success as soon as the current Animator state ends.")] + [Shared.Utility.Category("Unity")] + public class WaitForAnimatorState : TargetGameObjectAction + { + [Tooltip("The layer to wait for the state on.")] + public SharedVariable m_Layer; + + private Animator m_Animator; + private int m_StateHash; + + /// + /// Initializes the default values. + /// + public override void OnAwake() + { + base.OnAwake(); + + m_Animator = gameObject.GetComponent(); + } + + /// + /// Caches the Animator state. + /// + public override void OnStart() + { + m_StateHash = (m_Animator.IsInTransition(m_Layer.Value) ? m_Animator.GetNextAnimatorStateInfo(m_Layer.Value) : m_Animator.GetCurrentAnimatorStateInfo(m_Layer.Value)).fullPathHash; + } + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + if (m_Animator.IsInTransition(m_Layer.Value)) { + return TaskStatus.Running; + } + var currentState = m_Animator.GetCurrentAnimatorStateInfo(m_Layer.Value).fullPathHash; + if (currentState != m_StateHash) { + return TaskStatus.Success; + } + return TaskStatus.Running; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/UnityObjects/WaitForAnimatorState.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/UnityObjects/WaitForAnimatorState.cs.meta new file mode 100644 index 0000000..0de3894 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/UnityObjects/WaitForAnimatorState.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7f6c915175357ab449604315406c51bb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Wait.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Wait.cs new file mode 100644 index 0000000..1cf9460 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Wait.cs @@ -0,0 +1,383 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Actions +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.BehaviorDesigner.Runtime.Utility; + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using Opsive.Shared.Utility; + using Unity.Entities; + using Unity.Burst; + using UnityEngine; + using System; + + [NodeIcon("b4b59e888607422409f1efa599af34ae", "e1cb9cb566a90fb4489bf31465b99747")] + [Opsive.Shared.Utility.Description("Wait a specified amount of time. The task will return running until the task is done waiting. It will return success after the wait time has elapsed.")] + public class Wait : ECSActionTask, ICloneable, IPausableTask, ISavableTask + { + [Tooltip("The amount of time to wait (in seconds).")] + [SerializeField] float m_Duration; + [Tooltip("Should the wait duration be randomized?")] + [SerializeField] bool m_RandomDuration; + [Tooltip("The seed of the random number generator. Set to 0 to use the entity index as the seed.")] + [SerializeField] uint m_Seed; + [Tooltip("The wait duration range if random wait is enabled.")] + [SerializeField] RangeFloat m_RandomDurationRange; + + private ushort m_ComponentIndex; + + public float Duration { get => m_Duration; set => m_Duration = value; } + public bool RandomDuration { get => m_RandomDuration; set => m_RandomDuration = value; } + public uint Seed { get => m_Seed; set => m_Seed = value; } + public RangeFloat RandomDurationRange { get => m_RandomDurationRange; set => m_RandomDurationRange = value; } + + /// + /// Resets the task to its default values. + /// + public override void Reset() { m_Duration = m_RandomDurationRange.Min = m_RandomDurationRange.Max = 1; m_RandomDuration = false; m_Seed = 0; } + + /// + /// The type of tag that should be enabled when the task is running. + /// + public override ComponentType Flag { get => typeof(WaitFlag); } + + /// + /// Returns a new TBufferElement for use by the system. + /// + /// A new TBufferElement for use by the system. + public override WaitComponent GetBufferElement() + { + return new WaitComponent() { + Index = RuntimeIndex, + Duration = m_Duration, + RandomDuration = m_RandomDuration, + RandomDurationRange = m_RandomDurationRange, + Seed = m_Seed, + }; + } + + /// + /// Adds the IBufferElementData to the entity. + /// + /// The world that the entity exists in. + /// The entity that the IBufferElementData should be assigned to. + /// The GameObject that the entity is attached to. + /// The index of the element within the buffer. + public override int AddBufferElement(World world, Entity entity, GameObject gameObject) + { + m_ComponentIndex = (ushort)base.AddBufferElement(world, entity, gameObject); + return m_ComponentIndex; + } + + /// + /// Specifies the type of reflection that should be used to save the task. + /// + /// The index of the sub-task. This is used for the task set allowing each contained task to have their own save type. + public MemberVisibility GetSaveReflectionType(int index) { return MemberVisibility.None; } + + /// + /// The task has been paused. + /// + /// The DOTS world. + /// The DOTS entity. + public void Pause(World world, Entity entity) + { + var waitComponents = world.EntityManager.GetBuffer(entity); + var waitComponent = waitComponents[m_ComponentIndex]; + waitComponent.PauseTime = Time.time; + var waitComponentBuffer = waitComponents; + waitComponentBuffer[m_ComponentIndex] = waitComponent; + } + + /// + /// The task has been resumed. + /// + /// The DOTS world. + /// The DOTS entity. + public void Resume(World world, Entity entity) + { + var waitComponents = world.EntityManager.GetBuffer(entity); + var waitComponent = waitComponents[m_ComponentIndex]; + waitComponent.StartTime += (Time.time - waitComponent.PauseTime); + waitComponent.PauseTime = 0; + var waitComponentBuffer = waitComponents; + waitComponentBuffer[m_ComponentIndex] = waitComponent; + } + + /// + /// Returns the current task state. + /// + /// The DOTS world. + /// The DOTS entity. + /// The current task state. + public object Save(World world, Entity entity) + { + var waitComponents = world.EntityManager.GetBuffer(entity); + var waitComponent = waitComponents[m_ComponentIndex]; + + // Save the unique data. + return new object[] { waitComponent.WaitDuration, Time.time - waitComponent.StartTime }; + } + + /// + /// Loads the previous task state. + /// + /// The previous task state. + /// The DOTS world. + /// The DOTS entity. + public void Load(object saveData, World world, Entity entity) + { + var waitComponents = world.EntityManager.GetBuffer(entity); + var waitComponent = waitComponents[m_ComponentIndex]; + + // saveData is the wait duration and the elapsed amount of time. + var data = (object[])saveData; + waitComponent.WaitDuration = (double)data[0]; + waitComponent.StartTime = Time.time - (double)data[1]; + waitComponents[m_ComponentIndex] = waitComponent; + } + + /// + /// Creates a deep clone of the component. + /// + /// A deep clone of the component. + public object Clone() + { + var clone = Activator.CreateInstance(); + clone.Index = Index; + clone.ParentIndex = ParentIndex; + clone.SiblingIndex = SiblingIndex; + clone.Duration = Duration; + clone.RandomDuration = RandomDuration; + clone.Seed = Seed; + clone.RandomDurationRange = RandomDurationRange; + return clone; + } + } + + /// + /// The DOTS data structure for the Wait struct. + /// + public struct WaitComponent : IBufferElementData + { + [Tooltip("The index of the node.")] + public ushort Index; + [Tooltip("The amount of time the task should wait.")] + public float Duration; + [Tooltip("Should the wait duration be randomized?")] + public bool RandomDuration; + [Tooltip("The wait duration range if random wait is enabled.")] + public RangeFloat RandomDurationRange; + [Tooltip("The amount of time the task should wait.")] + public double WaitDuration; + [Tooltip("The real time the task started to wait.")] + public double StartTime; + [Tooltip("The seed of the random number generator.")] + public uint Seed; + [Tooltip("The random number generator for the task.")] + public Unity.Mathematics.Random RandomNumberGenerator; + [Tooltip("The time the task was paused.")] + public double PauseTime; + } + + /// + /// A DOTS tag indicating when a Wait node is active. + /// + public struct WaitFlag : IComponentData, IEnableableComponent { } + + /// + /// Runs the Wait logic. + /// + [DisableAutoCreation] + public partial struct WaitTaskSystem : ISystem + { + /// + /// Updates the logic. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + var query = SystemAPI.QueryBuilder().WithAllRW().WithAllRW().WithAll().Build(); + state.Dependency = new WaitJob() { ElapsedTime = SystemAPI.Time.ElapsedTime }.ScheduleParallel(query, state.Dependency); + } + + /// + /// Waits for the specified amount of time. + /// + [BurstCompile] + private partial struct WaitJob : IJobEntity + { + [Tooltip("The current ElapsedTime.")] + public double ElapsedTime; + + /// + /// Updates the logic. + /// + /// The entity. + /// An array of TaskComponents. + /// An array of WaitComponents. + [BurstCompile] + public void Execute(Entity entity, ref DynamicBuffer taskComponents, ref DynamicBuffer waitComponents) + { + for (int i = 0; i < waitComponents.Length; ++i) { + var waitComponent = waitComponents[i]; + var taskComponent = taskComponents[waitComponent.Index]; + if (taskComponent.Status == TaskStatus.Queued) { + taskComponent.Status = TaskStatus.Running; + waitComponent.StartTime = ElapsedTime; + + if (waitComponent.RandomDuration) { + // Generate a new random number seed for each entity. + if (waitComponent.RandomNumberGenerator.state == 0) { + waitComponent.RandomNumberGenerator = Unity.Mathematics.Random.CreateFromIndex(waitComponent.Seed != 0 ? waitComponent.Seed : (uint)entity.Index); + } + + waitComponent.WaitDuration = waitComponent.RandomNumberGenerator.NextDouble(waitComponent.RandomDurationRange.Min, waitComponent.RandomDurationRange.Max); + } else { + waitComponent.WaitDuration = waitComponent.Duration; + } + + waitComponents[i] = waitComponent; + } + if (taskComponent.Status == TaskStatus.Running) { + if (waitComponent.StartTime + waitComponent.WaitDuration <= ElapsedTime) { + taskComponent.Status = TaskStatus.Success; + } + } + taskComponents[waitComponent.Index] = taskComponent; + } + } + } + } + + [NodeIcon("b4b59e888607422409f1efa599af34ae", "e1cb9cb566a90fb4489bf31465b99747")] + [Opsive.Shared.Utility.Description("Wait a specified amount of time. The task will return running until the task is done waiting. It will return success after the wait time has elapsed. Uses the GameObject workflow.")] + public class SharedWait : Action + { + [Tooltip("The amount of time to wait (in seconds).")] + [SerializeField] SharedVariable m_Duration = 1; + [Tooltip("The seed of the random number generator. Set to 0 to disable.")] + [SerializeField] int m_Seed; + [Tooltip("Should the wait duration be randomized?")] + [SerializeField] SharedVariable m_RandomDuration; + [Tooltip("The minimum wait duration if random wait is enabled.")] + [SerializeField] SharedVariable m_RandomDurationRange = new RangeFloat(1, 1); + [Tooltip("The maximum wait duration if random wait is enabled.")] + [SerializeField] SharedVariable m_RandomDurationMax = 1; + + public SharedVariable Duration { get => m_Duration; set => m_Duration = value; } + public int Seed { get => m_Seed; set => m_Seed = value; } + public SharedVariable RandomDuration { get => m_RandomDuration; set => m_RandomDuration = value; } + public SharedVariable RandomDurationRange { get => m_RandomDurationRange; set => m_RandomDurationRange = value; } + public SharedVariable RandomDurationMax { get => m_RandomDurationMax; set => m_RandomDurationMax = value; } + + private float m_WaitDuration; + private float m_StartTime; + private float m_PauseTime = -1; + + /// + /// Callback when the task is initialized. + /// + public override void OnAwake() + { + if (m_Seed != 0) { + UnityEngine.Random.InitState(m_Seed); + } + } + + /// + /// Callback when the task is started. + /// + public override void OnStart() + { + if (m_RandomDuration.Value) { + m_WaitDuration = UnityEngine.Random.Range(m_RandomDurationRange.Value.Min, m_RandomDurationRange.Value.Max); + } else { + m_WaitDuration = m_Duration.Value; + } + m_StartTime = Time.time; + } + + /// + /// Executes the task logic. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + return m_StartTime + m_WaitDuration <= Time.time ? TaskStatus.Success : TaskStatus.Running; + } + + /// + /// Returns the current task state. + /// + /// The DOTS world. + /// The DOTS entity. + /// The current task state. + public override object Save(World world, Entity entity) + { + // Save the unique data. + return new object[] { m_WaitDuration, Time.time - m_StartTime }; + } + + /// + /// Loads the previous task state. + /// + /// The previous task state. + /// The DOTS world. + /// The DOTS entity. + public override void Load(object saveData, World world, Entity entity) + { + // saveData is the wait duration and the elapsed amount of time. + var data = (object[])saveData; + m_WaitDuration = (float)data[0]; + m_StartTime = Time.time - (float)data[1]; + } + + /// + /// The behavior tree has been started. + /// + public override void OnBehaviorTreeStarted() + { + base.OnBehaviorTreeStarted(); + + if (m_PauseTime != -1) { + m_StartTime += (Time.time - m_PauseTime); + m_PauseTime = -1; + } + } + + /// + /// The behavior tree has been stopped or paused. + /// + /// True if the tree has been paused. + public override void OnBehaviorTreeStopped(bool paused) + { + base.OnBehaviorTreeStopped(paused); + + if (paused) { + m_PauseTime = Time.time; + } + } + + /// + /// Resets the variables. + /// + public override void Reset() + { + base.Reset(); + + m_Duration = 1; + m_RandomDuration = false; + m_Seed = 0; + m_RandomDurationRange = new RangeFloat(1, 1); + m_PauseTime = -1; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Wait.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Wait.cs.meta new file mode 100644 index 0000000..bf52020 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Actions/Wait.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0c0e41c99613e54428dc9103bb7635dd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites.meta new file mode 100644 index 0000000..8ab8244 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 52b686992c2aafd4bb5214021e8b492b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/CompositeNode.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/CompositeNode.cs new file mode 100644 index 0000000..1726571 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/CompositeNode.cs @@ -0,0 +1,35 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Composites +{ + using Opsive.BehaviorDesigner.Runtime.Systems; + using Opsive.GraphDesigner.Runtime; + using UnityEngine; + + /// + /// A TaskObject implementation of the Composite task. + /// + [NodeIcon("3afb3814c40717440b175b6fde4e73c2", "7fb12c74939f50b41b1679eb8f9e79ab")] + public abstract class CompositeNode : Task, ITreeLogicNode, IParentNode, IComposite, ITaskObjectParentNode + { + [Tooltip("The index of the node.")] + [SerializeField] ushort m_Index; + [Tooltip("The parent index of the node. ushort.MaxValue indicates no parent.")] + [SerializeField] ushort m_ParentIndex; + [Tooltip("The sibling index of the node. ushort.MaxValue indicates no sibling.")] + [SerializeField] ushort m_SiblingIndex; + + public ushort Index { get => m_Index; set => m_Index = value; } + public ushort ParentIndex { get => m_ParentIndex; set => m_ParentIndex = value; } + public ushort SiblingIndex { get => m_SiblingIndex; set => m_SiblingIndex = value; } + public ushort RuntimeIndex { get; set; } + + public virtual int MaxChildCount { get => int.MaxValue; } + public virtual ushort NextChildIndex { get => (ushort)(RuntimeIndex + 1); } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/CompositeNode.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/CompositeNode.cs.meta new file mode 100644 index 0000000..fc6cfd1 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/CompositeNode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 03dee97f70b381e4bb7a230cca3e5f8f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/Parallel.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/Parallel.cs new file mode 100644 index 0000000..985b5d3 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/Parallel.cs @@ -0,0 +1,225 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Composites +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.BehaviorDesigner.Runtime.Utility; + using Opsive.GraphDesigner.Runtime; + using Unity.Burst; + using Unity.Collections; + using Unity.Entities; + using Unity.Jobs; + using UnityEngine; + + /// + /// A node representation of the parallel task. + /// + [NodeIcon("f612c025389b22640b1b6df88f4502e7", "8a4a401bcfb527a48a08351efaf92e14")] + [Opsive.Shared.Utility.Description("Similar to the sequence task, the parallel task will run each child task until a child task returns failure. " + + "The parallel task will run all of its children tasks simultaneously versus running each task one at a time. " + + "Like the sequence class, the parallel task will return success once all of its children tasks have return success. " + + "If one tasks returns failure the parallel task will end all of the child tasks and return failure.")] + public class Parallel : ECSCompositeTask, IParentNode, IParallelNode + { + public override ComponentType Flag { get => typeof(ParallelFlag); } + + /// + /// Adds the IBufferElementData to the entity. + /// + /// The world that the entity exists in. + /// The entity that the IBufferElementData should be assigned to. + /// The GameObject that the entity is attached to. + /// The index of the element within the buffer. + public override int AddBufferElement(World world, Entity entity, GameObject gameObject) + { + var index = base.AddBufferElement(world, entity, gameObject); + ComponentUtility.AddInterruptComponents(world.EntityManager, entity); + return index; + } + + /// + /// Returns a new TBufferElement for use by the system. + /// + /// A new TBufferElement for use by the system. + public override ParallelComponent GetBufferElement() + { + return new ParallelComponent() + { + Index = RuntimeIndex + }; + } + } + + /// + /// The DOTS data structure for the Parallel class. + /// + public struct ParallelComponent : IBufferElementData + { + [Tooltip("The index of the node.")] + [SerializeField] ushort m_Index; + + public ushort Index { get => m_Index; set => m_Index = value; } + } + + /// + /// A DOTS tag indicating when a Parallel node is active. + /// + public struct ParallelFlag : IComponentData, IEnableableComponent { } + + /// + /// Runs the Parallel logic. + /// + [DisableAutoCreation] + public partial struct ParallelTaskSystem : ISystem + { + private EntityQuery m_Query; + private JobHandle m_Dependency; + + /// + /// Builds the query. + /// + /// THe current SystemState. + private void OnCreate(ref SystemState state) + { + m_Query = SystemAPI.QueryBuilder().WithAllRW().WithAllRW().WithAllRW().WithAll().Build(); + } + + /// + /// Creates the job. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + m_Dependency.Complete(); + + var ecb = SystemAPI.GetSingleton().CreateCommandBuffer(state.WorldUnmanaged); + state.Dependency = new ParallelJob() + { + EntityCommandBuffer = ecb.AsParallelWriter() + }.ScheduleParallel(m_Query, state.Dependency); + m_Dependency = state.Dependency; + } + + /// + /// Job which executes the task logic. + /// + [BurstCompile] + private partial struct ParallelJob : IJobEntity + { + [Tooltip("CommandBuffer which sets the component data.")] + public EntityCommandBuffer.ParallelWriter EntityCommandBuffer; + + /// + /// Executes the parallel logic. + /// + /// The entity that is being acted upon. + /// The index of the entity. + /// An array of ParallelComponents. + /// An array of TaskComponents. + /// An array of BranchComponents. + [BurstCompile] + public void Execute(Entity entity, [EntityIndexInQuery] int entityIndex, ref DynamicBuffer parallelComponents, ref DynamicBuffer taskComponents, ref DynamicBuffer branchComponents) + { + for (int i = 0; i < parallelComponents.Length; ++i) { + var parallelComponent = parallelComponents[i]; + var taskComponent = taskComponents[parallelComponent.Index]; + var branchComponent = branchComponents[taskComponent.BranchIndex]; + + // Do not continue if there will be an interrupt or the branch cannot execute. + if (branchComponent.InterruptType != InterruptType.None || !branchComponent.CanExecute) { + continue; + } + + ushort childIndex; + TaskComponent childTaskComponent; + if (taskComponent.Status == TaskStatus.Queued) { + taskComponent.Status = TaskStatus.Running; + taskComponents[taskComponent.Index] = taskComponent; + + childIndex = (ushort)(parallelComponent.Index + 1); + while (childIndex != ushort.MaxValue) { + childTaskComponent = taskComponents[childIndex]; + childTaskComponent.Status = TaskStatus.Queued; + taskComponents[childIndex] = childTaskComponent; + + var childBranchComponent = branchComponents[childTaskComponent.BranchIndex]; + childBranchComponent.NextIndex = childTaskComponent.Index; + branchComponents[childTaskComponent.BranchIndex] = childBranchComponent; + + childIndex = taskComponents[childIndex].SiblingIndex; + } + } else if (taskComponent.Status != TaskStatus.Running) { + continue; + } + + var childrenFailure = false; + var childrenRunning = false; + childIndex = (ushort)(parallelComponent.Index + 1); + while (childIndex != ushort.MaxValue) { + childTaskComponent = taskComponents[childIndex]; + if (childTaskComponent.Status == TaskStatus.Queued || childTaskComponent.Status == TaskStatus.Running) { + childrenRunning = true; + } else if (childTaskComponent.Status == TaskStatus.Failure) { + childrenFailure = true; + + var childBranchComponent = branchComponents[childTaskComponent.BranchIndex]; + childBranchComponent.NextIndex = ushort.MaxValue; + branchComponents[childTaskComponent.BranchIndex] = childBranchComponent; + break; + } else if (childTaskComponent.Status == TaskStatus.Success) { + var childBranchComponent = branchComponents[childTaskComponent.BranchIndex]; + if (childBranchComponent.ActiveIndex != ushort.MaxValue) { + childBranchComponent.NextIndex = ushort.MaxValue; + branchComponents[childTaskComponent.BranchIndex] = childBranchComponent; + } + } + childIndex = taskComponents[childIndex].SiblingIndex; + } + + // If a single child fails then all tasks should be stopped. + if (childrenFailure) { + var maxChildIndex = taskComponent.Index + TraversalUtility.GetChildCount(taskComponent.Index, ref taskComponents); + for (ushort j = (ushort)(taskComponent.Index + 1); j <= maxChildIndex; ++j) { + childTaskComponent = taskComponents[j]; + if (childTaskComponent.Status == TaskStatus.Running || childTaskComponent.Status == TaskStatus.Queued) { + childTaskComponent.Status = TaskStatus.Failure; + taskComponents[j] = childTaskComponent; + + branchComponent = branchComponents[childTaskComponent.BranchIndex]; + EntityCommandBuffer.SetComponentEnabled(entityIndex, entity, true); + if (branchComponent.ActiveIndex == childTaskComponent.Index) { + branchComponent.NextIndex = ushort.MaxValue; + branchComponents[childTaskComponent.BranchIndex] = branchComponent; + } + } + } + + branchComponent.NextIndex = taskComponent.ParentIndex; + branchComponents[taskComponent.BranchIndex] = branchComponent; + taskComponent.Status = TaskStatus.Failure; + taskComponents[taskComponent.Index] = taskComponent; + + continue; + } + + if (childrenRunning) { + continue; + } + + // No more children are running. Resume the parent task. + taskComponent.Status = TaskStatus.Success; + taskComponents[taskComponent.Index] = taskComponent; + + branchComponent.NextIndex = taskComponent.ParentIndex; + branchComponents[taskComponent.BranchIndex] = branchComponent; + } + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/Parallel.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/Parallel.cs.meta new file mode 100644 index 0000000..74fb69a --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/Parallel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 121e856fe6b49d648a50fde8ee6923ed +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/ParallelSelector.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/ParallelSelector.cs new file mode 100644 index 0000000..9435354 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/ParallelSelector.cs @@ -0,0 +1,219 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Composites +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.BehaviorDesigner.Runtime.Utility; + using Opsive.GraphDesigner.Runtime; + using Unity.Burst; + using Unity.Collections; + using Unity.Entities; + using Unity.Jobs; + using Unity.Mathematics; + using UnityEngine; + + /// + /// A node representation of the parallel selector task. + /// + [NodeIcon("d47aff1a00bcc6d4da8ca0df32ed8415", "108591b5d7a6bd94383d16a62cb3b4a7")] + [Opsive.Shared.Utility.Description("Similar to the selector task, the parallel selector task will return success as soon as a child task returns success. " + + "The parallel task will run all of its children tasks simultaneously versus running each task one at a time. " + + "If one tasks returns success the parallel selector task will end all of the child tasks and return success. " + + "If every child task returns failure then the parallel selector task will return failure.")] + public class ParallelSelector : ECSCompositeTask, IParentNode, IParallelNode + { + /// + /// The type of tag that should be enabled when the task is running. + /// + public override ComponentType Flag { get => typeof(ParallelSelectorFlag); } + + /// + /// Returns a new TBufferElement for use by the system. + /// + /// A new TBufferElement for use by the system. + public override ParallelSelectorComponent GetBufferElement() + { + return new ParallelSelectorComponent() { + Index = RuntimeIndex, + }; + } + + /// + /// Adds the IBufferElementData to the entity. + /// + /// The world that the entity exists in. + /// The entity that the IBufferElementData should be assigned to. + /// The GameObject that the entity is attached to. + /// The index of the element within the buffer. + public override int AddBufferElement(World world, Entity entity, GameObject gameObject) + { + var index = base.AddBufferElement(world, entity, gameObject); + ComponentUtility.AddInterruptComponents(world.EntityManager, entity); + return index; + } + } + + /// + /// The DOTS data structure for the ParallelSelector class. + /// + public struct ParallelSelectorComponent : IBufferElementData + { + [Tooltip("The index of the node.")] + [SerializeField] ushort m_Index; + + public ushort Index { get => m_Index; set => m_Index = value; } + } + + /// + /// A DOTS tag indicating when a ParallelSelector node is active. + /// + public struct ParallelSelectorFlag : IComponentData, IEnableableComponent { } + + /// + /// Runs the ParallelSelector logic. + /// + [DisableAutoCreation] + public partial struct ParallelSelectorTaskSystem : ISystem + { + private EntityQuery m_Query; + private JobHandle m_Dependency; + + /// + /// Builds the query. + /// + /// THe current SystemState. + private void OnCreate(ref SystemState state) + { + m_Query = SystemAPI.QueryBuilder().WithAllRW().WithAllRW().WithAllRW().WithAll().Build(); + } + + /// + /// Creates the job. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + m_Dependency.Complete(); + + var ecb = SystemAPI.GetSingleton().CreateCommandBuffer(state.WorldUnmanaged); + state.Dependency = new ParallelSelectorJob() + { + EntityCommandBuffer = ecb.AsParallelWriter() + }.ScheduleParallel(m_Query, state.Dependency); + m_Dependency = state.Dependency; + } + + /// + /// Job which executes the task logic. + /// + [BurstCompile] + private partial struct ParallelSelectorJob : IJobEntity + { + [Tooltip("CommandBuffer which sets the component data.")] + public EntityCommandBuffer.ParallelWriter EntityCommandBuffer; + + /// + /// Executes the parallel selector logic. + /// + /// The entity that is being acted upon. + /// The index of the entity. + /// An array of BranchComponents. + /// An array of TaskComponents. + /// An array of ParallelSelectorComponents. + [BurstCompile] + public void Execute(Entity entity, [EntityIndexInQuery] int entityIndex, ref DynamicBuffer branchComponents, ref DynamicBuffer taskComponents, ref DynamicBuffer parallelSelectorComponents) + { + for (int i = 0; i < parallelSelectorComponents.Length; ++i) { + var parallelSelectorComponent = parallelSelectorComponents[i]; + var taskComponent = taskComponents[parallelSelectorComponent.Index]; + var branchComponent = branchComponents[taskComponent.BranchIndex]; + + // Do not continue if there will be an interrupt or the branch cannot execute. + if (branchComponent.InterruptType != InterruptType.None || !branchComponent.CanExecute) { + continue; + } + + ushort childIndex; + TaskComponent childTaskComponent; + if (taskComponent.Status == TaskStatus.Queued) { + taskComponent.Status = TaskStatus.Running; + taskComponents[taskComponent.Index] = taskComponent; + + childIndex = (ushort)(parallelSelectorComponent.Index + 1); + while (childIndex != ushort.MaxValue) { + childTaskComponent = taskComponents[childIndex]; + childTaskComponent.Status = TaskStatus.Queued; + taskComponents[childIndex] = childTaskComponent; + + var childBranchComponent = branchComponents[childTaskComponent.BranchIndex]; + childBranchComponent.NextIndex = childTaskComponent.Index; + branchComponents[childTaskComponent.BranchIndex] = childBranchComponent; + + childIndex = taskComponents[childIndex].SiblingIndex; + } + } else if (taskComponent.Status != TaskStatus.Running) { + continue; + } + + var childSuccess = false; + var childrenRunning = false; + childIndex = (ushort)(parallelSelectorComponent.Index + 1); + while (childIndex != ushort.MaxValue) { + childTaskComponent = taskComponents[childIndex]; + if (childTaskComponent.Status == TaskStatus.Queued || childTaskComponent.Status == TaskStatus.Running) { + childrenRunning = true; + } else if (childTaskComponent.Status == TaskStatus.Failure) { + var childBranchComponent = branchComponents[childTaskComponent.BranchIndex]; + if (childBranchComponent.ActiveIndex != ushort.MaxValue) { + childBranchComponent.NextIndex = ushort.MaxValue; + branchComponents[childTaskComponent.BranchIndex] = childBranchComponent; + } + } else if (childTaskComponent.Status == TaskStatus.Success) { + childSuccess = true; + + var childBranchComponent = branchComponents[childTaskComponent.BranchIndex]; + childBranchComponent.NextIndex = ushort.MaxValue; + branchComponents[childTaskComponent.BranchIndex] = childBranchComponent; + break; + } + childIndex = taskComponents[childIndex].SiblingIndex; + } + + // If a single child succeeds then all tasks should be stopped. + if (childSuccess) { + var maxChildIndex = taskComponent.Index + TraversalUtility.GetChildCount(taskComponent.Index, ref taskComponents); + for (ushort j = (ushort)(taskComponent.Index + 1); j <= maxChildIndex; ++j) { + childTaskComponent = taskComponents[j]; + if (childTaskComponent.Status == TaskStatus.Running || childTaskComponent.Status == TaskStatus.Queued) { + childTaskComponent.Status = TaskStatus.Failure; + taskComponents[j] = childTaskComponent; + + branchComponent = branchComponents[childTaskComponent.BranchIndex]; + EntityCommandBuffer.SetComponentEnabled(entityIndex, entity, true); + if (branchComponent.ActiveIndex == childTaskComponent.Index) { + branchComponent.NextIndex = ushort.MaxValue; + branchComponents[childTaskComponent.BranchIndex] = branchComponent; + } + } + } + } else if (childrenRunning) { + continue; + } + + // No more children are running. Resume the parent task. + taskComponent.Status = TaskStatus.Success; + taskComponents[taskComponent.Index] = taskComponent; + + branchComponent.NextIndex = taskComponent.ParentIndex; + branchComponents[taskComponent.BranchIndex] = branchComponent; + } + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/ParallelSelector.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/ParallelSelector.cs.meta new file mode 100644 index 0000000..dc076e8 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/ParallelSelector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f3ba12965f09f3f4e81b66fa35df8ec3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/PrioritySelector.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/PrioritySelector.cs new file mode 100644 index 0000000..ed22b02 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/PrioritySelector.cs @@ -0,0 +1,331 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Composites +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.BehaviorDesigner.Runtime.Utility; + using Opsive.GraphDesigner.Runtime; + using Opsive.Shared.Utility; + using System; + using Unity.Burst; + using Unity.Collections; + using Unity.Entities; + using UnityEngine; + + /// + /// A node representation of the priority selector task. + /// + [NodeIcon("cea0f2b6cee06a742bb35dcc40202e8e", "744afc2640950e045961296f1d5800d7")] + [Opsive.Shared.Utility.Description("Similar to the selector task, the priority selector task will return success as soon as a child task returns success. " + + "Instead of running the tasks sequentially from left to right within the tree, the priority selector will ask the task what its priority is to determine the order. " + + "The higher priority tasks have a higher chance at being run first.")] + public class PrioritySelector : ECSCompositeTask, IParentNode, ISavableTask, ICloneable + { + private ushort m_ComponentIndex; + + public override ComponentType Flag { get => typeof(PrioritySelectorFlag); } + + /// + /// Returns a new TBufferElement for use by the system. + /// + /// A new TBufferElement for use by the system. + public override PrioritySelectorComponent GetBufferElement() + { + return new PrioritySelectorComponent() + { + Index = RuntimeIndex, + }; + } + + /// + /// Adds the IBufferElementData to the entity. + /// + /// The world that the entity exists in. + /// The entity that the IBufferElementData should be assigned to. + /// The GameObject that the entity is attached to. + /// The index of the element within the buffer. + public override int AddBufferElement(World world, Entity entity, GameObject gameObject) + { + m_ComponentIndex = (ushort)base.AddBufferElement(world, entity, gameObject); + return m_ComponentIndex; + } + + /// + /// Specifies the type of reflection that should be used to save the task. + /// + /// The index of the sub-task. This is used for the task set allowing each contained task to have their own save type. + public MemberVisibility GetSaveReflectionType(int index) { return MemberVisibility.None; } + + /// + /// Returns the current task state. + /// + /// The DOTS world. + /// The DOTS entity. + /// The current task state. + public object Save(World world, Entity entity) + { + var prioritySelectorComponents = world.EntityManager.GetBuffer(entity); + var prioritySelectorComponent = prioritySelectorComponents[m_ComponentIndex]; + + // Save the active child and array order. + var saveData = new object[2]; + saveData[0] = prioritySelectorComponent.ActiveRelativeChildIndex; + if (prioritySelectorComponent.Priorities.IsCreated) { + saveData[1] = prioritySelectorComponent.Priorities.ToArray(); + } + return saveData; + } + + /// + /// Loads the previous task state. + /// + /// The previous task state. + /// The DOTS world. + /// The DOTS entity. + public void Load(object saveData, World world, Entity entity) + { + var prioritySelectorComponents = world.EntityManager.GetBuffer(entity); + var prioritySelectorComponent = prioritySelectorComponents[m_ComponentIndex]; + + // saveData is the active child and array order. + var taskSaveData = (object[])saveData; + prioritySelectorComponent.ActiveRelativeChildIndex = (ushort)taskSaveData[0]; + if (taskSaveData[1] != null) { + prioritySelectorComponent.Priorities = new NativeArray((PrioritySelectorComponent.PriorityItem[])taskSaveData[1], Allocator.Persistent); + } + prioritySelectorComponents[m_ComponentIndex] = prioritySelectorComponent; + } + + /// + /// Creates a deep clone of the component. + /// + /// A deep clone of the component. + public object Clone() + { + var clone = Activator.CreateInstance(); + clone.Index = Index; + clone.ParentIndex = ParentIndex; + clone.SiblingIndex = SiblingIndex; + return clone; + } + } + + /// + /// The DOTS data structure for the PrioritySelector class. + /// + public struct PrioritySelectorComponent : IBufferElementData + { + [Tooltip("The index of the node.")] + public ushort Index; + [Tooltip("The relative index of the child that is currently active.")] + public ushort ActiveRelativeChildIndex; + [Tooltip("The latest priority values for each child task.")] + public NativeArray Priorities; + + /// + /// Joins the task index with the priority value. + /// + public struct PriorityItem : IComparable + { + [Tooltip("The index of the task.")] + public ushort TaskIndex; + [Tooltip("The index of the PriorityValueComponent. A value of ushort.MaxValue indicates that there is not a corresponding PriorityValueComponent to this element.")] + public ushort PriorityValueIndex; + [Tooltip("The priority value.")] + public float Value; + + /// + /// Compares the current PriorityItem to the other PriorityItem. + /// + /// The other PriorityItem. + /// The comparison between the current PriorityItem and the other PriorityItem. + public int CompareTo(PriorityItem other) + { + // The higher the value the lower the item is in the array. + return other.Value.CompareTo(Value); + } + } + } + + /// + /// DOTS structure that contains the most recently priority of the task. + /// + public struct PriorityValueComponent : IBufferElementData + { + [Tooltip("The index of the task.")] + public ushort Index; + [Tooltip("The current priority value. The higher the value the more likely it will be selected.")] + public float Value; + } + + /// + /// A DOTS tag indicating when a PrioritySelector node is active. + /// + public struct PrioritySelectorFlag : IComponentData, IEnableableComponent { } + + /// + /// Runs the PrioritySelector logic. + /// + [DisableAutoCreation] + public partial struct PrioritySelectorTaskSystem : ISystem + { + /// + /// Updates the logic. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + var hasPriorityValueComponent = false; + foreach (var (branchComponents, taskComponents, prioritySelectorComponents, priorityValueComponents) in + SystemAPI.Query, DynamicBuffer, DynamicBuffer, DynamicBuffer>().WithAll()) { + + hasPriorityValueComponent = true; + for (int i = 0; i < prioritySelectorComponents.Length; ++i) { + var prioritySelectorComponent = prioritySelectorComponents[i]; + var taskComponent = taskComponents[prioritySelectorComponent.Index]; + var branchComponent = branchComponents[taskComponent.BranchIndex]; + + // Do not continue if there will be an interrupt or the branch cannot execute. + if (branchComponent.InterruptType != InterruptType.None || !branchComponent.CanExecute) { + continue; + } + + var prioritySelectorComponentsBuffer = prioritySelectorComponents; + var taskComponentsBuffer = taskComponents; + var branchComponentBuffer = branchComponents; + if (taskComponent.Status == TaskStatus.Queued) { + taskComponent.Status = TaskStatus.Running; + taskComponentsBuffer[taskComponent.Index] = taskComponent; + + // Initialize the priority value array. + NativeArray priorities; + if (prioritySelectorComponent.Priorities.Length == 0) { + var childCount = TraversalUtility.GetImmediateChildCount(ref taskComponent, ref taskComponentsBuffer); + priorities = new NativeArray(childCount, Allocator.Persistent); + // Match the PriorityValueComponent with the child index. + var childIndex = (ushort)(taskComponent.Index + 1); + for (ushort j = 0; j < childCount; ++j) { + priorities[j] = new PrioritySelectorComponent.PriorityItem() { TaskIndex = childIndex, PriorityValueIndex = ushort.MaxValue, Value = float.MinValue }; + for (ushort k = 0; k < priorityValueComponents.Length; ++k) { + var priorityValueComponent = priorityValueComponents[k]; + + if (priorityValueComponent.Index == childIndex) { + var priorityItem = priorities[j]; + priorityItem.PriorityValueIndex = k; + priorities[j] = priorityItem; + break; + } + } + childIndex = taskComponents[childIndex].SiblingIndex; + } + + prioritySelectorComponent.Priorities = priorities; + } + + // Determine the child order when the task starts. + priorities = prioritySelectorComponent.Priorities; + + for (ushort j = 0; j < priorities.Length; ++j) { + var valueIndex = priorities[j].PriorityValueIndex; + // The task may not have a matching PriorityValueComponent. + if (valueIndex == ushort.MaxValue) { + continue; + } + + var priorityItem = priorities[j]; + priorityItem.Value = priorityValueComponents[valueIndex].Value; + priorities[j] = priorityItem; + } + priorities.Sort(); + prioritySelectorComponent.Priorities = priorities; + prioritySelectorComponentsBuffer[i] = prioritySelectorComponent; + + prioritySelectorComponent.ActiveRelativeChildIndex = 0; + branchComponent.NextIndex = prioritySelectorComponent.Priorities[prioritySelectorComponent.ActiveRelativeChildIndex].TaskIndex; + branchComponentBuffer[taskComponent.BranchIndex] = branchComponent; + + // Start the child. + var nextChildTaskComponent = taskComponents[branchComponent.NextIndex]; + nextChildTaskComponent.Status = TaskStatus.Queued; + taskComponentsBuffer[branchComponent.NextIndex] = nextChildTaskComponent; + } else if (taskComponent.Status != TaskStatus.Running) { + continue; + } + + // The prioritySelector task is currently active. Check the first child. + var childTaskComponent = taskComponents[prioritySelectorComponent.Priorities[prioritySelectorComponent.ActiveRelativeChildIndex].TaskIndex]; + if (childTaskComponent.Status == TaskStatus.Queued || childTaskComponent.Status == TaskStatus.Running) { + // The child should keep running. + continue; + } + + // Switch to the next highest priority. If no more priority values exist the task should act as a normal selector. + if (prioritySelectorComponent.ActiveRelativeChildIndex == prioritySelectorComponent.Priorities.Length - 1 || + childTaskComponent.Status == TaskStatus.Success) { + // There are no more children or the child succeeded. The selector task should end. + taskComponent.Status = childTaskComponent.Status; + prioritySelectorComponent.ActiveRelativeChildIndex = 0; + taskComponentsBuffer[prioritySelectorComponent.Index] = taskComponent; + + branchComponent.NextIndex = taskComponent.ParentIndex; + branchComponentBuffer[taskComponent.BranchIndex] = branchComponent; + } else { + // The child task returned failure. Move onto the next task. + prioritySelectorComponent.ActiveRelativeChildIndex++; + var nextIndex = prioritySelectorComponent.Priorities[prioritySelectorComponent.ActiveRelativeChildIndex].TaskIndex; + var nextTaskComponent = taskComponents[nextIndex]; + nextTaskComponent.Status = TaskStatus.Queued; + taskComponentsBuffer[nextIndex] = nextTaskComponent; + + branchComponent.NextIndex = nextIndex; + branchComponentBuffer[taskComponent.BranchIndex] = branchComponent; + } + prioritySelectorComponentsBuffer[i] = prioritySelectorComponent; + } + } + + // Special case where the PrioritySelectorComponent has no PriorityValueComponent children. + if (!hasPriorityValueComponent) { + foreach (var (prioritySelectorComponents, taskComponents, branchComponents) in + SystemAPI.Query, DynamicBuffer, DynamicBuffer>().WithAll()) { + + for (int i = 0; i < prioritySelectorComponents.Length; ++i) { + var prioritySelectorComponent = prioritySelectorComponents[i]; + var taskComponent = taskComponents[prioritySelectorComponent.Index]; + + // If there are no values then the selector should return failure. + if (taskComponent.Status == TaskStatus.Queued && prioritySelectorComponent.Priorities.Length == 0) { + taskComponent.Status = TaskStatus.Failure; + var taskComponentsBuffer = taskComponents; + taskComponentsBuffer[prioritySelectorComponent.Index] = taskComponent; + + var branchComponent = branchComponents[taskComponent.BranchIndex]; + branchComponent.NextIndex = taskComponent.ParentIndex; + var branchComponentBuffer = branchComponents; + branchComponentBuffer[taskComponent.BranchIndex] = branchComponent; + } + } + } + } + } + + /// + /// The task has been destroyed. + /// + /// The current state of the system. + private void OnDestroy(ref SystemState state) + { + foreach (var prioritySelectorComponents in SystemAPI.Query>()) { + for (int i = 0; i < prioritySelectorComponents.Length; ++i) { + prioritySelectorComponents[i].Priorities.Dispose(); + } + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/PrioritySelector.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/PrioritySelector.cs.meta new file mode 100644 index 0000000..ce4eafb --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/PrioritySelector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0df94ec9b57703043babb28f51e4b55d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/RandomSelector.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/RandomSelector.cs new file mode 100644 index 0000000..af57f9e --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/RandomSelector.cs @@ -0,0 +1,324 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Composites +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.BehaviorDesigner.Runtime.Utility; + using Opsive.GraphDesigner.Runtime; + using Opsive.Shared.Utility; + using Unity.Collections; + using Unity.Entities; + using Unity.Burst; + using UnityEngine; + using System; + + /// + /// A node representation of the random selector task. + /// + [NodeIcon("d7c1e0f5830316e449df8a35561df859", "7638e4bc5a1f4cd488801902387ec5ea")] + [Opsive.Shared.Utility.Description("Similar to the selector task, the random selector task will return success as soon as a child task returns success. " + + "The difference is that the random selector class will run its children in a random order. The selector task is deterministic " + + "in that it will always run the tasks from left to right within the tree. The random selector task shuffles the child tasks up and then begins " + + "execution in a random order. Other than that the random selector class is the same as the selector class. It will continue running tasks " + + "until a task completes successfully. If no child tasks return success then it will return failure.")] + public class RandomSelector : ECSCompositeTask, IParentNode, IConditionalAbortParent, IInterruptResponder, ISavableTask, ICloneable + { + [Tooltip("Specifies how the child conditional tasks should be reevaluated.")] + [SerializeField] ConditionalAbortType m_AbortType; + [Tooltip("The seed of the random number generator. Set to 0 to use the entity index as the seed.")] + [SerializeField] uint m_Seed; + + private ushort m_ComponentIndex; + + public ConditionalAbortType AbortType { get => m_AbortType; set => m_AbortType = value; } + public uint Seed { get => m_Seed; set => m_Seed = value; } + + public override ComponentType Flag { get => typeof(RandomSelectorFlag); } + public Type InterruptSystemType { get => typeof(RandomSelectorInterruptSystem); } + + /// + /// Returns a new TBufferElement for use by the system. + /// + /// A new TBufferElement for use by the system. + public override RandomSelectorComponent GetBufferElement() + { + return new RandomSelectorComponent() + { + Index = RuntimeIndex, + Seed = m_Seed, + }; + } + + /// + /// Adds the IBufferElementData to the entity. + /// + /// The world that the entity exists in. + /// The entity that the IBufferElementData should be assigned to. + /// The GameObject that the entity is attached to. + /// The index of the element within the buffer. + public override int AddBufferElement(World world, Entity entity, GameObject gameObject) + { + m_ComponentIndex = (ushort)base.AddBufferElement(world, entity, gameObject); + return m_ComponentIndex; + } + + /// + /// Specifies the type of reflection that should be used to save the task. + /// + /// The index of the sub-task. This is used for the task set allowing each contained task to have their own save type. + public MemberVisibility GetSaveReflectionType(int index) { return MemberVisibility.None; } + + /// + /// Returns the current task state. + /// + /// The DOTS world. + /// The DOTS entity. + /// The current task state. + public object Save(World world, Entity entity) + { + var randomSelectorComponents = world.EntityManager.GetBuffer(entity); + var randomSelectorComponent = randomSelectorComponents[m_ComponentIndex]; + + // Save the active child and array order. + var saveData = new object[2]; + saveData[0] = randomSelectorComponent.ActiveRelativeChildIndex; + if (randomSelectorComponent.TaskOrder.IsCreated) { + var taskOrder = randomSelectorComponent.TaskOrder.Value.Indicies.ToArray(); + saveData[1] = taskOrder; + } + return saveData; + } + + /// + /// Loads the previous task state. + /// + /// The previous task state. + /// The DOTS world. + /// The DOTS entity. + public void Load(object saveData, World world, Entity entity) + { + var randomSelectorComponents = world.EntityManager.GetBuffer(entity); + var randomSelectorComponent = randomSelectorComponents[m_ComponentIndex]; + + // saveData is the active child and array order. + var taskSaveData = (object[])saveData; + randomSelectorComponent.ActiveRelativeChildIndex = (ushort)taskSaveData[0]; + if (taskSaveData[1] != null) { + var taskOrder = (ushort[])taskSaveData[1]; + var builder = new BlobBuilder(Allocator.Temp); + ref var root = ref builder.ConstructRoot(); + var orderArray = builder.Allocate(ref root.Indicies, taskOrder.Length); + for (int i = 0; i < taskOrder.Length; i++) { + orderArray[i] = taskOrder[i]; + } + randomSelectorComponent.TaskOrder = builder.CreateBlobAssetReference(Allocator.Persistent); + builder.Dispose(); + } + randomSelectorComponents[m_ComponentIndex] = randomSelectorComponent; + } + + /// + /// Creates a deep clone of the component. + /// + /// A deep clone of the component. + public object Clone() + { + var clone = Activator.CreateInstance(); + clone.Index = Index; + clone.ParentIndex = ParentIndex; + clone.SiblingIndex = SiblingIndex; + clone.AbortType = AbortType; + return clone; + } + } + + /// + /// The DOTS data structure for the RandomSelector class. + /// + public struct RandomSelectorComponent : IBufferElementData + { + [Tooltip("The index of the node.")] + public ushort Index; + [Tooltip("The relative index of the child that is currently active.")] + public ushort ActiveRelativeChildIndex; + [Tooltip("The seed of the random number generator.")] + public uint Seed; + [Tooltip("The random number generator for the task.")] + public Unity.Mathematics.Random RandomNumberGenerator; + [Tooltip("The indicies of the child task execution order.")] + public BlobAssetReference TaskOrder; + } + + /// + /// A DOTS tag indicating when a RandomSelector node is active. + /// + public struct RandomSelectorFlag : IComponentData, IEnableableComponent { } + + /// + /// Runs the RandomSelector logic. + /// + [DisableAutoCreation] + public partial struct RandomSelectorTaskSystem : ISystem + { + /// + /// Updates the logic. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + foreach (var (branchComponents, taskComponents, randomSelectorComponents, entity) in + SystemAPI.Query, DynamicBuffer, DynamicBuffer>().WithAll().WithEntityAccess()) { + for (int i = 0; i < randomSelectorComponents.Length; ++i) { + var randomSelectorComponent = randomSelectorComponents[i]; + var taskComponent = taskComponents[randomSelectorComponent.Index]; + var branchComponent = branchComponents[taskComponent.BranchIndex]; + + // Do not continue if there will be an interrupt or the branch cannot execute. + if (branchComponent.InterruptType != InterruptType.None || !branchComponent.CanExecute) { + continue; + } + + var randomSelectorComponentsBuffer = randomSelectorComponents; + var taskComponentsBuffer = taskComponents; + var branchComponentBuffer = branchComponents; + if (taskComponent.Status == TaskStatus.Queued) { + taskComponent.Status = TaskStatus.Running; + taskComponentsBuffer[taskComponent.Index] = taskComponent; + + // Initialize the task order array. + if (!randomSelectorComponent.TaskOrder.IsCreated) { + var childCount = TraversalUtility.GetImmediateChildCount(ref taskComponent, ref taskComponentsBuffer); + var builder = new BlobBuilder(Allocator.Temp); + ref var root = ref builder.ConstructRoot(); + var orderArray = builder.Allocate(ref root.Indicies, childCount); + var childIndex = taskComponent.Index + 1; + for (int j = 0; j < childCount; ++j) { + orderArray[j] = (ushort)childIndex; + childIndex = taskComponents[childIndex].SiblingIndex; + } + randomSelectorComponent.TaskOrder = builder.CreateBlobAssetReference(Allocator.Persistent); + builder.Dispose(); + } + + // Generate a new random number seed for each entity. + if (randomSelectorComponent.RandomNumberGenerator.state == 0) { + randomSelectorComponent.RandomNumberGenerator = Unity.Mathematics.Random.CreateFromIndex(randomSelectorComponent.Seed != 0 ? randomSelectorComponent.Seed : (uint)entity.Index); + } + + // Use fisher-yates to shuffle the array in place. + ref var initialTaskOrder = ref randomSelectorComponent.TaskOrder.Value.Indicies; + var index = initialTaskOrder.Length; + while (index != 0) { + var randomUnitFloat = randomSelectorComponent.RandomNumberGenerator.NextFloat(); + var randomIndex = (int)Unity.Mathematics.math.floor(randomUnitFloat * index); + index--; + + var element = initialTaskOrder[randomIndex]; + initialTaskOrder[randomIndex] = initialTaskOrder[index]; + initialTaskOrder[index] = element; + } + + randomSelectorComponent.ActiveRelativeChildIndex = 0; + randomSelectorComponentsBuffer[i] = randomSelectorComponent; + + branchComponent.NextIndex = initialTaskOrder[randomSelectorComponent.ActiveRelativeChildIndex]; + branchComponentBuffer[taskComponent.BranchIndex] = branchComponent; + + // The child may have already ran and have a non-inactive status. + var nextChildTaskComponent = taskComponents[branchComponent.NextIndex]; + nextChildTaskComponent.Status = TaskStatus.Queued; + taskComponentsBuffer[branchComponent.NextIndex] = nextChildTaskComponent; + } else if (taskComponent.Status != TaskStatus.Running) { + continue; + } + + // The randomSelector task is currently active. Check the first child. + ref var taskOrder = ref randomSelectorComponent.TaskOrder.Value.Indicies; + var childTaskComponent = taskComponents[taskOrder[randomSelectorComponent.ActiveRelativeChildIndex]]; + if (childTaskComponent.Status == TaskStatus.Queued || childTaskComponent.Status == TaskStatus.Running) { + // The child should keep running. + continue; + } + + if (randomSelectorComponent.ActiveRelativeChildIndex == taskOrder.Length - 1 || childTaskComponent.Status == TaskStatus.Success) { + // There are no more children or the child succeeded. The random selector task should end. A task status of inactive indicates the last task was disabled. Return failure. + taskComponent.Status = childTaskComponent.Status != TaskStatus.Inactive ? childTaskComponent.Status : TaskStatus.Failure; + randomSelectorComponent.ActiveRelativeChildIndex = 0; + taskComponentsBuffer[randomSelectorComponent.Index] = taskComponent; + + branchComponent.NextIndex = taskComponent.ParentIndex; + branchComponentBuffer[taskComponent.BranchIndex] = branchComponent; + } else { + // The child task returned failure. Move onto the next task. + randomSelectorComponent.ActiveRelativeChildIndex++; + var nextIndex = taskOrder[randomSelectorComponent.ActiveRelativeChildIndex]; + var nextTaskComponent = taskComponents[nextIndex]; + nextTaskComponent.Status = TaskStatus.Queued; + taskComponentsBuffer[nextIndex] = nextTaskComponent; + + branchComponent.NextIndex = nextIndex; + branchComponentBuffer[taskComponent.BranchIndex] = branchComponent; + } + randomSelectorComponentsBuffer[i] = randomSelectorComponent; + } + } + } + + /// + /// The task has been destroyed. + /// + /// The current state of the system. + private void OnDestroy(ref SystemState state) + { + foreach (var randomSelectorComponents in SystemAPI.Query>()) { + for (int i = 0; i < randomSelectorComponents.Length; ++i) { + var randomSelectorComponent = randomSelectorComponents[i]; + if (randomSelectorComponent.TaskOrder.IsCreated) { + randomSelectorComponent.TaskOrder.Dispose(); + } + } + } + } + } + + /// + /// An interrupt has occurred. Ensure the task state is correct after the interruption. + /// + [DisableAutoCreation] + + public partial struct RandomSelectorInterruptSystem : ISystem + { + /// + /// Runs the logic after an interruption. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + foreach (var (taskComponents, randomSelectorComponents) in + SystemAPI.Query, DynamicBuffer>().WithAll()) { + for (int i = 0; i < randomSelectorComponents.Length; ++i) { + var randomSelectorComponent = randomSelectorComponents[i]; + // The active child will have a non-running status if it has been interrupted. + var taskComponent = taskComponents[randomSelectorComponent.Index]; + if (taskComponent.Status == TaskStatus.Running && taskComponents[randomSelectorComponent.TaskOrder.Value.Indicies[randomSelectorComponent.ActiveRelativeChildIndex]].Status != TaskStatus.Running) { + ushort relativeChildIndex = 0; + // Find the currently active task. + while (taskComponents[randomSelectorComponent.TaskOrder.Value.Indicies[relativeChildIndex]].Status != TaskStatus.Running) { + relativeChildIndex++; + } + randomSelectorComponent.ActiveRelativeChildIndex = relativeChildIndex; + var randomSelectorBuffer = randomSelectorComponents; + randomSelectorBuffer[i] = randomSelectorComponent; + } + } + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/RandomSelector.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/RandomSelector.cs.meta new file mode 100644 index 0000000..08d2062 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/RandomSelector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 88b2c4cec0256b8478ada94d9f020ae3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/RandomSequence.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/RandomSequence.cs new file mode 100644 index 0000000..60548ed --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/RandomSequence.cs @@ -0,0 +1,324 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Composites +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.BehaviorDesigner.Runtime.Utility; + using Opsive.GraphDesigner.Runtime; + using Opsive.Shared.Utility; + using Unity.Collections; + using Unity.Entities; + using Unity.Burst; + using UnityEngine; + using System; + + /// + /// A node representation of the random sequence task. + /// + [NodeIcon("edb30349221143a408c76da55a6aa809", "cfb9039832ed52748b617bde070898dc")] + [Opsive.Shared.Utility.Description("Similar to the sequence task, the random sequence task will return success as soon as every child task returns success. " + + "The difference is that the random sequence class will run its children in a random order. The sequence task is deterministic " + + "in that it will always run the tasks from left to right within the tree. The random sequence task shuffles the child tasks up and then begins " + + "execution in a random order. Other than that the random sequence class is the same as the sequence class. It will stop running tasks " + + "as soon as a single task ends in failure. On a task failure it will stop executing all of the child tasks and return failure. " + + "If no child returns failure then it will return success.")] + public class RandomSequence : ECSCompositeTask, IParentNode, IConditionalAbortParent, IInterruptResponder, ISavableTask, ICloneable + { + [Tooltip("Specifies how the child conditional tasks should be reevaluated.")] + [SerializeField] ConditionalAbortType m_AbortType; + [Tooltip("The seed of the random number generator. Set to 0 to use the entity index as the seed.")] + [SerializeField] uint m_Seed; + + private ushort m_ComponentIndex; + + public ConditionalAbortType AbortType { get => m_AbortType; set => m_AbortType = value; } + public uint Seed { get => m_Seed; set => m_Seed = value; } + + public override ComponentType Flag { get => typeof(RandomSequenceFlag); } + public Type InterruptSystemType { get => typeof(RandomSequenceInterruptSystem); } + + /// + /// Returns a new TBufferElement for use by the system. + /// + /// A new TBufferElement for use by the system. + public override RandomSequenceComponent GetBufferElement() + { + return new RandomSequenceComponent() + { + Index = RuntimeIndex, + Seed = m_Seed, + }; + } + + /// + /// Adds the IBufferElementData to the entity. + /// + /// The world that the entity exists in. + /// The entity that the IBufferElementData should be assigned to. + /// The GameObject that the entity is attached to. + /// The index of the element within the buffer. + public override int AddBufferElement(World world, Entity entity, GameObject gameObject) + { + m_ComponentIndex = (ushort)base.AddBufferElement(world, entity, gameObject); + return m_ComponentIndex; + } + + /// + /// Specifies the type of reflection that should be used to save the task. + /// + /// The index of the sub-task. This is used for the task set allowing each contained task to have their own save type. + public MemberVisibility GetSaveReflectionType(int index) { return MemberVisibility.None; } + + /// + /// Returns the current task state. + /// + /// The DOTS world. + /// The DOTS entity. + /// The current task state. + public object Save(World world, Entity entity) + { + var randomSequenceComponents = world.EntityManager.GetBuffer(entity); + var randomSequenceComponent = randomSequenceComponents[m_ComponentIndex]; + + // Save the active child and array order. + var saveData = new object[2]; + saveData[0] = randomSequenceComponent.ActiveRelativeChildIndex; + if (randomSequenceComponent.TaskOrder.IsCreated) { + var taskOrder = randomSequenceComponent.TaskOrder.Value.Indicies.ToArray(); + saveData[1] = taskOrder; + } + return saveData; + } + + /// + /// Loads the previous task state. + /// + /// The previous task state. + /// The DOTS world. + /// The DOTS entity. + public void Load(object saveData, World world, Entity entity) + { + var randomSequenceComponents = world.EntityManager.GetBuffer(entity); + var randomSequenceComponent = randomSequenceComponents[m_ComponentIndex]; + + // saveData is the active child and array order. + var taskSaveData = (object[])saveData; + randomSequenceComponent.ActiveRelativeChildIndex = (ushort)taskSaveData[0]; + if (taskSaveData[1] != null) { + var taskOrder = (ushort[])taskSaveData[1]; + var builder = new BlobBuilder(Allocator.Temp); + ref var root = ref builder.ConstructRoot(); + var orderArray = builder.Allocate(ref root.Indicies, taskOrder.Length); + for (int i = 0; i < taskOrder.Length; i++) { + orderArray[i] = taskOrder[i]; + } + randomSequenceComponent.TaskOrder = builder.CreateBlobAssetReference(Allocator.Persistent); + builder.Dispose(); + } + randomSequenceComponents[m_ComponentIndex] = randomSequenceComponent; + } + + /// + /// Creates a deep clone of the component. + /// + /// A deep clone of the component. + public object Clone() + { + var clone = Activator.CreateInstance(); + clone.Index = Index; + clone.ParentIndex = ParentIndex; + clone.SiblingIndex = SiblingIndex; + clone.AbortType = AbortType; + return clone; + } + } + + /// + /// The DOTS data structure for the RandomSequence class. + /// + public struct RandomSequenceComponent : IBufferElementData + { + [Tooltip("The index of the node.")] + public ushort Index; + [Tooltip("The relative index of the child that is currently active.")] + public ushort ActiveRelativeChildIndex; + [Tooltip("The seed of the random number generator.")] + public uint Seed; + [Tooltip("The random number generator for the task.")] + public Unity.Mathematics.Random RandomNumberGenerator; + [Tooltip("The indicies of the child task execution order.")] + public BlobAssetReference TaskOrder; + } + + /// + /// A DOTS tag indicating when a RandomSequence node is active. + /// + public struct RandomSequenceFlag : IComponentData, IEnableableComponent { } + + /// + /// Runs the RandomSequence logic. + /// + [DisableAutoCreation] + public partial struct RandomSequenceTaskSystem : ISystem + { + /// + /// Updates the logic. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + foreach (var (branchComponents, taskComponents, randomSequenceComponents, entity) in + SystemAPI.Query, DynamicBuffer, DynamicBuffer>().WithAll().WithEntityAccess()) { + for (int i = 0; i < randomSequenceComponents.Length; ++i) { + var randomSequenceComponent = randomSequenceComponents[i]; + var taskComponent = taskComponents[randomSequenceComponent.Index]; + var branchComponent = branchComponents[taskComponent.BranchIndex]; + + // Do not continue if there will be an interrupt or the branch cannot execute. + if (branchComponent.InterruptType != InterruptType.None || !branchComponent.CanExecute) { + continue; + } + + var randomSequenceComponentsBuffer = randomSequenceComponents; + var taskComponentsBuffer = taskComponents; + var branchComponentBuffer = branchComponents; + if (taskComponent.Status == TaskStatus.Queued) { + taskComponent.Status = TaskStatus.Running; + taskComponentsBuffer[taskComponent.Index] = taskComponent; + + // Initialize the task order array. + if (!randomSequenceComponent.TaskOrder.IsCreated) { + var childCount = TraversalUtility.GetImmediateChildCount(ref taskComponent, ref taskComponentsBuffer); + var builder = new BlobBuilder(Allocator.Temp); + ref var root = ref builder.ConstructRoot(); + var orderArray = builder.Allocate(ref root.Indicies, childCount); + var childIndex = taskComponent.Index + 1; + for (int j = 0; j < childCount; ++j) { + orderArray[j] = (ushort)childIndex; + childIndex = taskComponents[childIndex].SiblingIndex; + } + randomSequenceComponent.TaskOrder = builder.CreateBlobAssetReference(Allocator.Persistent); + builder.Dispose(); + } + + // Generate a new random number seed for each entity. + if (randomSequenceComponent.RandomNumberGenerator.state == 0) { + randomSequenceComponent.RandomNumberGenerator = Unity.Mathematics.Random.CreateFromIndex(randomSequenceComponent.Seed != 0 ? randomSequenceComponent.Seed : (uint)entity.Index); + } + + // Use fisher-yates to shuffle the array in place. + ref var initialTaskOrder = ref randomSequenceComponent.TaskOrder.Value.Indicies; + var index = initialTaskOrder.Length; + while (index != 0) { + var randomUnitFloat = randomSequenceComponent.RandomNumberGenerator.NextFloat(); + var randomIndex = (int)Unity.Mathematics.math.floor(randomUnitFloat * index); + index--; + + var element = initialTaskOrder[randomIndex]; + initialTaskOrder[randomIndex] = initialTaskOrder[index]; + initialTaskOrder[index] = element; + } + + randomSequenceComponent.ActiveRelativeChildIndex = 0; + randomSequenceComponentsBuffer[i] = randomSequenceComponent; + + branchComponent.NextIndex = initialTaskOrder[randomSequenceComponent.ActiveRelativeChildIndex]; + branchComponentBuffer[taskComponent.BranchIndex] = branchComponent; + + // Start the child. + var nextChildTaskComponent = taskComponents[branchComponent.NextIndex]; + nextChildTaskComponent.Status = TaskStatus.Queued; + taskComponentsBuffer[branchComponent.NextIndex] = nextChildTaskComponent; + } else if (taskComponent.Status != TaskStatus.Running) { + continue; + } + + // The randomSequence task is currently active. Check the first child. + ref var taskOrder = ref randomSequenceComponent.TaskOrder.Value.Indicies; + var childTaskComponent = taskComponents[taskOrder[randomSequenceComponent.ActiveRelativeChildIndex]]; + if (childTaskComponent.Status == TaskStatus.Queued || childTaskComponent.Status == TaskStatus.Running) { + // The child should keep running. + continue; + } + + if (randomSequenceComponent.ActiveRelativeChildIndex == taskOrder.Length - 1 || childTaskComponent.Status == TaskStatus.Failure) { + // There are no more children or the child failed. The random sequence task should end. A task status of inactive indicates the last task was disabled. Return success. + taskComponent.Status = childTaskComponent.Status != TaskStatus.Inactive ? childTaskComponent.Status : TaskStatus.Success; + randomSequenceComponent.ActiveRelativeChildIndex = 0; + taskComponentsBuffer[randomSequenceComponent.Index] = taskComponent; + + branchComponent.NextIndex = taskComponent.ParentIndex; + branchComponentBuffer[taskComponent.BranchIndex] = branchComponent; + } else { + // The child task returned success. Move onto the next task. + randomSequenceComponent.ActiveRelativeChildIndex++; + var nextIndex = taskOrder[randomSequenceComponent.ActiveRelativeChildIndex]; + var nextTaskComponent = taskComponents[nextIndex]; + nextTaskComponent.Status = TaskStatus.Queued; + taskComponentsBuffer[nextIndex] = nextTaskComponent; + + branchComponent.NextIndex = nextIndex; + branchComponentBuffer[taskComponent.BranchIndex] = branchComponent; + } + randomSequenceComponentsBuffer[i] = randomSequenceComponent; + } + } + } + + /// + /// The task has been destroyed. + /// + /// The current state of the system. + private void OnDestroy(ref SystemState state) + { + foreach (var randomSequenceComponents in SystemAPI.Query>()) { + for (int i = 0; i < randomSequenceComponents.Length; ++i) { + var randomSequenceComponent = randomSequenceComponents[i]; + if (randomSequenceComponent.TaskOrder.IsCreated) { + randomSequenceComponent.TaskOrder.Dispose(); + } + } + } + } + } + + /// + /// An interrupt has occurred. Ensure the task state is correct after the interruption. + /// + [DisableAutoCreation] + public partial struct RandomSequenceInterruptSystem : ISystem + { + /// + /// Runs the logic after an interruption. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + foreach (var (taskComponents, randomSequenceComponents) in + SystemAPI.Query, DynamicBuffer>().WithAll()) { + for (int i = 0; i < randomSequenceComponents.Length; ++i) { + var randomSequenceComponent = randomSequenceComponents[i]; + // The active child will have a non-running status if it has been interrupted. + var taskComponent = taskComponents[randomSequenceComponent.Index]; + if (taskComponent.Status == TaskStatus.Running && taskComponents[randomSequenceComponent.TaskOrder.Value.Indicies[randomSequenceComponent.ActiveRelativeChildIndex]].Status != TaskStatus.Running) { + ushort relativeChildIndex = 0; + // Find the currently active task. + while (taskComponents[randomSequenceComponent.TaskOrder.Value.Indicies[relativeChildIndex]].Status != TaskStatus.Running) { + relativeChildIndex++; + } + randomSequenceComponent.ActiveRelativeChildIndex = relativeChildIndex; + var randomSequenceBuffer = randomSequenceComponents; + randomSequenceBuffer[i] = randomSequenceComponent; + } + } + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/RandomSequence.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/RandomSequence.cs.meta new file mode 100644 index 0000000..bd76250 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/RandomSequence.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d02a71e18382d8548b9f8f0a4834da93 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/Selector.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/Selector.cs new file mode 100644 index 0000000..c779a08 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/Selector.cs @@ -0,0 +1,258 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Composites +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.GraphDesigner.Runtime; + using Opsive.Shared.Utility; + using Unity.Entities; + using Unity.Burst; + using UnityEngine; + using System; + + /// + /// A node representation of the selector task. + /// + [NodeIcon("4c3d0559a9ebc604e88b16e9a3fdfa05", "de3acf0e386a26246b8bc999b1ef8e32")] + [Opsive.Shared.Utility.Description("The selector task is similar to an \"or\" operation. It will return success as soon as one of its child tasks return success. " + + "If a child task returns failure then it will sequentially run the next task. If no child task returns success then it will return failure.")] + public class Selector : ECSCompositeTask, IParentNode, IConditionalAbortParent, IInterruptResponder, ISavableTask, ICloneable + { + [Tooltip("Specifies how the child conditional tasks should be reevaluated.")] + [SerializeField] ConditionalAbortType m_AbortType; + + private ushort m_ComponentIndex; + + public ConditionalAbortType AbortType { get => m_AbortType; set => m_AbortType = value; } + public Type InterruptSystemType { get => typeof(SelectorInterruptSystem); } + + /// + /// The type of tag that should be enabled when the task is running. + /// + public override ComponentType Flag { get => typeof(SelectorFlag); } + + /// + /// Returns a new TBufferElement for use by the system. + /// + /// A new TBufferElement for use by the system. + public override SelectorComponent GetBufferElement() + { + return new SelectorComponent() { + Index = RuntimeIndex, + }; + } + + /// + /// Adds the IBufferElementData to the entity. + /// + /// The world that the entity exists in. + /// The entity that the IBufferElementData should be assigned to. + /// The GameObject that the entity is attached to. + /// The index of the element within the buffer. + public override int AddBufferElement(World world, Entity entity, GameObject gameObject) + { + m_ComponentIndex = (ushort)base.AddBufferElement(world, entity, gameObject); + return m_ComponentIndex; + } + + /// + /// Specifies the type of reflection that should be used to save the task. + /// + /// The index of the sub-task. This is used for the task set allowing each contained task to have their own save type. + public MemberVisibility GetSaveReflectionType(int index) { return MemberVisibility.None; } + + /// + /// Returns the current task state. + /// + /// The DOTS world. + /// The DOTS entity. + /// The current task state. + public object Save(World world, Entity entity) + { + var selectorComponents = world.EntityManager.GetBuffer(entity); + var selectorComponent = selectorComponents[m_ComponentIndex]; + + // Save the active child. + return selectorComponent.ActiveChildIndex; + } + + /// + /// Loads the previous task state. + /// + /// The previous task state. + /// The DOTS world. + /// The DOTS entity. + public void Load(object saveData, World world, Entity entity) + { + var selectorComponents = world.EntityManager.GetBuffer(entity); + var selectorComponent = selectorComponents[m_ComponentIndex]; + + // saveData is the active child. + selectorComponent.ActiveChildIndex = (ushort)saveData; + selectorComponents[m_ComponentIndex] = selectorComponent; + } + + /// + /// Creates a deep clone of the component. + /// + /// A deep clone of the component. + public object Clone() + { + var clone = Activator.CreateInstance(); + clone.Index = Index; + clone.ParentIndex = ParentIndex; + clone.SiblingIndex = SiblingIndex; + clone.AbortType = AbortType; + return clone; + } + } + + /// + /// The DOTS data structure for the Selector class. + /// + public struct SelectorComponent : IBufferElementData + { + [Tooltip("The index of the node.")] + public ushort Index; + [Tooltip("The index of the child that is currently active.")] + public ushort ActiveChildIndex; + } + + /// + /// A DOTS tag indicating when a Selector node is active. + /// + public struct SelectorFlag : IComponentData, IEnableableComponent { } + + /// + /// Runs the Selector logic. + /// + [DisableAutoCreation] + public partial struct SelectorTaskSystem : ISystem + { + /// + /// Creates the job. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + var query = SystemAPI.QueryBuilder().WithAllRW().WithAllRW().WithAllRW().WithAll().Build(); + state.Dependency = new SelectorJob().ScheduleParallel(query, state.Dependency); + } + + /// + /// Job which executes the task logic. + /// + [BurstCompile] + private partial struct SelectorJob : IJobEntity + { + /// + /// Executes the selector logic. + /// + /// An array of BranchComponents. + /// An array of TaskComponents. + /// An array of SelectorComponents. + [BurstCompile] + public void Execute(ref DynamicBuffer branchComponents, ref DynamicBuffer taskComponents, ref DynamicBuffer selectorComponents) + { + for (int i = 0; i < selectorComponents.Length; ++i) { + var selectorComponent = selectorComponents[i]; + var taskComponent = taskComponents[selectorComponent.Index]; + var branchComponent = branchComponents[taskComponent.BranchIndex]; + + // Do not continue if there will be an interrupt or the branch cannot execute. + if (branchComponent.InterruptType != InterruptType.None || !branchComponent.CanExecute) { + continue; + } + + if (taskComponent.Status == TaskStatus.Queued) { + taskComponent.Status = TaskStatus.Running; + taskComponents[taskComponent.Index] = taskComponent; + + selectorComponent.ActiveChildIndex = (ushort)(taskComponent.Index + 1); + selectorComponents[i] = selectorComponent; + + branchComponent.NextIndex = selectorComponent.ActiveChildIndex; + branchComponents[taskComponent.BranchIndex] = branchComponent; + + // Start the child. + var nextChildTaskComponent = taskComponents[branchComponent.NextIndex]; + nextChildTaskComponent.Status = TaskStatus.Queued; + taskComponents[branchComponent.NextIndex] = nextChildTaskComponent; + } else if (taskComponent.Status != TaskStatus.Running) { + continue; + } + + // The selector task is currently active. Check the first child. + var childTaskComponent = taskComponents[selectorComponent.ActiveChildIndex]; + if (childTaskComponent.Status == TaskStatus.Queued || childTaskComponent.Status == TaskStatus.Running) { + // The child should keep running. + continue; + } + + if (childTaskComponent.SiblingIndex == ushort.MaxValue || childTaskComponent.Status == TaskStatus.Success) { + // There are no more children or the child succeeded. The selector task should end. A task status of inactive indicates the last task was disabled. Return failure. + taskComponent.Status = childTaskComponent.Status != TaskStatus.Inactive ? childTaskComponent.Status : TaskStatus.Failure; + selectorComponent.ActiveChildIndex = (ushort)(selectorComponent.Index + 1); + taskComponents[selectorComponent.Index] = taskComponent; + + branchComponent.NextIndex = taskComponent.ParentIndex; + branchComponents[taskComponent.BranchIndex] = branchComponent; + } else { + // The previous task is no longer running. + var siblingTaskComponent = taskComponents[childTaskComponent.SiblingIndex]; + + siblingTaskComponent.Status = TaskStatus.Queued; + taskComponents[childTaskComponent.SiblingIndex] = siblingTaskComponent; + // The current index is now the sibling index. + selectorComponent.ActiveChildIndex = childTaskComponent.SiblingIndex; + + branchComponent.NextIndex = selectorComponent.ActiveChildIndex; + branchComponents[taskComponent.BranchIndex] = branchComponent; + } + selectorComponents[i] = selectorComponent; + } + } + } + } + + /// + /// An interrupt has occurred. Ensure the task state is correct after the interruption. + /// + [DisableAutoCreation] + public partial struct SelectorInterruptSystem : ISystem + { + /// + /// Runs the logic after an interruption. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + foreach (var (taskComponents, selectorComponents) in + SystemAPI.Query, DynamicBuffer>().WithAll()) { + for (int i = 0; i < selectorComponents.Length; ++i) { + var selectorComponent = selectorComponents[i]; + // The active child will have a non-running status if it has been interrupted. + if (taskComponents[selectorComponent.ActiveChildIndex].Status != TaskStatus.Running) { + var childIndex = (ushort)(selectorComponent.Index + 1); + // Find the currently active task. + while (childIndex != ushort.MaxValue && taskComponents[childIndex].Status != TaskStatus.Running) { + childIndex = taskComponents[childIndex].SiblingIndex; + } + if (childIndex != ushort.MaxValue) { + selectorComponent.ActiveChildIndex = childIndex; + } + var selectorBuffer = selectorComponents; + selectorBuffer[i] = selectorComponent; + } + } + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/Selector.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/Selector.cs.meta new file mode 100644 index 0000000..6315eeb --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/Selector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9b0cbe842d363e545a41d9ac600430a3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/Sequence.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/Sequence.cs new file mode 100644 index 0000000..172efd1 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/Sequence.cs @@ -0,0 +1,257 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Composites +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.GraphDesigner.Runtime; + using Opsive.Shared.Utility; + using Unity.Burst; + using Unity.Entities; + using UnityEngine; + using System; + + /// + /// A node representation of the sequence task. + /// + [NodeIcon("8981cc246f900b24da46ae10eb49b68b", "4a7b39d8e0d056a4a9d8eb390b4bc9b8")] + [Opsive.Shared.Utility.Description("The sequence task is similar to an \"and\" operation. It will return failure as soon as one of its child tasks return failure. " + + "If a child task returns success then it will sequentially run the next task. If all child tasks return success then it will return success.")] + public class Sequence : ECSCompositeTask, IParentNode, IConditionalAbortParent, IInterruptResponder, ISavableTask, ICloneable + { + [Tooltip("Specifies how the child conditional tasks should be reevaluated.")] + [SerializeField] ConditionalAbortType m_AbortType; + + private ushort m_ComponentIndex; + + public ConditionalAbortType AbortType { get => m_AbortType; set => m_AbortType = value; } + public Type InterruptSystemType { get => typeof(SequenceInterruptSystem); } + + /// + /// The type of tag that should be enabled when the task is running. + /// + public override ComponentType Flag { get => typeof(SequenceFlag); } + + /// + /// Returns a new TBufferElement for use by the system. + /// + /// A new TBufferElement for use by the system. + public override SequenceComponent GetBufferElement() + { + return new SequenceComponent() { + Index = RuntimeIndex, + }; + } + + /// + /// Adds the IBufferElementData to the entity. + /// + /// The world that the entity exists in. + /// The entity that the IBufferElementData should be assigned to. + /// The GameObject that the entity is attached to. + /// The index of the element within the buffer. + public override int AddBufferElement(World world, Entity entity, GameObject gameObject) + { + m_ComponentIndex = (ushort)base.AddBufferElement(world, entity, gameObject); + return m_ComponentIndex; + } + + /// + /// Specifies the type of reflection that should be used to save the task. + /// + /// The index of the sub-task. This is used for the task set allowing each contained task to have their own save type. + public MemberVisibility GetSaveReflectionType(int index) { return MemberVisibility.None; } + + /// + /// Returns the current task state. + /// + /// The DOTS world. + /// The DOTS entity. + /// The current task state. + public object Save(World world, Entity entity) + { + var sequenceComponents = world.EntityManager.GetBuffer(entity); + var sequenceComponent = sequenceComponents[m_ComponentIndex]; + + // Save the active child. + return sequenceComponent.ActiveChildIndex; + } + + /// + /// Loads the previous task state. + /// + /// The previous task state. + /// The DOTS world. + /// The DOTS entity. + public void Load(object saveData, World world, Entity entity) + { + var sequenceComponents = world.EntityManager.GetBuffer(entity); + var sequenceComponent = sequenceComponents[m_ComponentIndex]; + + // saveData is the active child. + sequenceComponent.ActiveChildIndex = (ushort)saveData; + sequenceComponents[m_ComponentIndex] = sequenceComponent; + } + + /// + /// Creates a deep clone of the component. + /// + /// A deep clone of the component. + public object Clone() + { + var clone = Activator.CreateInstance(); + clone.Index = Index; + clone.ParentIndex = ParentIndex; + clone.SiblingIndex = SiblingIndex; + clone.AbortType = AbortType; + return clone; + } + } + + /// + /// The DOTS data structure for the Sequence class. + /// + public struct SequenceComponent : IBufferElementData + { + [Tooltip("The index of the node.")] + public ushort Index; + [Tooltip("The index of the child that is currently active.")] + public ushort ActiveChildIndex; + } + + /// + /// A DOTS tag indicating when a Sequence node is active. + /// + public struct SequenceFlag : IComponentData, IEnableableComponent { } + + /// + /// Runs the Sequence logic. + /// + [DisableAutoCreation] + public partial struct SequenceTaskSystem : ISystem + { + /// + /// Creates the job. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + var query = SystemAPI.QueryBuilder().WithAllRW().WithAllRW().WithAllRW().WithAll().Build(); + state.Dependency = new SequenceJob().ScheduleParallel(query, state.Dependency); + } + + /// + /// Job which executes the task logic. + /// + [BurstCompile] + private partial struct SequenceJob : IJobEntity + { + /// + /// Executes the sequence logic. + /// + /// An array of BranchComponents. + /// An array of TaskComponents. + /// An array of SequenceComponents. + [BurstCompile] + public void Execute(ref DynamicBuffer branchComponents, ref DynamicBuffer taskComponents, ref DynamicBuffer sequenceComponents) + { + for (int i = 0; i < sequenceComponents.Length; ++i) { + var sequenceComponent = sequenceComponents[i]; + var taskComponent = taskComponents[sequenceComponent.Index]; + var branchComponent = branchComponents[taskComponent.BranchIndex]; + + // Do not continue if there will be an interrupt or the branch cannot execute. + if (branchComponent.InterruptType != InterruptType.None || !branchComponent.CanExecute) { + continue; + } + + if (taskComponent.Status == TaskStatus.Queued) { + taskComponent.Status = TaskStatus.Running; + taskComponents[taskComponent.Index] = taskComponent; + + sequenceComponent.ActiveChildIndex = (ushort)(taskComponent.Index + 1); + sequenceComponents[i] = sequenceComponent; + + branchComponent.NextIndex = sequenceComponent.ActiveChildIndex; + branchComponents[taskComponent.BranchIndex] = branchComponent; + + // Start the child. + var nextChildTaskComponent = taskComponents[branchComponent.NextIndex]; + nextChildTaskComponent.Status = TaskStatus.Queued; + taskComponents[branchComponent.NextIndex] = nextChildTaskComponent; + } else if (taskComponent.Status != TaskStatus.Running) { + continue; + } + + // The sequence task is currently active. Check the first child. + var childTaskComponent = taskComponents[sequenceComponent.ActiveChildIndex]; + if (childTaskComponent.Status == TaskStatus.Queued || childTaskComponent.Status == TaskStatus.Running) { + // The child should keep running. + continue; + } + + if (childTaskComponent.SiblingIndex == ushort.MaxValue || childTaskComponent.Status == TaskStatus.Failure) { + // There are no more children or the child failed. The sequence task should end. A task status of inactive indicates the last task was disabled. Return success. + taskComponent.Status = childTaskComponent.Status != TaskStatus.Inactive ? childTaskComponent.Status : TaskStatus.Success; + sequenceComponent.ActiveChildIndex = (ushort)(sequenceComponent.Index + 1); + taskComponents[sequenceComponent.Index] = taskComponent; + + branchComponent.NextIndex = taskComponent.ParentIndex; + branchComponents[taskComponent.BranchIndex] = branchComponent; + } else { + // The previous task is no longer running. + var siblingTaskComponent = taskComponents[childTaskComponent.SiblingIndex]; + + siblingTaskComponent.Status = TaskStatus.Queued; + taskComponents[childTaskComponent.SiblingIndex] = siblingTaskComponent; + // The current index is now the sibling index. + sequenceComponent.ActiveChildIndex = childTaskComponent.SiblingIndex; + + branchComponent.NextIndex = sequenceComponent.ActiveChildIndex; + branchComponents[taskComponent.BranchIndex] = branchComponent; + } + sequenceComponents[i] = sequenceComponent; + } + } + } + } + + /// + /// An interrupt has occurred. Ensure the task state is correct after the interruption. + /// + [DisableAutoCreation] + public partial struct SequenceInterruptSystem : ISystem + { + /// + /// Runs the logic after an interruption. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + foreach (var (taskComponents, sequenceComponents) in + SystemAPI.Query, DynamicBuffer>().WithAll()) { + for (int i = 0; i < sequenceComponents.Length; ++i) { + var sequenceComponent = sequenceComponents[i]; + if (taskComponents[sequenceComponent.ActiveChildIndex].Status != TaskStatus.Running) { + var childIndex = (ushort)(sequenceComponent.Index + 1); + // Find the currently active task. + while (childIndex != ushort.MaxValue && taskComponents[childIndex].Status != TaskStatus.Running) { + childIndex = taskComponents[childIndex].SiblingIndex; + } + if (childIndex != ushort.MaxValue) { + sequenceComponent.ActiveChildIndex = childIndex; + } + var sequenceBuffer = sequenceComponents; + sequenceBuffer[i] = sequenceComponent; + } + } + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/Sequence.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/Sequence.cs.meta new file mode 100644 index 0000000..8fcffd3 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/Sequence.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 519b18064a01b25499eb333d144065c0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/UtilitySelector.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/UtilitySelector.cs new file mode 100644 index 0000000..0d2a200 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/UtilitySelector.cs @@ -0,0 +1,361 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Composites +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.BehaviorDesigner.Runtime.Utility; + using Opsive.GraphDesigner.Runtime; + using Opsive.Shared.Utility; + using Unity.Collections; + using Unity.Entities; + using Unity.Burst; + using UnityEngine; + using System; + + /// + /// A node representation of the utility selector task. + /// + [NodeIcon("9d36cd363c3e08246a6e9eaf5ad99d69", "db3d0b77c7f9e0b4f9157aa03178836a")] + [Opsive.Shared.Utility.Description("The utility selector task evaluates the child tasks using Utility Theory AI. The child task can return the utility value " + + "at that particular time. The task with the highest utility value will be selected and the existing running task will be aborted. The utility selector " + + "task reevaluates its children every tick.")] + public class UtilitySelector : ECSCompositeTask, IParentNode, ISavableTask, ICloneable + { + private ushort m_ComponentIndex; + + public override ComponentType Flag { get => typeof(UtilitySelectorFlag); } + + /// + /// Returns a new TBufferElement for use by the system. + /// + /// A new TBufferElement for use by the system. + public override UtilitySelectorComponent GetBufferElement() + { + return new UtilitySelectorComponent() + { + Index = RuntimeIndex, + }; + } + + /// + /// Adds the IBufferElementData to the entity. + /// + /// The world that the entity exists in. + /// The entity that the IBufferElementData should be assigned to. + /// The GameObject that the entity is attached to. + /// The index of the element within the buffer. + public override int AddBufferElement(World world, Entity entity, GameObject gameObject) + { + m_ComponentIndex = (ushort)base.AddBufferElement(world, entity, gameObject); + ComponentUtility.AddInterruptComponents(world.EntityManager, entity); + return m_ComponentIndex; + } + + /// + /// Specifies the type of reflection that should be used to save the task. + /// + /// The index of the sub-task. This is used for the task set allowing each contained task to have their own save type. + public MemberVisibility GetSaveReflectionType(int index) { return MemberVisibility.None; } + + /// + /// Returns the current task state. + /// + /// The DOTS world. + /// The DOTS entity. + /// The current task state. + public object Save(World world, Entity entity) + { + var utilitySelectorComponents = world.EntityManager.GetBuffer(entity); + var utilitySelectorComponent = utilitySelectorComponents[m_ComponentIndex]; + + // Save the active child. + return utilitySelectorComponent.ActiveChildIndex; + } + + /// + /// Loads the previous task state. + /// + /// The previous task state. + /// The DOTS world. + /// The DOTS entity. + public void Load(object saveData, World world, Entity entity) + { + var utilitySelectorComponents = world.EntityManager.GetBuffer(entity); + var utilitySelectorComponent = utilitySelectorComponents[m_ComponentIndex]; + + // saveData is the active child index. + utilitySelectorComponent.ActiveChildIndex = (ushort)saveData; + utilitySelectorComponents[m_ComponentIndex] = utilitySelectorComponent; + } + + /// + /// Creates a deep clone of the component. + /// + /// A deep clone of the component. + public object Clone() + { + var clone = Activator.CreateInstance(); + clone.Index = Index; + clone.ParentIndex = ParentIndex; + clone.SiblingIndex = SiblingIndex; + return clone; + } + } + + /// + /// The DOTS data structure for the UtilitySelector class. + /// + public struct UtilitySelectorComponent : IBufferElementData + { + [Tooltip("The index of the node.")] + public ushort Index; + [Tooltip("The index of the child that is currently active.")] + public ushort ActiveChildIndex; + [Tooltip("The index of the UtilityValueComponent that corresponds to each child.")] + public NativeArray UtilityItems; + + /// + /// A mapping between the UnityValueComponent and the task. + /// + public struct UtilityItem + { + [Tooltip("The index of the task.")] + public ushort TaskIndex; + [Tooltip("The index of the UtilityValueComponent.")] + public ushort UtilityValueIndex; + [Tooltip("Can the task continue to exectute?")] + public bool CanExecute; + } + } + + /// + /// DOTS structure that contains the most recently utility of the task. + /// + public struct UtilityValueComponent : IBufferElementData + { + [Tooltip("The index of the task.")] + public ushort Index; + [Tooltip("The current utility value. The higher the value the more likely it will be selected.")] + public float Value; + } + + /// + /// A DOTS tag indicating when a UtilitySelector node is active. + /// + public struct UtilitySelectorFlag : IComponentData, IEnableableComponent { } + + /// + /// Runs the UtilitySelector logic. + /// + [DisableAutoCreation] + public partial struct UtilitySelectorTaskSystem : ISystem + { + /// + /// Updates the logic. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + var hasUtilityValueComponent = false; + foreach (var (utilitySelectorComponents, utilityValueComponents, taskComponents, branchComponents, entity) in + SystemAPI.Query, DynamicBuffer, DynamicBuffer, DynamicBuffer>().WithAll().WithEntityAccess()) { + + hasUtilityValueComponent = true; + for (int i = 0; i < utilitySelectorComponents.Length; ++i) { + var utilitySelectorComponent = utilitySelectorComponents[i]; + var taskComponent = taskComponents[utilitySelectorComponent.Index]; + var branchComponent = branchComponents[taskComponent.BranchIndex]; + + // Do not continue if there will be an interrupt or the branch cannot execute. + if (branchComponent.InterruptType != InterruptType.None || !branchComponent.CanExecute) { + continue; + } + + var utilitySelectorComponentsBuffer = utilitySelectorComponents; + var utilityValueComponentBuffer = utilityValueComponents; + var taskComponentsBuffer = taskComponents; + var branchComponentBuffer = branchComponents; + if (taskComponent.Status == TaskStatus.Queued) { + // Initialize the UtilityItem array. + if (utilitySelectorComponent.UtilityItems.Length == 0) { + var childCount = TraversalUtility.GetImmediateChildCount(ref taskComponent, ref taskComponentsBuffer); + var utilityItems = new NativeArray(childCount, Allocator.Persistent); + // Match the UtilitySelectorComponent with the child index. + var childIndex = (ushort)(taskComponent.Index + 1); + for (ushort j = 0; j < childCount; ++j) { + utilityItems[j] = new UtilitySelectorComponent.UtilityItem() { TaskIndex = childIndex, UtilityValueIndex = ushort.MaxValue, CanExecute = !taskComponents[childIndex].Disabled }; + + for (ushort k = 0; k < utilityValueComponents.Length; ++k) { + var utilityValueComponent = utilityValueComponents[k]; + if (utilityValueComponent.Index == childIndex) { + var utilityItem = utilityItems[j]; + utilityItem.UtilityValueIndex = k; + utilityItems[j] = utilityItem; + break; + } + } + childIndex = taskComponents[childIndex].SiblingIndex; + } + + utilitySelectorComponent.UtilityItems = utilityItems; + } else { + // Reset the execution status. + var childIndex = (ushort)(taskComponent.Index + 1); + for (int j = 0; j < utilitySelectorComponent.UtilityItems.Length; ++j) { + var utilityItem = utilitySelectorComponent.UtilityItems[j]; + utilityItem.CanExecute = !taskComponents[childIndex].Disabled; + utilitySelectorComponent.UtilityItems[j] = utilityItem; + + childIndex = taskComponents[childIndex].SiblingIndex; + } + } + + utilitySelectorComponent.ActiveChildIndex = GetHighestUtility(utilitySelectorComponent.UtilityItems, ref utilityValueComponentBuffer); + utilitySelectorComponentsBuffer[i] = utilitySelectorComponent; + + if (utilitySelectorComponent.ActiveChildIndex == ushort.MaxValue) { + taskComponent.Status = TaskStatus.Failure; + branchComponent.NextIndex = taskComponent.ParentIndex; + } else { + taskComponent.Status = TaskStatus.Running; + branchComponent.NextIndex = utilitySelectorComponent.UtilityItems[utilitySelectorComponent.ActiveChildIndex].TaskIndex; + + // Start the child. + var nextChildTaskComponent = taskComponents[branchComponent.NextIndex]; + nextChildTaskComponent.Status = TaskStatus.Queued; + taskComponentsBuffer[branchComponent.NextIndex] = nextChildTaskComponent; + } + taskComponentsBuffer[taskComponent.Index] = taskComponent; + branchComponentBuffer[taskComponent.BranchIndex] = branchComponent; + + continue; + } else if (taskComponent.Status != TaskStatus.Running) { + continue; + } + + var childTaskComponent = taskComponents[utilitySelectorComponent.UtilityItems[utilitySelectorComponent.ActiveChildIndex].TaskIndex]; + if (childTaskComponent.Status == TaskStatus.Success) { + // The child has returned success. Stop the selector. + taskComponent.Status = childTaskComponent.Status; + taskComponentsBuffer[utilitySelectorComponent.Index] = taskComponent; + branchComponent.NextIndex = taskComponent.ParentIndex; + branchComponentBuffer[taskComponent.BranchIndex] = branchComponent; + continue; + } else if (childTaskComponent.Status == TaskStatus.Failure) { + var utilityItem = utilitySelectorComponent.UtilityItems[utilitySelectorComponent.ActiveChildIndex]; + utilityItem.CanExecute = false; + utilitySelectorComponent.UtilityItems[utilitySelectorComponent.ActiveChildIndex] = utilityItem; + + utilitySelectorComponentsBuffer[i] = utilitySelectorComponent; + } + + // The active task returned failure or is currently running. Determine if the active task needs to change. + var highestIndex = GetHighestUtility(utilitySelectorComponent.UtilityItems, ref utilityValueComponentBuffer); + if (highestIndex == utilitySelectorComponent.ActiveChildIndex) { + // No changes are necessary. + continue; + } + + var activeTaskIndex = utilitySelectorComponent.UtilityItems[utilitySelectorComponent.ActiveChildIndex].TaskIndex; + utilitySelectorComponent.ActiveChildIndex = highestIndex; + utilitySelectorComponentsBuffer[i] = utilitySelectorComponent; + + // A new branch has been selected. Trigger an interrupt on the currently active branch. + if (taskComponents[activeTaskIndex].Status == TaskStatus.Running){ + branchComponent.InterruptType = InterruptType.Branch; + branchComponent.InterruptIndex = utilitySelectorComponent.UtilityItems[highestIndex].TaskIndex; + state.EntityManager.SetComponentEnabled(entity, true); + branchComponentBuffer[taskComponent.BranchIndex] = branchComponent; + continue; + } + + // No more tasks may need to run. + if (highestIndex == ushort.MaxValue) { + taskComponent.Status = TaskStatus.Failure; + taskComponentsBuffer[utilitySelectorComponent.Index] = taskComponent; + + branchComponent.NextIndex = taskComponent.ParentIndex; + } else { + // Run the task with the next highest utility value. + var nextTaskIndex = utilitySelectorComponent.UtilityItems[utilitySelectorComponent.ActiveChildIndex].TaskIndex; + var nextTaskComponent = taskComponents[nextTaskIndex]; + nextTaskComponent.Status = TaskStatus.Queued; + taskComponentsBuffer[nextTaskIndex] = nextTaskComponent; + + branchComponent.NextIndex = nextTaskIndex; + } + branchComponentBuffer[taskComponent.BranchIndex] = branchComponent; + } + } + + // Special case where the UtilitySelectorComponent has no UtilityValueComponent children. + if (!hasUtilityValueComponent) { + foreach (var (utilitySelectorComponents, taskComponents, branchComponents) in + SystemAPI.Query, DynamicBuffer, DynamicBuffer>().WithAll()) { + + for (int i = 0; i < utilitySelectorComponents.Length; ++i) { + var utilitySelectorComponent = utilitySelectorComponents[i]; + var taskComponent = taskComponents[utilitySelectorComponent.Index]; + + // If there are no values then the selector should return failure. + if (taskComponent.Status == TaskStatus.Queued && utilitySelectorComponent.UtilityItems.Length == 0) { + taskComponent.Status = TaskStatus.Failure; + var taskComponentsBuffer = taskComponents; + taskComponentsBuffer[utilitySelectorComponent.Index] = taskComponent; + + var branchComponent = branchComponents[taskComponent.BranchIndex]; + branchComponent.NextIndex = taskComponent.ParentIndex; + var branchComponentBuffer = branchComponents; + branchComponentBuffer[taskComponent.BranchIndex] = branchComponent; + } + } + } + } + } + + /// + /// Retruns the task index with the highest utility value. + /// + /// The components with utility values. + /// The utility values of the tasks. + /// The task with the highest utility value. + [BurstCompile] + private ushort GetHighestUtility(NativeArray utilityItems, ref DynamicBuffer utilityValueComponents) + { + var utilityIndex = ushort.MaxValue; + var highestUtility = float.MinValue; + for (ushort i = 0; i < utilityItems.Length; ++i) { + if (utilityItems[i].UtilityValueIndex == ushort.MaxValue || !utilityItems[i].CanExecute) { + continue; + } + + var utilityValue = utilityValueComponents[utilityItems[i].UtilityValueIndex].Value; + if (utilityValue > highestUtility) { + highestUtility = utilityValue; + utilityIndex = i; + } + } + + return utilityIndex; + } + + /// + /// The task has been destroyed. + /// + /// The current state of the system. + private void OnDestroy(ref SystemState state) + { + foreach (var utilitySelectorComponents in SystemAPI.Query>()) { + for (int i = 0; i < utilitySelectorComponents.Length; ++i) { + utilitySelectorComponents[i].UtilityItems.Dispose(); + } + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/UtilitySelector.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/UtilitySelector.cs.meta new file mode 100644 index 0000000..042d5bc --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Composites/UtilitySelector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c68beac686ca75c42879aee6c864fc5e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/ConditionalAbortType.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/ConditionalAbortType.cs new file mode 100644 index 0000000..84e4f21 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/ConditionalAbortType.cs @@ -0,0 +1,28 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks +{ + /// + /// Specifies that the task can interrupt using conditional aborts. + /// + public interface IConditionalAbortParent + { + ConditionalAbortType AbortType { get; } + } + + /// + /// The type of conditional abort. + /// + public enum ConditionalAbortType : byte + { + None, // No abort specified. + LowerPriority, // Any task to the right of the current branch can be aborted. + Self, // Any task within the current branch can be aborted. + Both // A combination of LowerPriority and Self. + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/ConditionalAbortType.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/ConditionalAbortType.cs.meta new file mode 100644 index 0000000..a58f477 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/ConditionalAbortType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c8d72bd503b98814ca0c5cbc857cd014 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals.meta new file mode 100644 index 0000000..0f2fa6c --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0a0792e3d1b870e4dad5e75b17c12724 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Conditional.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Conditional.cs new file mode 100644 index 0000000..4fec6b7 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Conditional.cs @@ -0,0 +1,25 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.GraphDesigner.Runtime; + + /// + /// A TaskObject implementation of the Conditional task. + /// + [NodeIcon("dea5c23eac9d12c4cbd380cc879816ea", "2963cf3eb0c036449829254b2074c4c3")] + public abstract class Conditional : Task, IConditional, IConditionalReevaluation + { + /// + /// Reevaluates the task logic. Returns a TaskStatus indicating how the behavior tree flow should proceed. + /// + /// The status of the task during the reevaluation phase. + public virtual TaskStatus OnReevaluateUpdate() { return OnUpdate(); } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Conditional.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Conditional.cs.meta new file mode 100644 index 0000000..6248e7c --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Conditional.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3a2db972855f8ce48b67b75699c1745a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/ConditionalNode.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/ConditionalNode.cs new file mode 100644 index 0000000..1fc8cce --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/ConditionalNode.cs @@ -0,0 +1,37 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals +{ + using Opsive.GraphDesigner.Runtime; + using UnityEngine; + + /// + /// A TaskObject implementation of the Conditional task. This class can be used when the task should not be grouped by the StackedConditional task. + /// + [NodeIcon("dea5c23eac9d12c4cbd380cc879816ea", "2963cf3eb0c036449829254b2074c4c3")] + public abstract class ConditionalNode : Task, ITreeLogicNode, IConditional, IConditionalReevaluation + { + [Tooltip("The index of the node.")] + [SerializeField] ushort m_Index; + [Tooltip("The parent index of the node. ushort.MaxValue indicates no parent.")] + [SerializeField] ushort m_ParentIndex; + [Tooltip("The sibling index of the node. ushort.MaxValue indicates no sibling.")] + [SerializeField] ushort m_SiblingIndex; + + public ushort Index { get => m_Index; set => m_Index = value; } + public ushort ParentIndex { get => m_ParentIndex; set => m_ParentIndex = value; } + public ushort SiblingIndex { get => m_SiblingIndex; set => m_SiblingIndex = value; } + public ushort RuntimeIndex { get; set; } + + /// + /// Reevaluates the task logic. Returns a TaskStatus indicating how the behavior tree flow should proceed. + /// + /// The status of the task during the reevaluation phase. + public virtual TaskStatus OnReevaluateUpdate() { return OnUpdate(); } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/ConditionalNode.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/ConditionalNode.cs.meta new file mode 100644 index 0000000..ea1205b --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/ConditionalNode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5a27f55166c97394ba777a25ede3e192 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/HasReceivedEvent.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/HasReceivedEvent.cs new file mode 100644 index 0000000..1f6e6a3 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/HasReceivedEvent.cs @@ -0,0 +1,262 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using Opsive.Shared.Events; + using UnityEngine; + + /// + /// A TaskObject implementation of the Conditional task. This class can be used when the task should not be grouped by the StackedConditional task. + /// + [NodeIcon("e6fc90c130121da4f9067b5e15b02975", "69959064b54a0cb4cb077dbb6967a3e1")] + [Opsive.Shared.Utility.Description("Returns success as soon as the event specified by eventName has been received.")] + public class HasReceivedEvent : TargetBehaviorTreeConditional + { + [Tooltip("The name of the event that should be registered.")] + [SerializeField] protected SharedVariable m_EventName; + [Tooltip("Is the event a global event?")] + [SerializeField] protected SharedVariable m_GlobalEvent; + [Tooltip("Optionally store the first sent argument.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoredValue1; + [Tooltip("Optionally store the second sent argument.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoredValue2; + [Tooltip("Optionally store the third sent argument.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoredValue3; + + private string m_RegisteredEventName; + private bool m_EventRegistered; + private bool m_EventReceived; + private bool m_ResetEventReceived = true; + + /// + /// The behavior tree has started. + /// + public override void OnBehaviorTreeStarted() + { + base.OnBehaviorTreeStarted(); + + RegisterEvents(); + } + + /// + /// Initializes the target behavior tree. + /// + protected override void InitializeTarget() + { + if (m_ResolvedBehaviorTree != null) { + UnregisterEvents(); + } + + base.InitializeTarget(); + + RegisterEvents(); + } + + /// + /// Registers for the events. + /// + private void RegisterEvents() + { + if (m_EventRegistered) { + return; + } + + if (string.IsNullOrEmpty(m_EventName.Value)) { + Debug.LogError("Error: Unable to receive event. The event name is empty."); + return; + } + + if (m_StoredValue1 == null || !m_StoredValue1.IsShared) { + if (m_GlobalEvent.Value) { + EventHandler.RegisterEvent(m_EventName.Value, ReceivedEvent); + } else { + EventHandler.RegisterEvent(m_ResolvedBehaviorTree, m_EventName.Value, ReceivedEvent); + } + } else { + if (m_StoredValue2 == null || !m_StoredValue2.IsShared) { + if (m_GlobalEvent.Value) { + EventHandler.RegisterEvent(m_EventName.Value, ReceivedEvent); + } else { + EventHandler.RegisterEvent(m_ResolvedBehaviorTree, m_EventName.Value, ReceivedEvent); + } + } else { + if (m_StoredValue3 == null || !m_StoredValue3.IsShared) { + if (m_GlobalEvent.Value) { + EventHandler.RegisterEvent(m_EventName.Value, ReceivedEvent); + } else { + EventHandler.RegisterEvent(m_ResolvedBehaviorTree, m_EventName.Value, ReceivedEvent); + } + } else { + if (m_GlobalEvent.Value) { + EventHandler.RegisterEvent(m_EventName.Value, ReceivedEvent); + } else { + EventHandler.RegisterEvent(m_ResolvedBehaviorTree, m_EventName.Value, ReceivedEvent); + } + } + } + } + + m_EventName.OnValueChange += UpdateEvents; + if (m_StoredValue1 != null) { m_StoredValue1.OnValueChange += UpdateEvents; } + if (m_StoredValue2 != null) { m_StoredValue2.OnValueChange += UpdateEvents; } + if (m_StoredValue3 != null) { m_StoredValue3.OnValueChange += UpdateEvents; } + + m_EventRegistered = true; + m_RegisteredEventName = m_EventName.Value; + } + + /// + /// The event name or parameter count has changed. Update the events. + /// + private void UpdateEvents() + { + UnregisterEvents(); + RegisterEvents(); + } + + /// + /// A parameterless event has been recevied. + /// + private void ReceivedEvent() + { + m_EventReceived = true; + } + + /// + /// A single parameter event has been received. + /// + /// The first parameter. + private void ReceivedEvent(object arg1) + { + m_EventReceived = true; + + if (m_StoredValue1 != null && m_StoredValue1.IsShared) { m_StoredValue1.SetValue(arg1); } + } + + /// + /// A two parameter event has been received. + /// + /// The first parameter. + /// The second parameter. + private void ReceivedEvent(object arg1, object arg2) + { + m_EventReceived = true; + + if (m_StoredValue1 != null && m_StoredValue1.IsShared) { m_StoredValue1.SetValue(arg1); } + if (m_StoredValue2 != null && m_StoredValue2.IsShared) { m_StoredValue2.SetValue(arg2); } + } + + /// + /// A three parameter event has been received. + /// + /// The first parameter. + /// The second parameter. + /// The third parameter. + private void ReceivedEvent(object arg1, object arg2, object arg3) + { + m_EventReceived = true; + + if (m_StoredValue1 != null && m_StoredValue1.IsShared) { m_StoredValue1.SetValue(arg1); } + if (m_StoredValue2 != null && m_StoredValue2.IsShared) { m_StoredValue2.SetValue(arg2); } + if (m_StoredValue3 != null && m_StoredValue3.IsShared) { m_StoredValue3.SetValue(arg3); } + } + + /// + /// Callback when the task is started. + /// + public override void OnStart() + { + base.OnStart(); + + if (m_ResetEventReceived) { + m_EventReceived = false; + } + } + + /// + /// The task has been updated. + /// + /// True if an event has been received. + public override TaskStatus OnUpdate() + { + return m_EventReceived ? TaskStatus.Success : TaskStatus.Failure; + } + + /// + /// Reevaluates the task logic. + /// + /// The status of the task during the reevaluation phase. + public override TaskStatus OnReevaluateUpdate() + { + if (m_EventReceived) { + // OnStart/OnUpdate will be called immediately after the task is reevaluated. Do not reset the receive status. + m_ResetEventReceived = false; + return TaskStatus.Success; + } + return TaskStatus.Failure; + } + + /// + /// The task has ended. + /// + public override void OnEnd() + { + base.OnEnd(); + + m_EventReceived = false; + m_ResetEventReceived = true; + } + + /// + /// The behavior tree has been stopped. + /// + /// Is the behavior tree paused? + public override void OnBehaviorTreeStopped(bool paused) + { + base.OnBehaviorTreeStopped(paused); + + UnregisterEvents(); + m_EventReceived = false; + m_ResetEventReceived = true; + } + + /// + /// Unregisters for the events that were registered. + /// + private void UnregisterEvents() + { + // The events must be registered first in order to be unregistered. + if (string.IsNullOrEmpty(m_RegisteredEventName)) { + return; + } + + // Unregister from all parameters. This will ensure no events are subscribed if the parameters change. + if (m_GlobalEvent.Value) { + EventHandler.UnregisterEvent(m_RegisteredEventName, ReceivedEvent); + EventHandler.UnregisterEvent(m_RegisteredEventName, ReceivedEvent); + EventHandler.UnregisterEvent(m_RegisteredEventName, ReceivedEvent); + EventHandler.UnregisterEvent(m_RegisteredEventName, ReceivedEvent); + } else { + EventHandler.UnregisterEvent(m_ResolvedBehaviorTree, m_RegisteredEventName, ReceivedEvent); + EventHandler.UnregisterEvent(m_ResolvedBehaviorTree, m_RegisteredEventName, ReceivedEvent); + EventHandler.UnregisterEvent(m_ResolvedBehaviorTree, m_RegisteredEventName, ReceivedEvent); + EventHandler.UnregisterEvent(m_ResolvedBehaviorTree, m_RegisteredEventName, ReceivedEvent); + } + + m_EventName.OnValueChange -= UpdateEvents; + if (m_StoredValue1 != null) { m_StoredValue1.OnValueChange -= UpdateEvents; } + if (m_StoredValue2 != null) { m_StoredValue2.OnValueChange -= UpdateEvents; } + if (m_StoredValue3 != null) { m_StoredValue3.OnValueChange -= UpdateEvents; } + + m_EventRegistered = false; + m_RegisteredEventName = string.Empty; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/HasReceivedEvent.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/HasReceivedEvent.cs.meta new file mode 100644 index 0000000..67b2e30 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/HasReceivedEvent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3c2c0606584fdc345a81cf527b283e30 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/HasValue.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/HasValue.cs new file mode 100644 index 0000000..b6f4998 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/HasValue.cs @@ -0,0 +1,38 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using System.Collections; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Returns true if the specified variable has a value.")] + public class HasValue : Conditional + { + [Tooltip("The variable to compare.")] + [SerializeField] protected SharedVariable m_Variable; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + object variableValue = null; + if (m_Variable == null || (variableValue = m_Variable.GetValue()) == null || variableValue.Equals(null)) { + return TaskStatus.Failure; + } + + if (variableValue is IList listValue) { + return listValue.Count > 0 ? TaskStatus.Success : TaskStatus.Failure; + } + return TaskStatus.Success; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/HasValue.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/HasValue.cs.meta new file mode 100644 index 0000000..fd2ccaf --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/HasValue.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e1e162d80f7bf49419493fe43c33c0a5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/IsBehaviorTreeActive.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/IsBehaviorTreeActive.cs new file mode 100644 index 0000000..2a4a9f2 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/IsBehaviorTreeActive.cs @@ -0,0 +1,29 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals +{ + using Opsive.GraphDesigner.Runtime; + + [NodeIcon("e0a8f1df788b6274a9a24003859dfa7e")] + [Opsive.Shared.Utility.Description("Returns true if the specified behavior tree is active.")] + public class IsBehaviorTreeActive : TargetBehaviorTreeConditional + { + /// + /// Executes the task logic. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + if (m_ResolvedBehaviorTree == null) { + return TaskStatus.Failure; + } + + return m_ResolvedBehaviorTree.IsActive() ? TaskStatus.Success : TaskStatus.Failure; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/IsBehaviorTreeActive.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/IsBehaviorTreeActive.cs.meta new file mode 100644 index 0000000..df7d026 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/IsBehaviorTreeActive.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2d23ca37ee86b15428911307549ab429 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math.meta new file mode 100644 index 0000000..0891ce0 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a1963b538eafb4144b6fdd080af86056 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/BoolComparison.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/BoolComparison.cs new file mode 100644 index 0000000..faf2ab2 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/BoolComparison.cs @@ -0,0 +1,32 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals.Math +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Compares two boolean values.")] + [Shared.Utility.Category("Math")] + public class BoolComparison : Conditional + { + [Tooltip("The first boolean.")] + [SerializeField] protected SharedVariable m_Bool1; + [Tooltip("The second boolean.")] + [SerializeField] protected SharedVariable m_Bool2; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + return m_Bool1.Value == m_Bool2.Value ? TaskStatus.Success : TaskStatus.Failure; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/BoolComparison.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/BoolComparison.cs.meta new file mode 100644 index 0000000..62ddc3a --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/BoolComparison.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 20df1d25d6eab8b429d6c8fe6af5a87a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/FloatComparison.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/FloatComparison.cs new file mode 100644 index 0000000..90c09d3 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/FloatComparison.cs @@ -0,0 +1,60 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals.Math +{ + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Compares two float values.")] + [Shared.Utility.Category("Math")] + public class FloatComparison : Conditional + { + /// + /// Specifies the type of comparison that should be performed. + /// + protected enum Operation + { + LessThan, + LessThanOrEqualTo, + EqualTo, + NotEqualTo, + GreaterThanOrEqualTo, + GreaterThan + } + + [Tooltip("The operation that should be performed.")] + [SerializeField] protected SharedVariable m_Operation; + [Tooltip("The first float.")] + [SerializeField] protected SharedVariable m_Float1; + [Tooltip("The second float.")] + [SerializeField] protected SharedVariable m_Float2; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + switch (m_Operation.Value) { + case Operation.LessThan: + return m_Float1.Value < m_Float2.Value ? TaskStatus.Success : TaskStatus.Failure; + case Operation.LessThanOrEqualTo: + return m_Float1.Value <= m_Float2.Value ? TaskStatus.Success : TaskStatus.Failure; + case Operation.EqualTo: + return m_Float1.Value == m_Float2.Value ? TaskStatus.Success : TaskStatus.Failure; + case Operation.NotEqualTo: + return m_Float1.Value != m_Float2.Value ? TaskStatus.Success : TaskStatus.Failure; + case Operation.GreaterThanOrEqualTo: + return m_Float1.Value >= m_Float2.Value ? TaskStatus.Success : TaskStatus.Failure; + case Operation.GreaterThan: + return m_Float1.Value > m_Float2.Value ? TaskStatus.Success : TaskStatus.Failure; + } + return TaskStatus.Failure; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/FloatComparison.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/FloatComparison.cs.meta new file mode 100644 index 0000000..119bcde --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/FloatComparison.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a440ba0c2e06f5c4aaeaf7921c721c69 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/GameObjectComparison.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/GameObjectComparison.cs new file mode 100644 index 0000000..1835a4c --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/GameObjectComparison.cs @@ -0,0 +1,32 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals.Math +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Compares two GameObject values.")] + [Shared.Utility.Category("Math")] + public class GameObjectComparison : Conditional + { + [Tooltip("The first GameObject.")] + [SerializeField] protected SharedVariable m_GameObject1; + [Tooltip("The second GameObject.")] + [SerializeField] protected SharedVariable m_GameObject2; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + return m_GameObject1.Value == m_GameObject2.Value ? TaskStatus.Success : TaskStatus.Failure; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/GameObjectComparison.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/GameObjectComparison.cs.meta new file mode 100644 index 0000000..37f83d3 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/GameObjectComparison.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3462716a0f02f06448a43ed06afe8ea8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/IntComparison.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/IntComparison.cs new file mode 100644 index 0000000..4e57e26 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/IntComparison.cs @@ -0,0 +1,61 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals.Math +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Compares two integer values.")] + [Shared.Utility.Category("Math")] + public class IntComparison : Conditional + { + /// + /// Specifies the type of comparison that should be performed. + /// + protected enum Operation + { + LessThan, + LessThanOrEqualTo, + EqualTo, + NotEqualTo, + GreaterThanOrEqualTo, + GreaterThan + } + + [Tooltip("The operation that should be performed.")] + [SerializeField] protected SharedVariable m_Operation; + [Tooltip("The first integer.")] + [SerializeField] protected SharedVariable m_Integer1; + [Tooltip("The second integer.")] + [SerializeField] protected SharedVariable m_Integer2; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + switch (m_Operation.Value) { + case Operation.LessThan: + return m_Integer1.Value < m_Integer2.Value ? TaskStatus.Success : TaskStatus.Failure; + case Operation.LessThanOrEqualTo: + return m_Integer1.Value <= m_Integer2.Value ? TaskStatus.Success : TaskStatus.Failure; + case Operation.EqualTo: + return m_Integer1.Value == m_Integer2.Value ? TaskStatus.Success : TaskStatus.Failure; + case Operation.NotEqualTo: + return m_Integer1.Value != m_Integer2.Value ? TaskStatus.Success : TaskStatus.Failure; + case Operation.GreaterThanOrEqualTo: + return m_Integer1.Value >= m_Integer2.Value ? TaskStatus.Success : TaskStatus.Failure; + case Operation.GreaterThan: + return m_Integer1.Value > m_Integer2.Value ? TaskStatus.Success : TaskStatus.Failure; + } + return TaskStatus.Failure; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/IntComparison.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/IntComparison.cs.meta new file mode 100644 index 0000000..ed8efa1 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/IntComparison.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a375a939d653fe147a5a14a0c2bef1ff +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/Vector2Comparison.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/Vector2Comparison.cs new file mode 100644 index 0000000..53d317c --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/Vector2Comparison.cs @@ -0,0 +1,32 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals.Math +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Compares two Vector2 values.")] + [Shared.Utility.Category("Math")] + public class Vector2Comparison : Conditional + { + [Tooltip("The first Vector2.")] + [SerializeField] protected SharedVariable m_Vector1; + [Tooltip("The second Vector2.")] + [SerializeField] protected SharedVariable m_Vector2; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + return m_Vector1.Value == m_Vector2.Value ? TaskStatus.Success : TaskStatus.Failure; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/Vector2Comparison.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/Vector2Comparison.cs.meta new file mode 100644 index 0000000..ec6e6d8 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/Vector2Comparison.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7c2b3d80126bb1f4d861fd3179310f4e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/Vector3Comparison.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/Vector3Comparison.cs new file mode 100644 index 0000000..9602914 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/Vector3Comparison.cs @@ -0,0 +1,32 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals.Math +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Compares two Vector3 values.")] + [Shared.Utility.Category("Math")] + public class Vector3Comparison : Conditional + { + [Tooltip("The first Vector3.")] + [SerializeField] protected SharedVariable m_Vector1; + [Tooltip("The second Vector3.")] + [SerializeField] protected SharedVariable m_Vector2; + + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + { + return m_Vector1.Value == m_Vector2.Value ? TaskStatus.Success : TaskStatus.Failure; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/Vector3Comparison.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/Vector3Comparison.cs.meta new file mode 100644 index 0000000..5fdfc3e --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Math/Vector3Comparison.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 56a06b56642c23e41be3a6ed24331bc4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics.meta new file mode 100644 index 0000000..8015fc8 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 61662c8f56bf6ff448ec2a4c8761613a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasEnteredCollision.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasEnteredCollision.cs new file mode 100644 index 0000000..07b4688 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasEnteredCollision.cs @@ -0,0 +1,61 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals.Physics +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Returns success when a collision starts. This task will only receive the physics callback if it is being reevaluated (with a conditional abort or under a parallel task).")] + [Shared.Utility.Category("Physics")] + public class HasEnteredCollision : Conditional + { + [Tooltip("The tag of the GameObject that the collision should be checked against.")] + [SerializeField] protected SharedVariable m_Tag; + [Tooltip("The collided GameObject.")] + [SerializeField] protected SharedVariable m_StoredCollisionGameObject; + + protected override bool ReceiveCollisionEnterCallback => true; + + private bool m_EnteredCollision; + + /// + /// Returns true when the agent has caused a collision. + /// + /// True when the agent has caused a collision. + public override TaskStatus OnUpdate() + { + return m_EnteredCollision ? TaskStatus.Success : TaskStatus.Failure; + } + + /// + /// The task has ended. + /// + public override void OnEnd() + { + base.OnEnd(); + + m_EnteredCollision = false; + } + + /// + /// The agent has caused a collision. + /// + /// The collision that caused the event. + protected override void OnCollisionEnter(Collision collision) + { + if (!string.IsNullOrEmpty(m_Tag.Value) && !collision.gameObject.CompareTag(m_Tag.Value)) { + return; + } + + if (m_StoredCollisionGameObject != null && m_StoredCollisionGameObject.IsShared) { m_StoredCollisionGameObject.Value = collision.gameObject; } + + m_EnteredCollision = true; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasEnteredCollision.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasEnteredCollision.cs.meta new file mode 100644 index 0000000..08dd55a --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasEnteredCollision.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9ce4017c15025f648a4a737683b98b18 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasEnteredCollision2D.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasEnteredCollision2D.cs new file mode 100644 index 0000000..4571b07 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasEnteredCollision2D.cs @@ -0,0 +1,61 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals.Physics +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Returns success when a 2D collision starts. This task will only receive the physics callback if it is being reevaluated (with a conditional abort or under a parallel task).")] + [Shared.Utility.Category("Physics")] + public class HasEnteredCollision2D : Conditional + { + [Tooltip("The tag of the GameObject that the collision should be checked against.")] + [SerializeField] protected SharedVariable m_Tag; + [Tooltip("The collided GameObject.")] + [SerializeField] protected SharedVariable m_StoredCollisionGameObject; + + protected override bool ReceiveCollisionEnterCallback => true; + + private bool m_EnteredCollision; + + /// + /// Returns true when the agent has caused a collision. + /// + /// True when the agent has caused a collision. + public override TaskStatus OnUpdate() + { + return m_EnteredCollision ? TaskStatus.Success : TaskStatus.Failure; + } + + /// + /// The task has ended. + /// + public override void OnEnd() + { + base.OnEnd(); + + m_EnteredCollision = false; + } + + /// + /// The agent has caused a collision. + /// + /// The collision that caused the event. + protected override void OnCollisionEnter2D(Collision2D collision) + { + if (!string.IsNullOrEmpty(m_Tag.Value) && !collision.gameObject.CompareTag(m_Tag.Value)) { + return; + } + + if (m_StoredCollisionGameObject != null && m_StoredCollisionGameObject.IsShared) { m_StoredCollisionGameObject.Value = collision.gameObject; } + + m_EnteredCollision = true; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasEnteredCollision2D.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasEnteredCollision2D.cs.meta new file mode 100644 index 0000000..50d55e5 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasEnteredCollision2D.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 37fa749cbcf6f7c459159eba18e9ca31 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasEnteredTrigger.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasEnteredTrigger.cs new file mode 100644 index 0000000..ec16868 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasEnteredTrigger.cs @@ -0,0 +1,60 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals.Physics +{ + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Returns success when an object enters the trigger. This task will only receive the physics callback if it is being reevaluated (with a conditional abort or under a parallel task).")] + [Shared.Utility.Category("Physics")] + public class HasEnteredTrigger : Conditional + { + [Tooltip("The tag of the GameObject that the trigger should be checked against.")] + [SerializeField] protected SharedVariable m_Tag; + [Tooltip("The entered trigger.")] + [SerializeField] protected SharedVariable m_StoredOtherCollider; + + protected override bool ReceiveTriggerEnterCallback => true; + + private bool m_EnteredTrigger; + + /// + /// Returns true when the agent has entered a trigger. + /// + /// True when the agent has entered a trigger. + public override TaskStatus OnUpdate() + { + return m_EnteredTrigger ? TaskStatus.Success : TaskStatus.Failure; + } + + /// + /// The task has ended. + /// + public override void OnEnd() + { + base.OnEnd(); + + m_EnteredTrigger = false; + } + + /// + /// The agent has entered a trigger. + /// + /// The trigger that the agent entered. + protected override void OnTriggerEnter(Collider other) + { + if (!string.IsNullOrEmpty(m_Tag.Value) && !other.gameObject.CompareTag(m_Tag.Value)) { + return; + } + + if (m_StoredOtherCollider != null && m_StoredOtherCollider.IsShared) { m_StoredOtherCollider.Value = other; } + + m_EnteredTrigger = true; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasEnteredTrigger.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasEnteredTrigger.cs.meta new file mode 100644 index 0000000..4298a2a --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasEnteredTrigger.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fe018fbcfb4b7404f865318125440626 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasEnteredTrigger2D.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasEnteredTrigger2D.cs new file mode 100644 index 0000000..1d91e69 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasEnteredTrigger2D.cs @@ -0,0 +1,61 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals.Physics +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Returns success when an object enters the 2D trigger. This task will only receive the physics callback if it is being reevaluated (with a conditional abort or under a parallel task).")] + [Shared.Utility.Category("Physics")] + public class HasEnteredTrigger2D : Conditional + { + [Tooltip("The tag of the GameObject that the trigger should be checked against.")] + [SerializeField] protected SharedVariable m_Tag; + [Tooltip("The entered trigger.")] + [SerializeField] protected SharedVariable m_StoredOtherCollider; + + protected override bool ReceiveTriggerEnter2DCallback => true; + + private bool m_EnteredTrigger; + + /// + /// Returns true when the agent has entered a trigger. + /// + /// True when the agent has entered a trigger. + public override TaskStatus OnUpdate() + { + return m_EnteredTrigger ? TaskStatus.Success : TaskStatus.Failure; + } + + /// + /// The task has ended. + /// + public override void OnEnd() + { + base.OnEnd(); + + m_EnteredTrigger = false; + } + + /// + /// The agent has entered a trigger. + /// + /// The trigger that the agent entered. + protected override void OnTriggerEnter2D(Collider2D other) + { + if (!string.IsNullOrEmpty(m_Tag.Value) && !other.gameObject.CompareTag(m_Tag.Value)) { + return; + } + + if (m_StoredOtherCollider != null && m_StoredOtherCollider.IsShared) { m_StoredOtherCollider.Value = other; } + + m_EnteredTrigger = true; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasEnteredTrigger2D.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasEnteredTrigger2D.cs.meta new file mode 100644 index 0000000..cd89048 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasEnteredTrigger2D.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 83caefa20e976f047b96f600eecffaed +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasExitedCollision.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasExitedCollision.cs new file mode 100644 index 0000000..2bba301 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasExitedCollision.cs @@ -0,0 +1,61 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals.Physics +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Returns success when a collision ends. This task will only receive the physics callback if it is being reevaluated (with a conditional abort or under a parallel task).")] + [Shared.Utility.Category("Physics")] + public class HasExitedCollision : Conditional + { + [Tooltip("The tag of the GameObject that the collision should be checked against.")] + [SerializeField] protected SharedVariable m_Tag; + [Tooltip("The collided GameObject.")] + [SerializeField] protected SharedVariable m_StoredCollisionGameObject; + + protected override bool ReceiveCollisionExitCallback => true; + + private bool m_ExitedCollision; + + /// + /// Returns true when the agent has left a collision. + /// + /// True when the agent has left a collision. + public override TaskStatus OnUpdate() + { + return m_ExitedCollision ? TaskStatus.Success : TaskStatus.Failure; + } + + /// + /// The task has ended. + /// + public override void OnEnd() + { + base.OnEnd(); + + m_ExitedCollision = false; + } + + /// + /// The agent has left a collision. + /// + /// The collision that caused the event. + protected override void OnCollisionExit(Collision collision) + { + if (!string.IsNullOrEmpty(m_Tag.Value) && !collision.gameObject.CompareTag(m_Tag.Value)) { + return; + } + + if (m_StoredCollisionGameObject != null && m_StoredCollisionGameObject.IsShared) { m_StoredCollisionGameObject.Value = collision.gameObject; } + + m_ExitedCollision = true; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasExitedCollision.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasExitedCollision.cs.meta new file mode 100644 index 0000000..4c94e62 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasExitedCollision.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c3ac7ec5199af7049b246d4eabfb0d51 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasExitedCollision2D.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasExitedCollision2D.cs new file mode 100644 index 0000000..81ed530 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasExitedCollision2D.cs @@ -0,0 +1,61 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals.Physics +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Returns success when a 2D collision ends. This task will only receive the physics callback if it is being reevaluated (with a conditional abort or under a parallel task).")] + [Shared.Utility.Category("Physics")] + public class HasExitedCollision2D : Conditional + { + [Tooltip("The tag of the GameObject that the collision should be checked against.")] + [SerializeField] protected SharedVariable m_Tag; + [Tooltip("The collided GameObject.")] + [SerializeField] protected SharedVariable m_StoredCollisionGameObject; + + protected override bool ReceiveCollisionExit2DCallback => true; + + private bool m_ExitedCollision; + + /// + /// Returns true when the agent has left a collision. + /// + /// True when the agent has left a collision. + public override TaskStatus OnUpdate() + { + return m_ExitedCollision ? TaskStatus.Success : TaskStatus.Failure; + } + + /// + /// The task has ended. + /// + public override void OnEnd() + { + base.OnEnd(); + + m_ExitedCollision = false; + } + + /// + /// The agent has left a collision. + /// + /// The collision that caused the event. + protected override void OnCollisionExit2D(Collision2D collision) + { + if (!string.IsNullOrEmpty(m_Tag.Value) && !collision.gameObject.CompareTag(m_Tag.Value)) { + return; + } + + if (m_StoredCollisionGameObject != null && m_StoredCollisionGameObject.IsShared) { m_StoredCollisionGameObject.Value = collision.gameObject; } + + m_ExitedCollision = true; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasExitedCollision2D.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasExitedCollision2D.cs.meta new file mode 100644 index 0000000..7d886ec --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasExitedCollision2D.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5fdb5f736525568428350e746b5b6d59 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasExitedTrigger.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasExitedTrigger.cs new file mode 100644 index 0000000..c92f1b5 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasExitedTrigger.cs @@ -0,0 +1,61 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals.Physics +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Returns success when an object exits the trigger. This task will only receive the physics callback if it is being reevaluated (with a conditional abort or under a parallel task).")] + [Shared.Utility.Category("Physics")] + public class HasExitedTrigger : Conditional + { + [Tooltip("The tag of the GameObject that the trigger should be checked against.")] + [SerializeField] protected SharedVariable m_Tag; + [Tooltip("The exited trigger.")] + [SerializeField] protected SharedVariable m_StoredOtherCollider; + + protected override bool ReceiveTriggerExitCallback => true; + + private bool m_ExitedTrigger; + + /// + /// Returns true when the agent has exited a trigger. + /// + /// True when the agent has exited a trigger. + public override TaskStatus OnUpdate() + { + return m_ExitedTrigger ? TaskStatus.Success : TaskStatus.Failure; + } + + /// + /// The task has ended. + /// + public override void OnEnd() + { + base.OnEnd(); + + m_ExitedTrigger = false; + } + + /// + /// The agent has exited a trigger. + /// + /// The trigger that the agent exited. + protected override void OnTriggerExit(Collider other) + { + if (!string.IsNullOrEmpty(m_Tag.Value) && !other.gameObject.CompareTag(m_Tag.Value)) { + return; + } + + if (m_StoredOtherCollider != null && m_StoredOtherCollider.IsShared) { m_StoredOtherCollider.Value = other; } + + m_ExitedTrigger = true; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasExitedTrigger.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasExitedTrigger.cs.meta new file mode 100644 index 0000000..3457e09 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasExitedTrigger.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9bde13c58ab44304da9e904934375552 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasExitedTrigger2D.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasExitedTrigger2D.cs new file mode 100644 index 0000000..c9c2b4d --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasExitedTrigger2D.cs @@ -0,0 +1,61 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals.Physics +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [Opsive.Shared.Utility.Description("Returns success when an object exits the 2D trigger. This task will only receive the physics callback if it is being reevaluated (with a conditional abort or under a parallel task).")] + [Shared.Utility.Category("Physics")] + public class HasExitedTrigger2D : Conditional + { + [Tooltip("The tag of the GameObject that the trigger should be checked against.")] + [SerializeField] protected SharedVariable m_Tag; + [Tooltip("The exited trigger.")] + [SerializeField] protected SharedVariable m_StoredOtherCollider; + + protected override bool ReceiveTriggerExit2DCallback => true; + + private bool m_ExitedTrigger; + + /// + /// Returns true when the agent has exited a trigger. + /// + /// True when the agent has exited a trigger. + public override TaskStatus OnUpdate() + { + return m_ExitedTrigger ? TaskStatus.Success : TaskStatus.Failure; + } + + /// + /// The task has ended. + /// + public override void OnEnd() + { + base.OnEnd(); + + m_ExitedTrigger = false; + } + + /// + /// The agent has exited a trigger. + /// + /// The trigger that the agent exited. + protected override void OnTriggerExit2D(Collider2D other) + { + if (!string.IsNullOrEmpty(m_Tag.Value) && !other.gameObject.CompareTag(m_Tag.Value)) { + return; + } + + if (m_StoredOtherCollider != null && m_StoredOtherCollider.IsShared) { m_StoredOtherCollider.Value = other; } + + m_ExitedTrigger = true; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasExitedTrigger2D.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasExitedTrigger2D.cs.meta new file mode 100644 index 0000000..168f1d5 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/Physics/HasExitedTrigger2D.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 74c369fe788ddbb4ab2b9265bdf4e9c0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/RandomProbability.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/RandomProbability.cs new file mode 100644 index 0000000..f27b287 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/RandomProbability.cs @@ -0,0 +1,229 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using Unity.Burst; + using Unity.Entities; + using UnityEngine; + using System; + + /// + /// A node representation of the random probability task. + /// + [NodeIcon("69bf50f8923f54c4c8bb8e258883a411", "6c5770241610a4c4aae4ac3af0ac8bf8")] + [Opsive.Shared.Utility.Description("The random probability task will return success when the random probability is below the succeed probability. It will otherwise return failure.")] + public class RandomProbability : ECSConditionalTask, IReevaluateResponder, ICloneable + { + [Tooltip("The probability of the task returning success.")] + [SerializeField] [Range(0, 1)] float m_SuccessProbability; + [Tooltip("The seed of the random number generator. Set to 0 to use the entity index as the seed.")] + [SerializeField] uint m_Seed; + + public float SuccessProbability { get => m_SuccessProbability; set => m_SuccessProbability = value; } + public uint Seed { get => m_Seed; set => m_Seed = value; } + + public override ComponentType Flag { get => typeof(RandomProbabilityFlag); } + public ComponentType ReevaluateFlag { get => typeof(RandomProbabilityReevaluateFlag); } + public System.Type ReevaluateSystemType { get => typeof(RandomProbabilityReevaluateTaskSystem); } + + /// + /// Returns a new TBufferElement for use by the system. + /// + /// A new TBufferElement for use by the system. + public override RandomProbabilityComponent GetBufferElement() + { + return new RandomProbabilityComponent() + { + Index = RuntimeIndex, + SuccessProbability = m_SuccessProbability, + Seed = m_Seed, + }; + } + + /// + /// Resets the task to its default values. + /// + public override void Reset() + { + m_SuccessProbability = 1; + } + + /// + /// Creates a deep clone of the component. + /// + /// A deep clone of the component. + public object Clone() + { + var clone = Activator.CreateInstance(); + clone.Index = Index; + clone.ParentIndex = ParentIndex; + clone.SiblingIndex = SiblingIndex; + clone.SuccessProbability = SuccessProbability; + return clone; + } + } + + /// + /// The DOTS data structure for the RandomProbability class. + /// + public struct RandomProbabilityComponent : IBufferElementData + { + [Tooltip("The index of the node.")] + public ushort Index; + [Tooltip("The probability of the task returning success.")] + public float SuccessProbability; + [Tooltip("The seed of the random number generator.")] + public uint Seed; + [Tooltip("The random number generator for the task.")] + public Unity.Mathematics.Random RandomNumberGenerator; + } + + /// + /// A DOTS tag indicating when a RandomProbability node is active. + /// + public struct RandomProbabilityFlag : IComponentData, IEnableableComponent { } + + /// + /// Runs the RandomProbability logic. + /// + [DisableAutoCreation] + public partial struct RandomProbabilityTaskSystem : ISystem + { + /// + /// Creates the job. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + var query = SystemAPI.QueryBuilder().WithAllRW().WithAllRW().WithAll().Build(); + state.Dependency = new RandomProbabilityJob().ScheduleParallel(query, state.Dependency); + } + + /// + /// Job which executes the task logic. + /// + [BurstCompile] + private partial struct RandomProbabilityJob : IJobEntity + { + /// + /// Executes the random probability logic. + /// + /// The entity that is running the logic. + /// An array of TaskComponents. + /// An array of RandomProbabilityComponents. + [BurstCompile] + public void Execute(Entity entity, ref DynamicBuffer taskComponents, ref DynamicBuffer randomProbabilityComponents) + { + for (int i = 0; i < randomProbabilityComponents.Length; ++i) { + var randomProbabilityComponent = randomProbabilityComponents[i]; + var taskComponent = taskComponents[randomProbabilityComponent.Index]; + if (taskComponent.Status == TaskStatus.Queued) { + // Generate a new random number seed for each entity. + if (randomProbabilityComponent.RandomNumberGenerator.state == 0) { + randomProbabilityComponent.RandomNumberGenerator = Unity.Mathematics.Random.CreateFromIndex(randomProbabilityComponent.Seed != 0 ? randomProbabilityComponent.Seed : (uint)entity.Index); + } + // NextFloat updates the RandomNumberGenerator so the component must be replaced. + var probability = randomProbabilityComponent.RandomNumberGenerator.NextFloat(); + var randomProbabilityBuffer = randomProbabilityComponents; + randomProbabilityBuffer[i] = randomProbabilityComponent; + + // The task will always change status. + taskComponent.Status = probability < randomProbabilityComponent.SuccessProbability ? TaskStatus.Success : TaskStatus.Failure; + taskComponents[randomProbabilityComponent.Index] = taskComponent; + } else if (taskComponent.Status == TaskStatus.Running) { + // A status of running means the task is being resumed from a conditional abort. Return success. + taskComponent.Status = TaskStatus.Success; + taskComponents[randomProbabilityComponent.Index] = taskComponent; + } + } + } + } + } + + + /// + /// A DOTS tag indicating when an RandomProbability node needs to be reevaluated. + /// + public struct RandomProbabilityReevaluateFlag : IComponentData, IEnableableComponent + { + } + + /// + /// Runs the RandomProbability reevaluation logic. + /// + [DisableAutoCreation] + public partial struct RandomProbabilityReevaluateTaskSystem : ISystem + { + /// + /// Updates the reevaluation logic. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + foreach (var (taskComponents, randomProbabilityComponents, entity) in + SystemAPI.Query, DynamicBuffer>().WithAll().WithEntityAccess()) { + for (int i = 0; i < randomProbabilityComponents.Length; ++i) { + var randomProbabilityComponent = randomProbabilityComponents[i]; + var taskComponent = taskComponents[randomProbabilityComponent.Index]; + if (!taskComponent.Reevaluate) { + continue; + } + + // NextFloat updates the RandomNumberGenerator so the component must be replaced. + var probability = randomProbabilityComponent.RandomNumberGenerator.NextFloat(); + var randomProbabilityBuffer = randomProbabilityComponents; + randomProbabilityBuffer[i] = randomProbabilityComponent; + + var status = probability < randomProbabilityComponent.SuccessProbability ? TaskStatus.Success : TaskStatus.Failure; + if (status != taskComponent.Status) { + taskComponent.Status = status; + var buffer = taskComponents; + buffer[taskComponent.Index] = taskComponent; + } + } + } + } + } + + [NodeIcon("69bf50f8923f54c4c8bb8e258883a411", "6c5770241610a4c4aae4ac3af0ac8bf8")] + [Opsive.Shared.Utility.Description("The random probability task will return success when the random probability is below the succeed probability. It will otherwise return failure.")] + public class SharedRandomProbability : Conditional + { + [Tooltip("The probability of the task returning success.")] + [SerializeField] SharedVariable m_SuccessProbability; + [Tooltip("The seed of the random number generator. Set to 0 to disable.")] + [SerializeField] int m_Seed; + + public SharedVariable SuccessProbability { get => m_SuccessProbability; set => m_SuccessProbability = value; } + public int Seed { get => m_Seed; set => m_Seed = value; } + + /// + /// Callback when the task is initialized. + /// + public override void OnAwake() + { + if (m_Seed != 0) { + UnityEngine.Random.InitState(m_Seed); + } + } + + /// + /// Executes the task logic. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + return UnityEngine.Random.value < m_SuccessProbability.Value ? TaskStatus.Success : TaskStatus.Failure; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/RandomProbability.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/RandomProbability.cs.meta new file mode 100644 index 0000000..a9ad684 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/RandomProbability.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b6240825104968e44a250a717de2f39a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/StackedConditional.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/StackedConditional.cs new file mode 100644 index 0000000..3e42088 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/StackedConditional.cs @@ -0,0 +1,49 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals +{ + using Opsive.GraphDesigner.Runtime; + + /// + /// The StackedConditional task allows for multiple conditionals to be added to the same node. + /// + [NodeIcon("b2368834b8b80144a8b1ab97b609e966", "86fbf527a2c761e45bc4a47cf4894902")] + [Opsive.Shared.Utility.Description("Allows multiple conditional tasks to be added to a single node.")] + public class StackedConditional : StackedTask, IConditional, IConditionalReevaluation + { + /// + /// Reevaluates the task logic. Returns a TaskStatus indicating how the behavior tree flow should proceed. + /// + /// The status of the task during the reevaluation phase. + public TaskStatus OnReevaluateUpdate() + { + if (m_Tasks == null) { + return TaskStatus.Failure; + } + + for (int i = 0; i < m_Tasks.Length; ++i) { + if (m_Tasks[i] == null) { + continue; + } + + TaskStatus executionStatus; + if (m_Tasks[i] is IConditionalReevaluation reevaluateTask) { + executionStatus = reevaluateTask.OnReevaluateUpdate(); + } else { // Use the regular update method if the task isn't designed for conditional aborts. + executionStatus = m_Tasks[i].OnUpdate(); + } + if (m_ComparisonType == ComparisonType.Sequence && executionStatus == TaskStatus.Failure) { + return TaskStatus.Failure; + } else if (m_ComparisonType == ComparisonType.Selector && executionStatus == TaskStatus.Success) { + return TaskStatus.Success; + } + } + return m_ComparisonType == ComparisonType.Sequence ? TaskStatus.Success : TaskStatus.Failure; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/StackedConditional.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/StackedConditional.cs.meta new file mode 100644 index 0000000..7355b1b --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/StackedConditional.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 73c25e0bc2411614e950faaf32f8cfa1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/TargetBehaviorTreeConditional.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/TargetBehaviorTreeConditional.cs new file mode 100644 index 0000000..3f45e65 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/TargetBehaviorTreeConditional.cs @@ -0,0 +1,71 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals +{ + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + /// + /// A TaskObject Conditional task which implements the shared TargetGameObject/TreeUserID objects. + /// + public abstract class TargetBehaviorTreeConditional : Conditional + { + [Tooltip("The GameObject of the target behavior tree. If the value is null the current GameObject will be used.")] + [SerializeField] protected SharedVariable m_TargetGameObject; + [Tooltip("The index of the tree if there are multiple behavior trees on the same GameObject.")] + [SerializeField] protected SharedVariable m_TreeIndex; + + protected BehaviorTree m_ResolvedBehaviorTree; + + /// + /// Initializes the task. + /// + public override void OnAwake() + { + m_TargetGameObject.OnValueChange += InitializeTarget; + m_TreeIndex.OnValueChange += InitializeTarget; + + InitializeTarget(); + } + + /// + /// Initializes the target behavior tree. + /// + protected virtual void InitializeTarget() + { + if (m_TargetGameObject.Value == null) { + m_ResolvedBehaviorTree = m_BehaviorTree; + } else { + var behaviorTrees = m_TargetGameObject.Value.GetComponents(); + if (behaviorTrees.Length == 1) { + m_ResolvedBehaviorTree = behaviorTrees[0]; + } else if (behaviorTrees.Length > 1) { + for (int i = 0; i < behaviorTrees.Length; ++i) { + if (behaviorTrees[i].Index == m_TreeIndex.Value) { + m_ResolvedBehaviorTree = behaviorTrees[i]; + break; + } + } + // If the UserID can't be found then use the first behavior tree. + if (m_ResolvedBehaviorTree == null) { + m_ResolvedBehaviorTree = behaviorTrees[0]; + } + } + } + } + + /// + /// The behavior tree has been destroyed. + /// + public override void OnDestroy() + { + m_TargetGameObject.OnValueChange -= InitializeTarget; + m_TreeIndex.OnValueChange -= InitializeTarget; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/TargetBehaviorTreeConditional.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/TargetBehaviorTreeConditional.cs.meta new file mode 100644 index 0000000..c02b23b --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/TargetBehaviorTreeConditional.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8829f667141e1c04d95d5f9f2f68c7e2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/TargetGameObjectConditional.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/TargetGameObjectConditional.cs new file mode 100644 index 0000000..087bdb9 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/TargetGameObjectConditional.cs @@ -0,0 +1,53 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals +{ + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + /// + /// A TaskObject Conditional task which returns the current GameObject if the target is null. + /// + public abstract class TargetGameObjectConditional : Conditional + { + [Tooltip("The GameObject of the target behavior tree. If the value is null the current GameObject will be used.")] + [SerializeField] protected SharedVariable m_TargetGameObject; + protected override GameObject gameObject => m_ResolvedGameObject; + protected override Transform transform => m_ResolvedTransform; + + protected GameObject m_ResolvedGameObject; + protected Transform m_ResolvedTransform; + + /// + /// Initializes the task. + /// + public override void OnAwake() + { + m_TargetGameObject.OnValueChange += InitializeTarget; + + InitializeTarget(); + } + + /// + /// Initializes the target GameObject. + /// + protected virtual void InitializeTarget() + { + m_ResolvedGameObject = (m_TargetGameObject.Value == null || m_TargetGameObject.Value.Equals(null)) ? m_GameObject : m_TargetGameObject.Value; + m_ResolvedTransform = m_ResolvedGameObject.transform; + } + + /// + /// The behavior tree has been destroyed. + /// + public override void OnDestroy() + { + m_TargetGameObject.OnValueChange -= InitializeTarget; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/TargetGameObjectConditional.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/TargetGameObjectConditional.cs.meta new file mode 100644 index 0000000..f05cbf1 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Conditionals/TargetGameObjectConditional.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e53a3005031301c4c9f7c723c82763ce +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators.meta new file mode 100644 index 0000000..4278c3b --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1ae3ab6e20912c24eb56a8bc711e7688 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/ConditionalEvaluator.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/ConditionalEvaluator.cs new file mode 100644 index 0000000..7c63b51 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/ConditionalEvaluator.cs @@ -0,0 +1,176 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Decorators +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals; + using Opsive.BehaviorDesigner.Runtime.Utility; + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Utility; + using Opsive.Shared.Utility; + using Unity.Entities; + using UnityEngine; + + /// + /// The Conditional Evaluator is a decorator that will evaluate the specified conditional task. This conditional task can be reevaluated while the current task is active. + /// + [NodeIcon("63d6a403c13816a49b58d1de830ca51e", "3d3c18273075b3f40b6c921943f33964")] + [Opsive.Shared.Utility.Description("Evaluates the specified conditional task. If the conditional task returns success then the child task is run and the child status is returned. If the conditional task does not " + + "return success then the child task is not run and a failure status is immediately returned.")] + public class ConditionalEvaluator : DecoratorNode + { + [Tooltip("The target conditional task that should be evaluated.")] + [SerializeField] [InspectNode] protected Conditional m_Task; + + /// + /// Resets the task values back to their default. + /// + public override void Reset() + { + m_Task = null; + } + + /// + /// Initializes the base task parameters. + /// + /// A reference to the owning BehaviorTree. + /// The runtime index of the node. + internal override void Initialize(BehaviorTree behaviorTree, ushort runtimeIndex) + { + if (m_Task != null) { + m_Task.Initialize(behaviorTree, runtimeIndex); + + if (behaviorTree.World != null) { + ComponentUtility.AddInterruptComponents(behaviorTree.World.EntityManager, behaviorTree.Entity); + } + } + + base.Initialize(behaviorTree, runtimeIndex); + } + + /// + /// The behavior tree has been initialized. + /// + public override void OnAwake() + { + if (m_Task == null) { + Debug.LogError("Error: The task is null within the conditional evaluator."); + return; + } + + m_Task.OnAwake(); + } + + /// + /// The tree has been started. + /// + public override void OnBehaviorTreeStarted() + { + m_Task?.OnBehaviorTreeStarted(); + } + + /// + /// Starts evaluating the specified task. + /// + public override void OnStart() + { + m_Task?.OnStart(); + } + + /// + /// Updates the task. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + if (m_Task == null) { + return TaskStatus.Failure; + } + var status = m_Task.OnUpdate(); + if (status == TaskStatus.Failure) { + return TaskStatus.Failure; + } + + // If the child task returns success or failure then that status should be returned. Otherwise return running. + var taskComponents = m_BehaviorTree.World.EntityManager.GetBuffer(m_BehaviorTree.Entity); + var childStatus = taskComponents[RuntimeIndex + 1].Status; // RuntimeIndex + 1 will always be the task's only child. + if (childStatus == TaskStatus.Success || childStatus == TaskStatus.Failure) { + return childStatus; + } + return TaskStatus.Running; + } + + /// + /// The task has stopped execution. + /// + public override void OnEnd() + { + m_Task?.OnEnd(); + } + + /// + /// The tree has been stopped. + /// + /// Is the behavior tree paused? + public override void OnBehaviorTreeStopped(bool paused) + { + m_Task?.OnBehaviorTreeStopped(paused); + } + + /// + /// The tree has been destroyed. + /// + public override void OnDestroy() + { + m_Task?.OnDestroy(); + } + + /// + /// Specifies the type of reflection that should be used to save the task. + /// + /// The index of the sub-task. This is used for the task set allowing each contained task to have their own save type. + public override MemberVisibility GetSaveReflectionType(int index) + { + if (m_Task == null) { + return MemberVisibility.None; + } + + return m_Task.GetSaveReflectionType(index); + } + + /// + /// Returns the current task state. + /// + /// The DOTS world. + /// The DOTS entity. + /// The current task state. + public override object Save(World world, Entity entity) + { + if (m_Task == null) { + return null; + } + + return m_Task.Save(world, entity); + } + + /// + /// Loads the previous task state. + /// + /// The previous task state. + /// The DOTS world. + /// The DOTS entity. + public override void Load(object saveData, World world, Entity entity) + { + if (m_Task == null) { + return; + } + + m_Task.Load(saveData, world, entity); + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/ConditionalEvaluator.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/ConditionalEvaluator.cs.meta new file mode 100644 index 0000000..30ecb07 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/ConditionalEvaluator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8421ea18ed1f62349ac95e1b448b2a7f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/Cooldown.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/Cooldown.cs new file mode 100644 index 0000000..763f29e --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/Cooldown.cs @@ -0,0 +1,226 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Decorators +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.GraphDesigner.Runtime; + using Opsive.Shared.Utility; + using System; + using Unity.Burst; + using Unity.Entities; + using UnityEngine; + + /// + /// A node representation of the cooldown task. + /// + [NodeIcon("b5459f67bc5033e49ad7a763cdb885bb", "480c79a18119d2a488b5d984211463f1")] + [Opsive.Shared.Utility.Description("Waits the specified duration after the child has completed before returning the child's status of success or failure.")] + public class Cooldown : ECSDecoratorTask, IParentNode + { + [Tooltip("The duration of the cooldown.")] + [SerializeField] float m_Duration; + + public float Duration { get => m_Duration; set => m_Duration = value; } + + private ushort m_ComponentIndex; + + public override ComponentType Flag { get => typeof(CooldownFlag); } + + /// + /// Resets the task to its default values. + /// + public override void Reset() { m_Duration = 1; } + + /// + /// Returns a new TBufferElement for use by the system. + /// + /// A new TBufferElement for use by the system. + public override CooldownComponent GetBufferElement() + { + return new CooldownComponent() + { + Index = RuntimeIndex, + Duration = m_Duration, + StartTime = -1, + }; + } + + /// + /// Adds the IBufferElementData to the entity. + /// + /// The world that the entity exists in. + /// The entity that the IBufferElementData should be assigned to. + /// The GameObject that the entity is attached to. + /// The index of the element within the buffer. + public override int AddBufferElement(World world, Entity entity, GameObject gameObject) + { + m_ComponentIndex = (ushort)base.AddBufferElement(world, entity, gameObject); + return m_ComponentIndex; + } + + /// + /// Specifies the type of reflection that should be used to save the task. + /// + /// The index of the sub-task. This is used for the task set allowing each contained task to have their own save type. + public MemberVisibility GetSaveReflectionType(int index) { return MemberVisibility.None; } + + /// + /// Returns the current task state. + /// + /// The DOTS world. + /// The DOTS entity. + /// The current task state. + public object Save(World world, Entity entity) + { + var cooldownComponents = world.EntityManager.GetBuffer(entity); + var cooldownComponent = cooldownComponents[m_ComponentIndex]; + + // Save the elapsed time. + return Time.time - cooldownComponent.StartTime; + } + + /// + /// Loads the previous task state. + /// + /// The previous task state. + /// The DOTS world. + /// The DOTS entity. + public void Load(object saveData, World world, Entity entity) + { + var cooldownComponents = world.EntityManager.GetBuffer(entity); + var cooldownComponent = cooldownComponents[m_ComponentIndex]; + + // saveData is the elapsed amount of time. + var data = (object[])saveData; + cooldownComponent.StartTime = Time.time - (double)saveData; + cooldownComponents[m_ComponentIndex] = cooldownComponent; + } + + /// + /// Creates a deep clone of the component. + /// + /// A deep clone of the component. + public object Clone() + { + var clone = Activator.CreateInstance(); + clone.Index = Index; + clone.ParentIndex = ParentIndex; + clone.SiblingIndex = SiblingIndex; + clone.Duration = Duration; + return clone; + } + } + + /// + /// The DOTS data structure for the Cooldown class. + /// + public struct CooldownComponent : IBufferElementData + { + [Tooltip("The index of the node.")] + public ushort Index; + [Tooltip("The duration of the cooldown.")] + public float Duration; + [Tooltip("The time the cooldown started.")] + public double StartTime; + } + + /// + /// A DOTS tag indicating when an Cooldown node is active. + /// + public struct CooldownFlag : IComponentData, IEnableableComponent { } + + /// + /// Runs the Cooldown logic. + /// + [DisableAutoCreation] + public partial struct CooldownTaskSystem : ISystem + { + /// + /// Creates the job. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + var query = SystemAPI.QueryBuilder().WithAllRW().WithAllRW().WithAllRW().WithAll().Build(); + state.Dependency = new CooldownJob() + { + Time = SystemAPI.Time.ElapsedTime + }.ScheduleParallel(query, state.Dependency); + } + + /// + /// Job which executes the task logic. + /// + [BurstCompile] + private partial struct CooldownJob : IJobEntity + { + [Tooltip("The elapsed time.")] + public double Time; + + /// + /// Executes the cooldown logic. + /// + /// An array of BranchComponents. + /// An array of TaskComponents. + /// An array of CooldownComponents. + [BurstCompile] + public void Execute(ref DynamicBuffer branchComponents, ref DynamicBuffer taskComponents, ref DynamicBuffer cooldownComponents) + { + for (int i = 0; i < cooldownComponents.Length; ++i) { + var cooldownComponent = cooldownComponents[i]; + var taskComponent = taskComponents[cooldownComponent.Index]; + var branchComponent = branchComponents[taskComponent.BranchIndex]; + if (!branchComponent.CanExecute) { + continue; + } + + TaskComponent childTaskComponent; + if (taskComponent.Status == TaskStatus.Queued) { + taskComponent.Status = TaskStatus.Running; + taskComponents[taskComponent.Index] = taskComponent; + + childTaskComponent = taskComponents[taskComponent.Index + 1]; + childTaskComponent.Status = TaskStatus.Queued; + taskComponents[taskComponent.Index + 1] = childTaskComponent; + + branchComponent.NextIndex = (ushort)(taskComponent.Index + 1); + branchComponents[taskComponent.BranchIndex] = branchComponent; + + continue; + } else if (taskComponent.Status != TaskStatus.Running) { + continue; + } + + // The cooldown task is currently active. Check the first child. + childTaskComponent = taskComponents[taskComponent.Index + 1]; + if (childTaskComponent.Status == TaskStatus.Queued || childTaskComponent.Status == TaskStatus.Running) { + // The child should keep running. + continue; + } + + // The child has completed. Start the timer if it hasn't already started. If it has started then complete when the duration has elapsed. + if (cooldownComponent.StartTime == -1) { + cooldownComponent.StartTime = Time; + cooldownComponents[i] = cooldownComponent; + } else if (cooldownComponent.StartTime + cooldownComponent.Duration <= Time) { + taskComponent.Status = childTaskComponent.Status; + taskComponents[taskComponent.Index] = taskComponent; + + cooldownComponent.StartTime = -1; + var cooldownComponentsBuffer = cooldownComponents; + cooldownComponentsBuffer[i] = cooldownComponent; + + branchComponent.NextIndex = taskComponent.ParentIndex; + branchComponents[taskComponent.BranchIndex] = branchComponent; + } + } + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/Cooldown.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/Cooldown.cs.meta new file mode 100644 index 0000000..1cbbd0c --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/Cooldown.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c27e1444ff9ead74a89c45ce81873aca +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/DecoratorNode.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/DecoratorNode.cs new file mode 100644 index 0000000..5df9f80 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/DecoratorNode.cs @@ -0,0 +1,35 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Decorators +{ + using Opsive.BehaviorDesigner.Runtime.Systems; + using Opsive.GraphDesigner.Runtime; + using UnityEngine; + + /// + /// A TaskObject implementation of the Decorator task. + /// + [NodeIcon("9abc6c99a8db43b49b2b0d48cca90105", "1ee7d6a0873e3d942b556d3093d8173f")] + public abstract class DecoratorNode : Task, ITreeLogicNode, IParentNode, IDecorator, ITaskObjectParentNode + { + [Tooltip("The index of the node.")] + [SerializeField] ushort m_Index; + [Tooltip("The parent index of the node. ushort.MaxValue indicates no parent.")] + [SerializeField] ushort m_ParentIndex; + [Tooltip("The sibling index of the node. ushort.MaxValue indicates no sibling.")] + [SerializeField] ushort m_SiblingIndex; + + public ushort Index { get => m_Index; set => m_Index = value; } + public ushort ParentIndex { get => m_ParentIndex; set => m_ParentIndex = value; } + public ushort SiblingIndex { get => m_SiblingIndex; set => m_SiblingIndex = value; } + public ushort RuntimeIndex { get; set; } + + public int MaxChildCount { get => 1; } + public ushort NextChildIndex { get => (ushort)(RuntimeIndex + 1); } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/DecoratorNode.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/DecoratorNode.cs.meta new file mode 100644 index 0000000..360f18d --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/DecoratorNode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8fe6a83d84731a045a4c789e05b85214 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/Inverter.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/Inverter.cs new file mode 100644 index 0000000..f712e6a --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/Inverter.cs @@ -0,0 +1,126 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Decorators +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.GraphDesigner.Runtime; + using Unity.Burst; + using Unity.Entities; + using UnityEngine; + + /// + /// A node representation of the inverter task. + /// + [NodeIcon("53fe4de81c20e924095bdb5f3447acdc", "8d991ea2b725c214c85580d5647c578c")] + [Opsive.Shared.Utility.Description("The inverter task will invert the return value of the child task after it has finished executing. " + + "If the child returns success, the inverter task will return failure. If the child returns failure, the inverter task will return success.")] + public class Inverter : ECSDecoratorTask, IParentNode + { + public override ComponentType Flag { get => typeof(InverterFlag); } + + /// + /// Returns a new TBufferElement for use by the system. + /// + /// A new TBufferElement for use by the system. + public override InverterComponent GetBufferElement() + { + return new InverterComponent() + { + Index = RuntimeIndex, + }; + } + } + + /// + /// The DOTS data structure for the Inverter class. + /// + public struct InverterComponent : IBufferElementData + { + [Tooltip("The index of the node.")] + public ushort Index; + } + + /// + /// A DOTS tag indicating when an Inverter node is active. + /// + public struct InverterFlag : IComponentData, IEnableableComponent { } + + /// + /// Runs the Inverter logic. + /// + [DisableAutoCreation] + public partial struct InverterTaskSystem : ISystem + { + /// + /// Creates the job. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + var query = SystemAPI.QueryBuilder().WithAllRW().WithAllRW().WithAllRW().WithAll().Build(); + state.Dependency = new InverterJob().ScheduleParallel(query, state.Dependency); + } + + /// + /// Job which executes the task logic. + /// + [BurstCompile] + private partial struct InverterJob : IJobEntity + { + /// + /// Executes the inverter logic. + /// + /// An array of BranchComponents. + /// An array of TaskComponents. + /// An array of InverterComponents. + [BurstCompile] + public void Execute(ref DynamicBuffer branchComponents, ref DynamicBuffer taskComponents, ref DynamicBuffer inverterComponents) + { + for (int i = 0; i < inverterComponents.Length; ++i) { + var inverterComponent = inverterComponents[i]; + var taskComponent = taskComponents[inverterComponent.Index]; + var branchComponent = branchComponents[taskComponent.BranchIndex]; + if (!branchComponent.CanExecute) { + continue; + } + + TaskComponent childTaskComponent; + if (taskComponent.Status == TaskStatus.Queued) { + taskComponent.Status = TaskStatus.Running; + taskComponents[taskComponent.Index] = taskComponent; + + childTaskComponent = taskComponents[taskComponent.Index + 1]; + childTaskComponent.Status = TaskStatus.Queued; + taskComponents[taskComponent.Index + 1] = childTaskComponent; + + branchComponent.NextIndex = (ushort)(taskComponent.Index + 1); + branchComponents[taskComponent.BranchIndex] = branchComponent; + continue; + } else if (taskComponent.Status != TaskStatus.Running) { + continue; + } + + // The inverter task is currently active. Check the first child. + childTaskComponent = taskComponents[taskComponent.Index + 1]; + if (childTaskComponent.Status == TaskStatus.Queued || childTaskComponent.Status == TaskStatus.Running) { + // The child should keep running. + continue; + } + + // The child has completed. Invert the status. + taskComponent.Status = childTaskComponent.Status == TaskStatus.Success ? TaskStatus.Failure : TaskStatus.Success; + taskComponents[taskComponent.Index] = taskComponent; + + branchComponent.NextIndex = taskComponent.ParentIndex; + branchComponents[taskComponent.BranchIndex] = branchComponent; + } + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/Inverter.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/Inverter.cs.meta new file mode 100644 index 0000000..60c9b95 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/Inverter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5ee17779b73c2264485dda14bde477cd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/Iterator.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/Iterator.cs new file mode 100644 index 0000000..a996056 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/Iterator.cs @@ -0,0 +1,109 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Decorators +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using System.Collections; + using Unity.Entities; + using UnityEngine; + + [NodeIcon("3c1366e1dc8fe0b46b4a6c8724194cdd", "5b924a7ff18f0544aaa585af94ac536c")] + [Opsive.Shared.Utility.Description("Iterates through each element of the list. For each execution the Iterator task will set the next Element within the specified List.")] + public class Iterator : DecoratorNode + { + [Tooltip("The list that should be iterated upon.")] + [SerializeField] protected SharedVariable m_List; + [Tooltip("The current element within the list.")] + [SerializeField] [RequireShared] protected SharedVariable m_Element; + [Tooltip("Should the interator end on a failure?")] + [SerializeField] protected SharedVariable m_EndOnFailure; + + private int m_Index; + + /// + /// Resets the task values back to their default. + /// + public override void Reset() + { + m_List = null; + m_Element = null; + m_EndOnFailure = false; + } + + /// + /// Callback when the task is started. + /// + public override void OnStart() + { + base.OnStart(); + m_Index = 0; + } + + /// + /// Executes the task logic. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + if (m_List == null) { + return TaskStatus.Failure; + } + var list = m_List.GetValue() as IList; + if (list == null || list.Count == 0) { + return TaskStatus.Failure; + } + + var taskComponents = m_BehaviorTree.World.EntityManager.GetBuffer(m_BehaviorTree.Entity); + if (taskComponents[Index + 1].Status == TaskStatus.Queued || taskComponents[Index + 1].Status == TaskStatus.Running) { + return TaskStatus.Running; + } + + if (taskComponents[Index + 1].Status == TaskStatus.Failure && m_EndOnFailure.Value) { + return TaskStatus.Failure; + } + + // End when there are no more list elements. + if (m_Index >= list.Count) { + return taskComponents[Index + 1].Status; // Index + 1 will always be the task's only child. + } + + m_Element.SetValue(list[m_Index]); + m_Index++; + + return TaskStatus.Running; + } + + /// + /// Returns the current task state. + /// + /// The DOTS world. + /// The DOTS entity. + /// The current task state. + public override object Save(World world, Entity entity) + { + return m_Index; + } + + /// + /// Loads the previous task state. + /// + /// The previous task state. + /// The DOTS world. + /// The DOTS entity. + public override void Load(object saveData, World world, Entity entity) + { + m_Index = (int)saveData; + var list = m_List.GetValue() as IList; + if (list != null && m_Index < list.Count) { + m_Element.SetValue(list[m_Index]); + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/Iterator.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/Iterator.cs.meta new file mode 100644 index 0000000..68ad6bd --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/Iterator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5af8e0ebe3541fb4ba56854fa8a6bd62 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/PriorityEvaluator.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/PriorityEvaluator.cs new file mode 100644 index 0000000..53e11e6 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/PriorityEvaluator.cs @@ -0,0 +1,113 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Decorators +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.BehaviorDesigner.Runtime.Groups; + using Opsive.BehaviorDesigner.Runtime.Tasks.Composites; + using Opsive.GraphDesigner.Runtime; + using Unity.Entities; + + /// + /// Provides a PriorityValueComponent implementation that returns a priority value. + /// + public abstract class PriorityEvaluator : DecoratorNode + { + /// + /// Returns the priority of the decorator. The higher the priority the more likely the task will run next. + /// + /// The priority of the decorator. + public abstract float GetPriorityValue(); + + /// + /// Adds the task to the behavior tree buffer. + /// + /// The world that the task runs in. + /// The entity that the task is connected to. + /// The ID of the behavior tree running the task. + /// The index of the task. + public override void AddBufferElement(World world, Entity entity, int behaviorTreeID, ushort index) + { + base.AddBufferElement(world, entity, behaviorTreeID, index); + + DynamicBuffer buffer; + if (world.EntityManager.HasBuffer(entity)) { + buffer = world.EntityManager.GetBuffer(entity); + } else { + buffer = world.EntityManager.AddBuffer(entity); + } + buffer.Add(new PriorityValueComponent() + { + Index = index, + }); + var traversalTaskSystems = world.GetOrCreateSystemManaged(); + traversalTaskSystems.AddSystemToUpdateList(world.GetOrCreateSystem(typeof(PriorityEvaluatorSystem))); + } + + /// + /// Clears all component buffers from the behavior tree buffer. + /// + /// The world that the task runs in. + /// The entity that the task is connected to. + public override void ClearBufferElement(World world, Entity entity) + { + base.ClearBufferElement(world, entity); + + DynamicBuffer buffer; + if (world.EntityManager.HasBuffer(entity)) { + buffer = world.EntityManager.GetBuffer(entity); + buffer.Clear(); + } + } + + /// + /// Executes the task logic. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + var taskComponents = m_BehaviorTree.World.EntityManager.GetBuffer(m_BehaviorTree.Entity); + var childStatus = taskComponents[RuntimeIndex + 1].Status; // Index + 1 will always be the task's only child. + if (childStatus == TaskStatus.Success || childStatus == TaskStatus.Failure) { + return childStatus; + } + return TaskStatus.Running; + } + } + + /// + /// Sets the PriorityValueComponent value. + /// + [DisableAutoCreation] + [UpdateBefore(typeof(PrioritySelectorTaskSystem))] + public partial struct PriorityEvaluatorSystem : ISystem + { + /// + /// Updates the logic. + /// + /// The current state of the system. + private void OnUpdate(ref SystemState state) + { + foreach (var (priorityValueComponents, taskComponents, entity) in + SystemAPI.Query, DynamicBuffer>().WithAll().WithEntityAccess()) { + + for (int i = 0; i < priorityValueComponents.Length; ++i) { + var priorityValueComponent = priorityValueComponents[i]; + var priorityEvaluator = BehaviorTree.GetBehaviorTree(entity).GetTask(priorityValueComponent.Index) as PriorityEvaluator; + if (priorityEvaluator == null) { + continue; + } + + priorityValueComponent.Value = priorityEvaluator.GetPriorityValue(); + var priorityValueComponentBuffer = priorityValueComponents; + priorityValueComponentBuffer[i] = priorityValueComponent; + } + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/PriorityEvaluator.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/PriorityEvaluator.cs.meta new file mode 100644 index 0000000..a82df67 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/PriorityEvaluator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fa0f2261dad25fe4695811e9513527c8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/PriorityVariableEvaluator.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/PriorityVariableEvaluator.cs new file mode 100644 index 0000000..6292da7 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/PriorityVariableEvaluator.cs @@ -0,0 +1,29 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Decorators +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + /// + /// Implements the PriorityEvaluator returning a SharedVariable value. + /// + [Opsive.Shared.Utility.Description("Sets the priority value to the specified SharedVariable float value.")] + public class PriorityVariableEvaluator : PriorityEvaluator + { + [Tooltip("The priority of the decorator.")] + [SerializeField] SharedVariable m_Priority; + + /// + /// Returns the priority of the decorator. The higher the priority the more likely the task will run next. + /// + /// The priority of the decorator. + public override float GetPriorityValue() { return m_Priority.Value; } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/PriorityVariableEvaluator.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/PriorityVariableEvaluator.cs.meta new file mode 100644 index 0000000..9d0ed5f --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/PriorityVariableEvaluator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5620437f8c0efed48a49fd477ba18a91 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/Repeater.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/Repeater.cs new file mode 100644 index 0000000..1e005b5 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/Repeater.cs @@ -0,0 +1,304 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Decorators +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using Opsive.Shared.Utility; + using Unity.Burst; + using Unity.Entities; + using UnityEngine; + + /// + /// A node representation of the repeater task. + /// + [NodeIcon("ceb6f3e7f67cde640b28b2a15ec13ffe", "bb415ca6de87c3d49ab9a94fe8a6fca8")] + [Opsive.Shared.Utility.Description(@"The repeater task will repeat execution of its child task until the child task has been run a specified number of times. " + + "It has the option of continuing to execute the child task even if the child task returns a failure.")] + public class Repeater : ECSDecoratorTask, IParentNode, ISavableTask + { + [Tooltip("Should the task be repeated forever?")] + [SerializeField] bool m_RepeatForever; + [Tooltip("The number of times the task should repeat.")] + [SerializeField] ushort m_RepeatCount; + [Tooltip("Should the repeater end if the child task fails?")] + [SerializeField] bool m_EndOnFailure; + + private ushort m_ComponentIndex; + + public bool RepeatForever { get => m_RepeatForever; set => m_RepeatForever = value; } + public ushort RepeatCount { get => m_RepeatCount; set => m_RepeatCount = value; } + public bool EndOnFailure { get => m_EndOnFailure; set => m_EndOnFailure = value; } + + public override ComponentType Flag { get => typeof(RepeaterFlag); } + + /// + /// Resets the task to its default values. + /// + public override void Reset() { m_RepeatForever = true; } + + /// + /// Returns a new TBufferElement for use by the system. + /// + /// A new TBufferElement for use by the system. + public override RepeaterComponent GetBufferElement() + { + return new RepeaterComponent() { + Index = RuntimeIndex, + RepeatCount = m_RepeatForever ? -1 : m_RepeatCount, + EndOnFailure = m_EndOnFailure, + }; + } + + /// + /// Adds the IBufferElementData to the entity. + /// + /// The world that the entity exists in. + /// The entity that the IBufferElementData should be assigned to. + /// The GameObject that the entity is attached to. + /// The index of the element within the buffer. + public override int AddBufferElement(World world, Entity entity, GameObject gameObject) + { + m_ComponentIndex = (ushort)base.AddBufferElement(world, entity, gameObject); + return m_ComponentIndex; + } + + /// + /// Specifies the type of reflection that should be used to save the task. + /// + /// The index of the sub-task. This is used for the task set allowing each contained task to have their own save type. + public MemberVisibility GetSaveReflectionType(int index) { return MemberVisibility.None; } + + /// + /// Returns the current task state. + /// + /// The DOTS world. + /// The DOTS entity. + /// The current task state. + public object Save(World world, Entity entity) + { + var repeaterComponents = world.EntityManager.GetBuffer(entity); + var repeaterComponent = repeaterComponents[m_ComponentIndex]; + + // Save the current count. + return repeaterComponent.CurrentCount; + } + + /// + /// Loads the previous task state. + /// + /// The previous task state. + /// The DOTS world. + /// The DOTS entity. + public void Load(object saveData, World world, Entity entity) + { + var repeaterComponents = world.EntityManager.GetBuffer(entity); + var repeaterComponent = repeaterComponents[m_ComponentIndex]; + + // saveData is the current count. + repeaterComponent.CurrentCount = (uint)saveData; + repeaterComponents[m_ComponentIndex] = repeaterComponent; + } + } + + /// + /// The DOTS data structure for the Repeater class. + /// + public struct RepeaterComponent : IBufferElementData + { + [Tooltip("The index of the node.")] + public ushort Index; + [Tooltip("The number of times the child task can repeat.")] + public int RepeatCount; + [Tooltip("The number of times the child task has been repeated.")] + public uint CurrentCount; + [Tooltip("Should the task end when the child returns failure?")] + public bool EndOnFailure; + } + + /// + /// A DOTS tag indicating when a Repeater node is active. + /// + public struct RepeaterFlag : IComponentData, IEnableableComponent { } + + /// + /// Runs the Repeater logic. + /// + [DisableAutoCreation] + public partial struct RepeaterTaskSystem : ISystem + { + /// + /// Creates the job. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + var query = SystemAPI.QueryBuilder().WithAllRW().WithAllRW().WithAllRW().WithAll().Build(); + state.Dependency = new RepeaterJob().ScheduleParallel(query, state.Dependency); + } + + /// + /// Job which executes the task logic. + /// + [BurstCompile] + private partial struct RepeaterJob : IJobEntity + { + /// + /// Executes the repeater logic. + /// + /// An array of BranchComponents. + /// An array of TaskComponents. + /// An array of RepeaterComponents. + [BurstCompile] + public void Execute(ref DynamicBuffer branchComponents, ref DynamicBuffer taskComponents, ref DynamicBuffer repeaterComponents) + { + for (int i = 0; i < repeaterComponents.Length; ++i) { + var repeaterComponent = repeaterComponents[i]; + var taskComponent = taskComponents[repeaterComponent.Index]; + var branchComponent = branchComponents[taskComponent.BranchIndex]; + if (!branchComponent.CanExecute) { + continue; + } + + if (taskComponent.Status == TaskStatus.Queued) { + taskComponent.Status = TaskStatus.Running; + taskComponents[taskComponent.Index] = taskComponent; + + repeaterComponent.CurrentCount = 1; + var repeaterBuffer = repeaterComponents; + repeaterBuffer[i] = repeaterComponent; + + branchComponent.NextIndex = (ushort)(taskComponent.Index + 1); + branchComponents[taskComponent.BranchIndex] = branchComponent; + + // Start the child. + var nextChildTaskComponent = taskComponents[branchComponent.NextIndex]; + nextChildTaskComponent.Status = TaskStatus.Queued; + taskComponents[branchComponent.NextIndex] = nextChildTaskComponent; + } else if (taskComponent.Status != TaskStatus.Running) { + continue; + } + + // The repeater task is currently active. Check the first child. + var childTaskComponent = taskComponents[taskComponent.Index + 1]; + if (childTaskComponent.Status == TaskStatus.Queued || childTaskComponent.Status == TaskStatus.Running) { + // The child should keep running. + continue; + } + + branchComponent = branchComponents[childTaskComponent.BranchIndex]; + if ((repeaterComponent.RepeatCount == -1 || repeaterComponent.CurrentCount <= repeaterComponent.RepeatCount) && + (childTaskComponent.Status == TaskStatus.Success || (!repeaterComponent.EndOnFailure && childTaskComponent.Status == TaskStatus.Failure))) { + // Restart the child if the branch should repeat again. + childTaskComponent.Status = TaskStatus.Queued; + taskComponents[childTaskComponent.Index] = childTaskComponent; + + repeaterComponent.CurrentCount++; + var repeaterBuffer = repeaterComponents; + repeaterBuffer[i] = repeaterComponent; + + branchComponent.NextIndex = childTaskComponent.Index; + branchComponents[childTaskComponent.BranchIndex] = branchComponent; + } else { + // End with the child status if there should not be any more repeats. An inactive status will be returned if the child is disabled. + taskComponent.Status = childTaskComponent.Status == TaskStatus.Inactive ? TaskStatus.Success : childTaskComponent.Status; + taskComponents[taskComponent.Index] = taskComponent; + + branchComponent.NextIndex = taskComponent.ParentIndex; + branchComponents[childTaskComponent.BranchIndex] = branchComponent; + } + } + } + } + } + /// + /// A node representation of the repeater task. + /// + [NodeIcon("ceb6f3e7f67cde640b28b2a15ec13ffe", "bb415ca6de87c3d49ab9a94fe8a6fca8")] + [Opsive.Shared.Utility.Description(@"The repeater task will repeat execution of its child task until the child task has been run a specified number of times. " + + "It has the option of continuing to execute the child task even if the child task returns a failure. Uses the GameObject workflow.")] + public class SharedRepeater : DecoratorNode + { + [Tooltip("Should the task be repeated forever?")] + [SerializeField] SharedVariable m_RepeatForever = true; + [Tooltip("The number of times the task should repeat.")] + [SerializeField] SharedVariable m_RepeatCount; + [Tooltip("Should the repeater end if the child task fails?")] + [SerializeField] SharedVariable m_EndOnFailure; + + public SharedVariable RepeatForever { get => m_RepeatForever; set => m_RepeatForever = value; } + public SharedVariable RepeatCount { get => m_RepeatCount; set => m_RepeatCount = value; } + public SharedVariable EndOnFailure { get => m_EndOnFailure; set => m_EndOnFailure = value; } + + private uint m_CurrentCount; + + /// + /// Callback when the task is started. + /// + public override void OnStart() + { + base.OnStart(); + m_CurrentCount = 0; + } + + /// + /// Executes the task logic. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + var taskComponents = m_BehaviorTree.World.EntityManager.GetBuffer(m_BehaviorTree.Entity); + if (taskComponents[Index + 1].Status == TaskStatus.Running || taskComponents[Index + 1].Status == TaskStatus.Queued) { + return TaskStatus.Running; + } + + if (taskComponents[Index + 1].Status == TaskStatus.Failure && m_EndOnFailure.Value) { + return TaskStatus.Failure; + } + + // The child isn't running. Repeat + if (m_RepeatForever.Value || m_CurrentCount <= m_RepeatCount.Value) { + m_CurrentCount++; + return TaskStatus.Running; + } + + return taskComponents[Index + 1].Status; + } + + /// + /// Specifies the type of reflection that should be used to save the task. + /// + /// The index of the sub-task. This is used for the task set allowing each contained task to have their own save type. + public override MemberVisibility GetSaveReflectionType(int index) { return MemberVisibility.None; } + + /// + /// Returns the current task state. + /// + /// The DOTS world. + /// The DOTS entity. + /// The current task state. + public override object Save(World world, Entity entity) + { + // Save the current count. + return m_CurrentCount; + } + + /// + /// Loads the previous task state. + /// + /// The previous task state. + /// The DOTS world. + /// The DOTS entity. + public override void Load(object saveData, World world, Entity entity) + { + m_CurrentCount = (uint)saveData; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/Repeater.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/Repeater.cs.meta new file mode 100644 index 0000000..8dffca9 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/Repeater.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 19b46aa4b55e8994bae2c60e08040863 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/ReturnFailure.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/ReturnFailure.cs new file mode 100644 index 0000000..cc8ceed --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/ReturnFailure.cs @@ -0,0 +1,125 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Decorators +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.GraphDesigner.Runtime; + using Unity.Burst; + using Unity.Entities; + using UnityEngine; + + /// + /// A node representation of the return failure task. + /// + [NodeIcon("667a475ceee05824188a36b24ec8d392", "7d32c9b05505df24a94069606f3b823d")] + [Opsive.Shared.Utility.Description("The return failure task will always return failure except when the child task is running.")] + public class ReturnFailure : ECSDecoratorTask, IParentNode + { + public override ComponentType Flag { get => typeof(ReturnFailureFlag); } + + /// + /// Returns a new TBufferElement for use by the system. + /// + /// A new TBufferElement for use by the system. + public override ReturnFailureComponent GetBufferElement() + { + return new ReturnFailureComponent() + { + Index = RuntimeIndex, + }; + } + } + + /// + /// The DOTS data structure for the ReturnFailure class. + /// + public struct ReturnFailureComponent : IBufferElementData + { + [Tooltip("The index of the node.")] + public ushort Index; + } + + /// + /// A DOTS tag indicating when an ReturnFailure node is active. + /// + public struct ReturnFailureFlag : IComponentData, IEnableableComponent { } + + /// + /// Runs the ReturnFailure logic. + /// + [DisableAutoCreation] + public partial struct ReturnFailureTaskSystem : ISystem + { + /// + /// Creates the job. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + var query = SystemAPI.QueryBuilder().WithAllRW().WithAllRW().WithAllRW().WithAll().Build(); + state.Dependency = new ReturnFailureJob().ScheduleParallel(query, state.Dependency); + } + + /// + /// Job which executes the task logic. + /// + [BurstCompile] + private partial struct ReturnFailureJob : IJobEntity + { + /// + /// Executes the return failure logic. + /// + /// An array of BranchComponents. + /// An array of TaskComponents. + /// An array of ReturnFailureComponents. + [BurstCompile] + public void Execute(ref DynamicBuffer branchComponents, ref DynamicBuffer taskComponents, ref DynamicBuffer returnFailureComponents) + { + for (int i = 0; i < returnFailureComponents.Length; ++i) { + var returnFailureComponent = returnFailureComponents[i]; + var taskComponent = taskComponents[returnFailureComponent.Index]; + var branchComponent = branchComponents[taskComponent.BranchIndex]; + if (!branchComponent.CanExecute) { + continue; + } + + TaskComponent childTaskComponent; + if (taskComponent.Status == TaskStatus.Queued) { + taskComponent.Status = TaskStatus.Running; + taskComponents[taskComponent.Index] = taskComponent; + + childTaskComponent = taskComponents[taskComponent.Index + 1]; + childTaskComponent.Status = TaskStatus.Queued; + taskComponents[taskComponent.Index + 1] = childTaskComponent; + + branchComponent.NextIndex = (ushort)(taskComponent.Index + 1); + branchComponents[taskComponent.BranchIndex] = branchComponent; + continue; + } else if (taskComponent.Status != TaskStatus.Running) { + continue; + } + + // The return failure task is currently active. Check the first child. + childTaskComponent = taskComponents[taskComponent.Index + 1]; + if (childTaskComponent.Status == TaskStatus.Queued || childTaskComponent.Status == TaskStatus.Running) { + // The child should keep running. + continue; + } + + // The child has completed. Return failure. + taskComponent.Status = TaskStatus.Failure; + taskComponents[taskComponent.Index] = taskComponent; + + branchComponent.NextIndex = taskComponent.ParentIndex; + branchComponents[taskComponent.BranchIndex] = branchComponent; + } + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/ReturnFailure.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/ReturnFailure.cs.meta new file mode 100644 index 0000000..a49e108 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/ReturnFailure.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 52ce11b290bb0b240a985296c757fcd5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/ReturnSuccess.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/ReturnSuccess.cs new file mode 100644 index 0000000..2019e3b --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/ReturnSuccess.cs @@ -0,0 +1,125 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Decorators +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.GraphDesigner.Runtime; + using Unity.Burst; + using Unity.Entities; + using UnityEngine; + + /// + /// A node representation of the return success task. + /// + [NodeIcon("66f47acff1d46f848bc8c22b221ee1d0", "3eb990b93a7fd6e479d6b032c7e6973f")] + [Opsive.Shared.Utility.Description("The return success task will always return success except when the child task is running.")] + public class ReturnSuccess : ECSDecoratorTask, IParentNode + { + public override ComponentType Flag { get => typeof(ReturnSuccessFlag); } + + /// + /// Returns a new TBufferElement for use by the system. + /// + /// A new TBufferElement for use by the system. + public override ReturnSuccessComponent GetBufferElement() + { + return new ReturnSuccessComponent() + { + Index = RuntimeIndex, + }; + } + } + + /// + /// The DOTS data structure for the ReturnSuccess class. + /// + public struct ReturnSuccessComponent : IBufferElementData + { + [Tooltip("The index of the node.")] + public ushort Index; + } + + /// + /// A DOTS tag indicating when an ReturnSuccess node is active. + /// + public struct ReturnSuccessFlag : IComponentData, IEnableableComponent { } + + /// + /// Runs the ReturnSuccess logic. + /// + [DisableAutoCreation] + public partial struct ReturnSuccessTaskSystem : ISystem + { + /// + /// Creates the job. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + var query = SystemAPI.QueryBuilder().WithAllRW().WithAllRW().WithAllRW().WithAll().Build(); + state.Dependency = new ReturnSuccessJob().ScheduleParallel(query, state.Dependency); + } + + /// + /// Job which executes the task logic. + /// + [BurstCompile] + private partial struct ReturnSuccessJob : IJobEntity + { + /// + /// Executes the return success logic. + /// + /// An array of BranchComponents. + /// An array of TaskComponents. + /// An array of ReturnSuccessComponents. + [BurstCompile] + public void Execute(ref DynamicBuffer branchComponents, ref DynamicBuffer taskComponents, ref DynamicBuffer returnSuccessComponents) + { + for (int i = 0; i < returnSuccessComponents.Length; ++i) { + var returnSuccessComponent = returnSuccessComponents[i]; + var taskComponent = taskComponents[returnSuccessComponent.Index]; + var branchComponent = branchComponents[taskComponent.BranchIndex]; + if (!branchComponent.CanExecute) { + continue; + } + + TaskComponent childTaskComponent; + if (taskComponent.Status == TaskStatus.Queued) { + taskComponent.Status = TaskStatus.Running; + taskComponents[taskComponent.Index] = taskComponent; + + childTaskComponent = taskComponents[taskComponent.Index + 1]; + childTaskComponent.Status = TaskStatus.Queued; + taskComponents[taskComponent.Index + 1] = childTaskComponent; + + branchComponent.NextIndex = (ushort)(taskComponent.Index + 1); + branchComponents[taskComponent.BranchIndex] = branchComponent; + continue; + } else if (taskComponent.Status != TaskStatus.Running) { + continue; + } + + // The return success task is currently active. Check the first child. + childTaskComponent = taskComponents[taskComponent.Index + 1]; + if (childTaskComponent.Status == TaskStatus.Queued || childTaskComponent.Status == TaskStatus.Running) { + // The child should keep running. + continue; + } + + // The child has completed. Return success. + taskComponent.Status = TaskStatus.Success; + taskComponents[taskComponent.Index] = taskComponent; + + branchComponent.NextIndex = taskComponent.ParentIndex; + branchComponents[taskComponent.BranchIndex] = branchComponent; + } + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/ReturnSuccess.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/ReturnSuccess.cs.meta new file mode 100644 index 0000000..3c5f548 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/ReturnSuccess.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ffe15b86a15ee5e4c9c4693ab315d6c6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UntilFailure.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UntilFailure.cs new file mode 100644 index 0000000..51fe1dd --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UntilFailure.cs @@ -0,0 +1,135 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Decorators +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.GraphDesigner.Runtime; + using Unity.Burst; + using Unity.Entities; + using UnityEngine; + + /// + /// A node representation of the until failure task. + /// + [NodeIcon("60da350fd1f5b48428e466b79cb85cb2", "3d29cc3223984f44291c0e423a0aa6c6")] + [Opsive.Shared.Utility.Description("The until failure task will keep executing its child task until the child task returns failure.")] + public class UntilFailure : ECSDecoratorTask, IParentNode + { + public override ComponentType Flag { get => typeof(UntilFailureFlag); } + + /// + /// Returns a new TBufferElement for use by the system. + /// + /// A new TBufferElement for use by the system. + public override UntilFailureComponent GetBufferElement() + { + return new UntilFailureComponent() + { + Index = RuntimeIndex, + }; + } + } + + /// + /// The DOTS data structure for the UntilFailure class. + /// + public struct UntilFailureComponent : IBufferElementData + { + [Tooltip("The index of the node.")] + public ushort Index; + } + + /// + /// A DOTS tag indicating when an UntilFailure node is active. + /// + public struct UntilFailureFlag : IComponentData, IEnableableComponent { } + + /// + /// Runs the UntilFailure logic. + /// + [DisableAutoCreation] + public partial struct UntilFailureTaskSystem : ISystem + { + /// + /// Creates the job. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + var query = SystemAPI.QueryBuilder().WithAllRW().WithAllRW().WithAllRW().WithAll().Build(); + state.Dependency = new UntilFailureJob().ScheduleParallel(query, state.Dependency); + } + + /// + /// Job which executes the task logic. + /// + [BurstCompile] + private partial struct UntilFailureJob : IJobEntity + { + /// + /// Executes the until failure logic. + /// + /// An array of BranchComponents. + /// An array of TaskComponents. + /// An array of UntilFailureComponents. + [BurstCompile] + public void Execute(ref DynamicBuffer branchComponents, ref DynamicBuffer taskComponents, ref DynamicBuffer untilFailureComponents) + { + for (int i = 0; i < untilFailureComponents.Length; ++i) { + var untilFailureComponent = untilFailureComponents[i]; + var taskComponent = taskComponents[untilFailureComponent.Index]; + var branchComponent = branchComponents[taskComponent.BranchIndex]; + if (!branchComponent.CanExecute) { + continue; + } + + TaskComponent childTaskComponent; + if (taskComponent.Status == TaskStatus.Queued) { + taskComponent.Status = TaskStatus.Running; + taskComponents[taskComponent.Index] = taskComponent; + + childTaskComponent = taskComponents[taskComponent.Index + 1]; + childTaskComponent.Status = TaskStatus.Queued; + taskComponents[taskComponent.Index + 1] = childTaskComponent; + + branchComponent.NextIndex = (ushort)(taskComponent.Index + 1); + branchComponents[taskComponent.BranchIndex] = branchComponent; + continue; + } else if (taskComponent.Status != TaskStatus.Running) { + continue; + } + + // The until failure task is currently active. Check the first child. + childTaskComponent = taskComponents[taskComponent.Index + 1]; + if (childTaskComponent.Status == TaskStatus.Queued || childTaskComponent.Status == TaskStatus.Running) { + // The child should keep running. + continue; + } + + // If the child returns success then it should be queued again. + if (childTaskComponent.Status == TaskStatus.Success) { + childTaskComponent.Status = TaskStatus.Queued; + taskComponents[taskComponent.Index + 1] = childTaskComponent; + + branchComponent.NextIndex = (ushort)(taskComponent.Index + 1); + branchComponents[taskComponent.BranchIndex] = branchComponent; + continue; + } + + // The child has returned failure. + taskComponent.Status = TaskStatus.Failure; + taskComponents[taskComponent.Index] = taskComponent; + + branchComponent.NextIndex = taskComponent.ParentIndex; + branchComponents[taskComponent.BranchIndex] = branchComponent; + } + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UntilFailure.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UntilFailure.cs.meta new file mode 100644 index 0000000..9876f2b --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UntilFailure.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8b8878b781010e04b87748609a6ac6d3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UntilSuccess.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UntilSuccess.cs new file mode 100644 index 0000000..36c8841 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UntilSuccess.cs @@ -0,0 +1,135 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Decorators +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.GraphDesigner.Runtime; + using Unity.Burst; + using Unity.Entities; + using UnityEngine; + + /// + /// A node representation of the until success task. + /// + [NodeIcon("f2e750025a5812640919385b75319d6f", "4e9ac4f2dd8bfe741a5f889efb1ade67")] + [Opsive.Shared.Utility.Description("The until success task will keep executing its child task until the child task returns success.")] + public class UntilSuccess : ECSDecoratorTask, IParentNode + { + public override ComponentType Flag { get => typeof(UntilSuccessFlag); } + + /// + /// Returns a new TBufferElement for use by the system. + /// + /// A new TBufferElement for use by the system. + public override UntilSuccessComponent GetBufferElement() + { + return new UntilSuccessComponent() + { + Index = RuntimeIndex, + }; + } + } + + /// + /// The DOTS data structure for the UntilSuccess class. + /// + public struct UntilSuccessComponent : IBufferElementData + { + [Tooltip("The index of the node.")] + public ushort Index; + } + + /// + /// A DOTS tag indicating when an UntilSuccess node is active. + /// + public struct UntilSuccessFlag : IComponentData, IEnableableComponent { } + + /// + /// Runs the UntilSuccess logic. + /// + [DisableAutoCreation] + public partial struct UntilSuccessTaskSystem : ISystem + { + /// + /// Creates the job. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + var query = SystemAPI.QueryBuilder().WithAllRW().WithAllRW().WithAllRW().WithAll().Build(); + state.Dependency = new UntilSuccessJob().ScheduleParallel(query, state.Dependency); + } + + /// + /// Job which executes the task logic. + /// + [BurstCompile] + private partial struct UntilSuccessJob : IJobEntity + { + /// + /// Executes the until success logic. + /// + /// An array of BranchComponents. + /// An array of TaskComponents. + /// An array of UntilSuccessComponents. + [BurstCompile] + public void Execute(ref DynamicBuffer branchComponents, ref DynamicBuffer taskComponents, ref DynamicBuffer untilSuccessComponents) + { + for (int i = 0; i < untilSuccessComponents.Length; ++i) { + var untilSuccessComponent = untilSuccessComponents[i]; + var taskComponent = taskComponents[untilSuccessComponent.Index]; + var branchComponent = branchComponents[taskComponent.BranchIndex]; + if (!branchComponent.CanExecute) { + continue; + } + + TaskComponent childTaskComponent; + if (taskComponent.Status == TaskStatus.Queued) { + taskComponent.Status = TaskStatus.Running; + taskComponents[taskComponent.Index] = taskComponent; + + childTaskComponent = taskComponents[taskComponent.Index + 1]; + childTaskComponent.Status = TaskStatus.Queued; + taskComponents[taskComponent.Index + 1] = childTaskComponent; + + branchComponent.NextIndex = (ushort)(taskComponent.Index + 1); + branchComponents[taskComponent.BranchIndex] = branchComponent; + continue; + } else if (taskComponent.Status != TaskStatus.Running) { + continue; + } + + // The until success task is currently active. Check the first child. + childTaskComponent = taskComponents[taskComponent.Index + 1]; + if (childTaskComponent.Status == TaskStatus.Queued || childTaskComponent.Status == TaskStatus.Running ) { + // The child should keep running. + continue; + } + + // If the child returns failure then it should be queued again. + if (childTaskComponent.Status == TaskStatus.Failure) { + childTaskComponent.Status = TaskStatus.Queued; + taskComponents[taskComponent.Index + 1] = childTaskComponent; + + branchComponent.NextIndex = (ushort)(taskComponent.Index + 1); + branchComponents[taskComponent.BranchIndex] = branchComponent; + continue; + } + + // The child has returned success. The task can end. + taskComponent.Status = TaskStatus.Success; + taskComponents[taskComponent.Index] = taskComponent; + + branchComponent.NextIndex = taskComponent.ParentIndex; + branchComponents[taskComponent.BranchIndex] = branchComponent; + } + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UntilSuccess.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UntilSuccess.cs.meta new file mode 100644 index 0000000..b906293 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UntilSuccess.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b11a4f9197ec0964cb1f620368654a53 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UtilityCurveEvaluator.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UtilityCurveEvaluator.cs new file mode 100644 index 0000000..f2f72a0 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UtilityCurveEvaluator.cs @@ -0,0 +1,65 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Decorators +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + using UnityEngine.Serialization; + + /// + /// Implements the UtilityEvaluator returning a SharedVariable value. + /// + [Opsive.Shared.Utility.Description("Sets the utility value to the evaluated curve value.")] + public class UtilityCurveEvaluator : UtilityEvaluator + { + [Tooltip("The curve that should be evaluated for the utility value.")] + [FormerlySerializedAs("m_Utility")] + [SerializeField] SharedVariable m_UtilityValue; + [Tooltip("The time to evaluate the curve at. Set it to -1 to use Time.time.")] + [SerializeField] SharedVariable m_Time; + [Tooltip("Should the time be reset after the task stops running?")] + [SerializeField] SharedVariable m_ResetTimeOnEnd; + + private float m_ResetTime = -1; + + /// + /// Resets the task values back to their default. + /// + public override void Reset() + { + base.Reset(); + + m_UtilityValue = AnimationCurve.Linear(0, 0, 1, 1); + m_Time = -1; + m_ResetTimeOnEnd = false; + } + + /// + /// Returns the utility of the decorator. The higher the utility the more likely the task will run next. + /// + /// The utility of the decorator. + public override float GetUtilityValue() + { + var evaluateTime = m_Time.Value == -1 ? Time.time : m_Time.Value; + if (m_ResetTimeOnEnd.Value && m_ResetTime != -1) { + evaluateTime = Time.time - m_ResetTime; + } + + return m_UtilityValue.Value.Evaluate(evaluateTime); + } + + /// + /// The task has ended. + /// + public override void OnEnd() + { + m_ResetTime = Time.time; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UtilityCurveEvaluator.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UtilityCurveEvaluator.cs.meta new file mode 100644 index 0000000..b2c6f4a --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UtilityCurveEvaluator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6052dd7dfb15b574eaba0db3729bbee4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UtilityEvaluator.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UtilityEvaluator.cs new file mode 100644 index 0000000..db5bb86 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UtilityEvaluator.cs @@ -0,0 +1,130 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Decorators +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.BehaviorDesigner.Runtime.Groups; + using Opsive.BehaviorDesigner.Runtime.Tasks.Composites; + using Unity.Entities; + using UnityEngine; + + /// + /// Provides a UtilityValueComponent implementation that returns a utility value. + /// + public abstract class UtilityEvaluator : DecoratorNode + { + [Tooltip("Should an infinite utility value be returned while the child is running?")] + [SerializeField] protected bool m_BlockDuringExecution = true; + + public bool BlockDuringExecution { get => m_BlockDuringExecution; set => m_BlockDuringExecution = value; } + + /// + /// Returns the utility of the decorator. The higher the utility the more likely the task will run next. + /// + /// The utility of the decorator. + public abstract float GetUtilityValue(); + + /// + /// Adds the task to the behavior tree buffer. + /// + /// The world that the task runs in. + /// The entity that the task is connected to. + /// The ID of the behavior tree running the task. + /// The index of the task. + public override void AddBufferElement(World world, Entity entity, int behaviorTreeID, ushort index) + { + base.AddBufferElement(world, entity, behaviorTreeID, index); + + DynamicBuffer buffer; + if (world.EntityManager.HasBuffer(entity)) { + buffer = world.EntityManager.GetBuffer(entity); + } else { + buffer = world.EntityManager.AddBuffer(entity); + } + + buffer.Add(new UtilityValueComponent() + { + Index = index, + }); + var traversalTaskSystems = world.GetOrCreateSystemManaged(); + traversalTaskSystems.AddSystemToUpdateList(world.GetOrCreateSystem(typeof(UtilityEvaluatorSystem))); + } + + /// + /// Clears all component buffers from the behavior tree buffer. + /// + /// The world that the task runs in. + /// The entity that the task is connected to. + public override void ClearBufferElement(World world, Entity entity) + { + base.ClearBufferElement(world, entity); + + DynamicBuffer buffer; + if (world.EntityManager.HasBuffer(entity)) { + buffer = world.EntityManager.GetBuffer(entity); + buffer.Clear(); + } + } + + /// + /// Executes the task logic. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + var taskComponents = m_BehaviorTree.World.EntityManager.GetBuffer(m_BehaviorTree.Entity); + var childStatus = taskComponents[RuntimeIndex + 1].Status; // Index + 1 will always be the task's only child. + if (childStatus == TaskStatus.Success || childStatus == TaskStatus.Failure) { + return childStatus; + } + return TaskStatus.Running; + } + } + + /// + /// Sets the UtilityValueComponent value. + /// + [DisableAutoCreation] + [UpdateBefore(typeof(UtilitySelectorTaskSystem))] + public partial struct UtilityEvaluatorSystem : ISystem + { + /// + /// Updates the logic. + /// + /// The current state of the system. + private void OnUpdate(ref SystemState state) + { + foreach (var (utilityValueComponents, taskComponents, entity) in + SystemAPI.Query, DynamicBuffer>().WithAll().WithEntityAccess()) { + + for (int i = 0; i < utilityValueComponents.Length; ++i) { + var utilityValueComponent = utilityValueComponents[i]; + var utilityEvaluator = BehaviorTree.GetBehaviorTree(entity).GetTask(utilityValueComponent.Index) as UtilityEvaluator; + if (utilityEvaluator == null) { + continue; + } + + // If the branch is currently active then it should return an infinite utility value until the branch has completed. This will allow the entire + // branch to execute. + if (utilityEvaluator.BlockDuringExecution) { + var taskComponent = taskComponents[utilityValueComponent.Index + 1]; + if (taskComponent.Status == TaskStatus.Running) { + utilityValueComponent.Value = float.PositiveInfinity; + } else { + utilityValueComponent.Value = utilityEvaluator.GetUtilityValue(); + } + } else { + utilityValueComponent.Value = utilityEvaluator.GetUtilityValue(); + } + var utilityValueComponentBuffer = utilityValueComponents; + utilityValueComponentBuffer[i] = utilityValueComponent; + } + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UtilityEvaluator.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UtilityEvaluator.cs.meta new file mode 100644 index 0000000..b6de0e1 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UtilityEvaluator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 74c275bf295659342be09f83dcacd5cd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UtilityVariableEvaluator.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UtilityVariableEvaluator.cs new file mode 100644 index 0000000..52c6ca5 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UtilityVariableEvaluator.cs @@ -0,0 +1,29 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Decorators +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + /// + /// Implements the UtilityEvaluator returning a SharedVariable value. + /// + [Opsive.Shared.Utility.Description("Sets the utility value to the specified SharedVariable float value.")] + public class UtilityVariableEvaluator : UtilityEvaluator + { + [Tooltip("The utility of the decorator.")] + [SerializeField] SharedVariable m_Utility; + + /// + /// Returns the utility of the decorator. The higher the utility the more likely the task will run next. + /// + /// The utility of the decorator. + public override float GetUtilityValue() { return m_Utility.Value; } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UtilityVariableEvaluator.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UtilityVariableEvaluator.cs.meta new file mode 100644 index 0000000..7c5d953 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Decorators/UtilityVariableEvaluator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fa1905f557f151b45b17a10ffb0a44f3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/ECSTask.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/ECSTask.cs new file mode 100644 index 0000000..e8fd977 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/ECSTask.cs @@ -0,0 +1,132 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks +{ + using Opsive.GraphDesigner.Runtime; + using Unity.Entities; + using UnityEngine; + + /// + /// Base class for a boilerplate ECS task. + /// + public abstract class ECSTask : ITreeLogicNode, IAuthoringTask where TBufferElement : unmanaged, IBufferElementData + { + [Tooltip("The index of the node.")] + [SerializeField] ushort m_Index; + [Tooltip("The parent index of the node. ushort.MaxValue indicates no parent.")] + [SerializeField] ushort m_ParentIndex; + [Tooltip("The sibling index of the node. ushort.MaxValue indicates no sibling.")] + [SerializeField] ushort m_SiblingIndex; + + /// + /// The type of flag that should be enabled when the task is running. + /// + public abstract ComponentType Flag { get; } + /// + /// The system type that the component uses. + /// + public System.Type SystemType => typeof(TSystem); + + public ushort Index + { + get => m_Index; + set => m_Index = value; + } + + public ushort ParentIndex + { + get => m_ParentIndex; + set => m_ParentIndex = value; + } + + public ushort SiblingIndex + { + get => m_SiblingIndex; + set => m_SiblingIndex = value; + } + + public ushort RuntimeIndex { get; set; } + + /// + /// Resets the node values back to their default. + /// + public virtual void Reset() { } + + /// + /// Adds the IBufferElementData to the entity. + /// + /// The world that the entity exists in. + /// The entity that the IBufferElementData should be assigned to. + /// The GameObject that the entity is attached to. + /// The index of the element within the buffer. + public virtual int AddBufferElement(World world, Entity entity, GameObject gameObject) + { + DynamicBuffer buffer; + if (world.EntityManager.HasBuffer(entity)) { + buffer = world.EntityManager.GetBuffer(entity); + } else { + buffer = world.EntityManager.AddBuffer(entity); + } + + buffer.Add(GetBufferElement()); + return buffer.Length - 1; + } + + /// + /// Returns a new TBufferElement for use by the system. + /// + /// A new TBufferElement for use by the system. + public abstract TBufferElement GetBufferElement(); + + /// + /// Clears the IBufferElementData from the entity. + /// + /// The world that the entity exists in. + /// The entity that the IBufferElementData should be cleared from. + public void ClearBufferElement(World world, Entity entity) + { + DynamicBuffer buffer; + if (world.EntityManager.HasBuffer(entity)) { + buffer = world.EntityManager.GetBuffer(entity); + buffer.Clear(); + } + } + } + + /// + /// Base class for an ECS action task. + /// + public abstract class ECSActionTask : ECSTask, IAction where TComponent : unmanaged, IBufferElementData { } + + /// + /// Base class for an ECS composite task. + /// + public abstract class ECSCompositeTask : ECSTask, IComposite, IParentNode where TComponent : unmanaged, IBufferElementData + { + /// + /// The maximum number of children the node can have. + /// + public virtual int MaxChildCount { get => ushort.MaxValue; } + } + + /// + /// Base class for an ECS conditional task. + /// + public abstract class ECSConditionalTask : ECSTask, IConditional where TComponent : unmanaged, IBufferElementData { } + + /// + /// Base class for an ECS decorator task. + /// + public abstract class ECSDecoratorTask : ECSTask, IDecorator, IParentNode where TComponent : unmanaged, IBufferElementData + { + /// + /// The maximum number of children the node can have. + /// + public int MaxChildCount { get => 1; } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/ECSTask.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/ECSTask.cs.meta new file mode 100644 index 0000000..37c6a40 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/ECSTask.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5ab224e1523f7bf41a1bf128e4e1c02a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events.meta new file mode 100644 index 0000000..f01189c --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 77a6adc251fa2434892e5e0d483f1fb0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/EventNode.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/EventNode.cs new file mode 100644 index 0000000..aac502e --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/EventNode.cs @@ -0,0 +1,35 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Events +{ + using Opsive.GraphDesigner.Runtime; + using UnityEngine; + + /// + /// A base IEventNode implementation. + /// + [NodeIcon("9041375773f69454792084ab67820b7e", "b1382ad24c668174c9a6e0bd00f229e3")] + public abstract class EventNode : IEventNode, IEventNodeGameObjectReceiver + { + [Tooltip("The index of the ITreeLogicNode that the IEventNode is connected to. ushort.MaxValue indicates no connection.")] + [SerializeField] protected ushort m_ConnectedIndex; + + public ushort ConnectedIndex { get => m_ConnectedIndex; set => m_ConnectedIndex = value; } + + protected BehaviorTree m_BehaviorTree; + + /// + /// Initializes the node to the specified graph. + /// + /// The graph that is initializing the task. + public virtual void Initialize(IGraph graph) + { + m_BehaviorTree = graph as BehaviorTree; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/EventNode.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/EventNode.cs.meta new file mode 100644 index 0000000..4056695 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/EventNode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ae332159f8bb5f14c8a6d12075be9bab +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnCollisionEnter.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnCollisionEnter.cs new file mode 100644 index 0000000..a03fe26 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnCollisionEnter.cs @@ -0,0 +1,60 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Events +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [AllowMultipleTypes] + [NodeIcon("06864c37115f11445b04701c616d0e14", "8b8a2793322238240b4f25171d772003")] + [Opsive.Shared.Utility.Description("Invoked when the agent causes a collision.")] + public class OnCollisionEnter : EventNode + { + [Tooltip("The tag of the GameObject that the collision should be checked against.")] + [SerializeField] protected SharedVariable m_Tag; + [Tooltip("The collided GameObject.")] + [SerializeField] protected SharedVariable m_StoredCollisionGameObject; + + /// + /// Initializes the node to the specified graph. + /// + /// The graph that is initializing the task. + public override void Initialize(IGraph graph) + { + base.Initialize(graph); + + m_BehaviorTree.OnBehaviorTreeDestroyed += Destroy; + m_BehaviorTree.OnBehaviorTreeCollisionEnter += EnteredCollision; + } + + /// + /// The agent has caused a collision. + /// + /// The collision that caused the event. + private void EnteredCollision(Collision collision) + { + if (!string.IsNullOrEmpty(m_Tag.Value) && !collision.gameObject.CompareTag(m_Tag.Value)) { + return; + } + + if (m_StoredCollisionGameObject != null && m_StoredCollisionGameObject.IsShared) { m_StoredCollisionGameObject.Value = collision.gameObject; } + + m_BehaviorTree.StartBranch(this); + } + + /// + /// The behavior tree has been destroyed. + /// + private void Destroy() + { + m_BehaviorTree.OnBehaviorTreeDestroyed -= Destroy; + m_BehaviorTree.OnBehaviorTreeCollisionEnter -= EnteredCollision; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnCollisionEnter.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnCollisionEnter.cs.meta new file mode 100644 index 0000000..66c7494 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnCollisionEnter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8e38ab2e4d966814f8b760b1f9d64416 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnCollisionEnter2D.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnCollisionEnter2D.cs new file mode 100644 index 0000000..bce7dc4 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnCollisionEnter2D.cs @@ -0,0 +1,60 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Events +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [AllowMultipleTypes] + [NodeIcon("06864c37115f11445b04701c616d0e14", "8b8a2793322238240b4f25171d772003")] + [Opsive.Shared.Utility.Description("Invoked when the agent causes a 2D collision.")] + public class OnCollisionEnter2D : EventNode + { + [Tooltip("The tag of the GameObject that the collision should be checked against.")] + [SerializeField] protected SharedVariable m_Tag; + [Tooltip("The collided GameObject.")] + [SerializeField] protected SharedVariable m_StoredCollisionGameObject; + + /// + /// Initializes the node to the specified graph. + /// + /// The graph that is initializing the task. + public override void Initialize(IGraph graph) + { + base.Initialize(graph); + + m_BehaviorTree.OnBehaviorTreeDestroyed += Destroy; + m_BehaviorTree.OnBehaviorTreeCollisionEnter2D += EnteredCollision2D; + } + + /// + /// The agent has caused a 2D collision. + /// + /// The collision that caused the event. + private void EnteredCollision2D(Collision2D collision) + { + if (!string.IsNullOrEmpty(m_Tag.Value) && !collision.gameObject.CompareTag(m_Tag.Value)) { + return; + } + + if (m_StoredCollisionGameObject != null && m_StoredCollisionGameObject.IsShared) { m_StoredCollisionGameObject.Value = collision.gameObject; } + + m_BehaviorTree.StartBranch(this); + } + + /// + /// The behavior tree has been destroyed. + /// + private void Destroy() + { + m_BehaviorTree.OnBehaviorTreeDestroyed -= Destroy; + m_BehaviorTree.OnBehaviorTreeCollisionEnter2D -= EnteredCollision2D; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnCollisionEnter2D.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnCollisionEnter2D.cs.meta new file mode 100644 index 0000000..e4775e0 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnCollisionEnter2D.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2280b16f94f390e43a89c0550eac22cc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnCollisionExit.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnCollisionExit.cs new file mode 100644 index 0000000..f964c29 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnCollisionExit.cs @@ -0,0 +1,60 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Events +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [AllowMultipleTypes] + [NodeIcon("06864c37115f11445b04701c616d0e14", "8b8a2793322238240b4f25171d772003")] + [Opsive.Shared.Utility.Description("Invoked when the agent leaves a collision.")] + public class OnCollisionExit : EventNode + { + [Tooltip("The tag of the GameObject that the collision should be checked against.")] + [SerializeField] protected SharedVariable m_Tag; + [Tooltip("The collided GameObject.")] + [SerializeField] protected SharedVariable m_StoredCollisionGameObject; + + /// + /// Initializes the node to the specified graph. + /// + /// The graph that is initializing the task. + public override void Initialize(IGraph graph) + { + base.Initialize(graph); + + m_BehaviorTree.OnBehaviorTreeDestroyed += Destroy; + m_BehaviorTree.OnBehaviorTreeCollisionExit += ExitedCollision; + } + + /// + /// The agent has left a collision. + /// + /// The collision that caused the event. + private void ExitedCollision(Collision collision) + { + if (!string.IsNullOrEmpty(m_Tag.Value) && !collision.gameObject.CompareTag(m_Tag.Value)) { + return; + } + + if (m_StoredCollisionGameObject != null && m_StoredCollisionGameObject.IsShared) { m_StoredCollisionGameObject.Value = collision.gameObject; } + + m_BehaviorTree.StartBranch(this); + } + + /// + /// The behavior tree has been destroyed. + /// + private void Destroy() + { + m_BehaviorTree.OnBehaviorTreeDestroyed -= Destroy; + m_BehaviorTree.OnBehaviorTreeCollisionExit -= ExitedCollision; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnCollisionExit.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnCollisionExit.cs.meta new file mode 100644 index 0000000..01c0100 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnCollisionExit.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fee2099d2a111594eadaee56c4998a20 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnCollisionExit2D.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnCollisionExit2D.cs new file mode 100644 index 0000000..84dc7e5 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnCollisionExit2D.cs @@ -0,0 +1,60 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Events +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [AllowMultipleTypes] + [NodeIcon("06864c37115f11445b04701c616d0e14", "8b8a2793322238240b4f25171d772003")] + [Opsive.Shared.Utility.Description("Invoked when the agent leaves a 2D collision.")] + public class OnCollisionExit2D : EventNode + { + [Tooltip("The tag of the GameObject that the collision should be checked against.")] + [SerializeField] protected SharedVariable m_Tag; + [Tooltip("The collided GameObject.")] + [SerializeField] protected SharedVariable m_StoredCollisionGameObject; + + /// + /// Initializes the node to the specified graph. + /// + /// The graph that is initializing the task. + public override void Initialize(IGraph graph) + { + base.Initialize(graph); + + m_BehaviorTree.OnBehaviorTreeDestroyed += Destroy; + m_BehaviorTree.OnBehaviorTreeCollisionExit2D += ExitedCollision2D; + } + + /// + /// The agent has left a 2D collision. + /// + /// The collision that caused the event. + private void ExitedCollision2D(Collision2D collision) + { + if (!string.IsNullOrEmpty(m_Tag.Value) && !collision.gameObject.CompareTag(m_Tag.Value)) { + return; + } + + if (m_StoredCollisionGameObject != null && m_StoredCollisionGameObject.IsShared) { m_StoredCollisionGameObject.Value = collision.gameObject; } + + m_BehaviorTree.StartBranch(this); + } + + /// + /// The behavior tree has been destroyed. + /// + private void Destroy() + { + m_BehaviorTree.OnBehaviorTreeDestroyed -= Destroy; + m_BehaviorTree.OnBehaviorTreeCollisionExit2D -= ExitedCollision2D; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnCollisionExit2D.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnCollisionExit2D.cs.meta new file mode 100644 index 0000000..ce342dd --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnCollisionExit2D.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2bcef3a2041a6144fb9692d1244330af +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnInterrupt.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnInterrupt.cs new file mode 100644 index 0000000..eeb6f7e --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnInterrupt.cs @@ -0,0 +1,130 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Events +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.BehaviorDesigner.Runtime.Groups; + using Opsive.GraphDesigner.Runtime; + using Unity.Burst; + using Unity.Entities; + using UnityEngine; + + [AllowMultipleTypes] + [NodeIcon("10ed9753a0870c84889dc42a7de397a8", "98f584ca47ddad64d9878314395ce160")] + [Opsive.Shared.Utility.Description("EventNode that is invoked when an interrupt occurs.")] + public class OnInterrupt : IEventNode, IEventNodeEntityReceiver + { + [Tooltip("The index of the ITreeLogicNode that the IEventNode is connected to. ushort.MaxValue indicates no connection.")] + [SerializeField] protected ushort m_ConnectedIndex; + [Tooltip("The node that caused the interruption.")] + [SerializeField] ILogicNode m_InterruptionSource; + public ushort ConnectedIndex { get => m_ConnectedIndex; set => m_ConnectedIndex = value; } + + /// + /// Adds the IBufferElementData to the entity. + /// + /// The world that the entity exists in. + /// The entity that the IBufferElementData should be assigned to. + /// The GameObject that the entity is attached to. + /// The offset between the connected index and the runtime index. + public void AddBufferElement(World world, Entity entity, GameObject gameObject, ushort taskOffset) + { + if (m_InterruptionSource == null || m_InterruptionSource.Index < 0) { + Debug.LogError("Error: An Interruption Source task must be specified within the OnInterrupt node."); + return; + } + + DynamicBuffer buffer; + if (world.EntityManager.HasBuffer(entity)) { + buffer = world.EntityManager.GetBuffer(entity); + } else { + buffer = world.EntityManager.AddBuffer(entity); + } + buffer.Add(new OnInterruptEventComponent() { + ConnectedIndex = (ushort)(m_ConnectedIndex - taskOffset), + InterruptionSourceIndex = m_InterruptionSource.RuntimeIndex, + }); + + var interruptSystemGroup = world.GetOrCreateSystemManaged(); + interruptSystemGroup.AddSystemToUpdateList(world.GetOrCreateSystem()); + } + + /// + /// Clears the IBufferElementData from the entity. + /// + /// The world that the entity exists in. + /// The entity that the IBufferElementData should be cleared from. + public void ClearBufferElement(World world, Entity entity) + { + DynamicBuffer buffer; + if (world.EntityManager.HasBuffer(entity)) { + buffer = world.EntityManager.GetBuffer(entity); + buffer.Clear(); + } + } + } + + /// + /// The DOTS data structure for the OnInterrupt class. + /// + public struct OnInterruptEventComponent : IBufferElementData + { + [Tooltip("The index of the ILogicNode that the IEventNode is connected to.")] + public ushort ConnectedIndex; + [Tooltip("The index of the node that can invoke the interrupt.")] + public ushort InterruptionSourceIndex; + } + + /// + /// Processes any interrupts. + /// + [DisableAutoCreation] + public partial struct OnInterruptSystem : ISystem + { + /// + /// Updates the logic. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + { + foreach (var (branchComponents, taskComponents, onInterruptEvents, entity) in + SystemAPI.Query, DynamicBuffer, DynamicBuffer>().WithAll().WithEntityAccess()) { + for (int i = 0; i < branchComponents.Length; ++i) { + var branchComponent = branchComponents[i]; + if (branchComponent.InterruptType != InterruptType.None) { + // The branch is going to cause an interrupt. + for (int j = 0; j < onInterruptEvents.Length; ++j) { + var onInterruptEvent = onInterruptEvents[j]; + if (branchComponent.ActiveIndex >= onInterruptEvent.InterruptionSourceIndex && + branchComponent.ActiveIndex < taskComponents[onInterruptEvent.InterruptionSourceIndex].SiblingIndex) { + // Trigger the callback. + var startTask = taskComponents[onInterruptEvent.ConnectedIndex]; + if (startTask.Status != TaskStatus.Queued && startTask.Status != TaskStatus.Running) { + startTask.Status = TaskStatus.Queued; + var taskComponentsBuffer = taskComponents; + taskComponentsBuffer[onInterruptEvent.ConnectedIndex] = startTask; + + var activeTag = taskComponents[onInterruptEvent.ConnectedIndex].FlagComponentType; + state.EntityManager.SetComponentEnabled(entity, activeTag, true); + + var connectedBranchIndex = taskComponents[onInterruptEvent.ConnectedIndex].BranchIndex; + branchComponent = branchComponents[connectedBranchIndex]; + branchComponent.ActiveIndex = branchComponent.NextIndex = onInterruptEvent.ConnectedIndex; + branchComponent.ActiveFlagComponentType = activeTag; + var branchComponentsBuffer = branchComponents; + branchComponentsBuffer[connectedBranchIndex] = branchComponent; + } + } + } + } + } + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnInterrupt.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnInterrupt.cs.meta new file mode 100644 index 0000000..290bfea --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnInterrupt.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 29da32620f380b34aa56ef14a1088104 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnReceivedEvent.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnReceivedEvent.cs new file mode 100644 index 0000000..f92ba4d --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnReceivedEvent.cs @@ -0,0 +1,167 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Events +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using Opsive.Shared.Events; + using UnityEngine; + + [AllowMultipleTypes] + [Opsive.Shared.Utility.Description("Invoked when the specified event is received.")] + public class OnReceivedEvent : EventNode + { + [Tooltip("The name of the event that starts the branch.")] + [SerializeField] protected SharedVariable m_EventName; + [Tooltip("Optionally store the first sent argument.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoredValue1; + [Tooltip("Optionally store the second sent argument.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoredValue2; + [Tooltip("Optionally store the third sent argument.")] + [RequireShared] [SerializeField] protected SharedVariable m_StoredValue3; + + private string m_RegisteredEventName; + private bool m_Initialized; + + /// + /// Initializes the node to the specified graph. + /// + /// The graph that is initializing the task. + public override void Initialize(IGraph graph) + { + if (m_Initialized) { + return; + } + m_Initialized = true; + + base.Initialize(graph); + + m_BehaviorTree.OnBehaviorTreeDestroyed += Destroy; + + m_EventName.OnValueChange += UpdateEvents; + if (m_StoredValue1 != null) { m_StoredValue1.OnValueChange += UpdateEvents; } + if (m_StoredValue2 != null) { m_StoredValue2.OnValueChange += UpdateEvents; } + if (m_StoredValue3 != null) { m_StoredValue3.OnValueChange += UpdateEvents; } + + RegisterEvents(); + } + + /// + /// Registers for the events. + /// + private void RegisterEvents() + { + if (m_StoredValue1 == null || !m_StoredValue1.IsShared) { + EventHandler.RegisterEvent(m_BehaviorTree, m_EventName.Value, ReceivedEvent); + } else { + if (m_StoredValue2 == null || !m_StoredValue2.IsShared) { + EventHandler.RegisterEvent(m_BehaviorTree, m_EventName.Value, ReceivedEvent); + } else { + if (m_StoredValue3 == null || !m_StoredValue3.IsShared) { + EventHandler.RegisterEvent(m_BehaviorTree, m_EventName.Value, ReceivedEvent); + } else { + EventHandler.RegisterEvent(m_BehaviorTree, m_EventName.Value, ReceivedEvent); + } + } + } + + m_RegisteredEventName = m_EventName.Value; + } + + /// + /// Unregisters for the events that were registered. + /// + private void UnregisterEvents() + { + // The events must be registered first in order to be unregistered. + if (string.IsNullOrEmpty(m_RegisteredEventName)) { + return; + } + + // Unregister from all parameters. This will ensure no events are subscribed if the parameters change. + EventHandler.UnregisterEvent(m_BehaviorTree, m_RegisteredEventName, ReceivedEvent); + EventHandler.UnregisterEvent(m_BehaviorTree, m_RegisteredEventName, ReceivedEvent); + EventHandler.UnregisterEvent(m_BehaviorTree, m_RegisteredEventName, ReceivedEvent); + EventHandler.UnregisterEvent(m_BehaviorTree, m_RegisteredEventName, ReceivedEvent); + + m_RegisteredEventName = string.Empty; + } + + /// + /// The event name or parameter count has changed. Update the events. + /// + private void UpdateEvents() + { + UnregisterEvents(); + RegisterEvents(); + } + + /// + /// The event has been received. + /// + private void ReceivedEvent() + { + m_BehaviorTree.StartBranch(this); + } + + /// + /// A single parameter event has been received. + /// + /// The first parameter. + private void ReceivedEvent(object arg1) + { + if (m_StoredValue1 != null && m_StoredValue1.IsShared) { m_StoredValue1.SetValue(arg1); } + + m_BehaviorTree.StartBranch(this); + } + + /// + /// A two parameter event has been received. + /// + /// The first parameter. + /// The second parameter. + private void ReceivedEvent(object arg1, object arg2) + { + if (m_StoredValue1 != null && m_StoredValue1.IsShared) { m_StoredValue1.SetValue(arg1); } + if (m_StoredValue2 != null && m_StoredValue2.IsShared) { m_StoredValue2.SetValue(arg2); } + + m_BehaviorTree.StartBranch(this); + } + + /// + /// A three parameter event has been received. + /// + /// The first parameter. + /// The second parameter. + /// The third parameter. + private void ReceivedEvent(object arg1, object arg2, object arg3) + { + if (m_StoredValue1 != null && m_StoredValue1.IsShared) { m_StoredValue1.SetValue(arg1); } + if (m_StoredValue2 != null && m_StoredValue2.IsShared) { m_StoredValue2.SetValue(arg2); } + if (m_StoredValue3 != null && m_StoredValue3.IsShared) { m_StoredValue3.SetValue(arg3); } + + m_BehaviorTree.StartBranch(this); + } + + /// + /// The behavior tree has been destroyed. + /// + private void Destroy() + { + m_BehaviorTree.OnBehaviorTreeDestroyed -= Destroy; + + m_EventName.OnValueChange -= UpdateEvents; + if (m_StoredValue1 != null) { m_StoredValue1.OnValueChange -= UpdateEvents; } + if (m_StoredValue2 != null) { m_StoredValue2.OnValueChange -= UpdateEvents; } + if (m_StoredValue3 != null) { m_StoredValue3.OnValueChange -= UpdateEvents; } + + UnregisterEvents(); + m_Initialized = false; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnReceivedEvent.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnReceivedEvent.cs.meta new file mode 100644 index 0000000..97cf5db --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnReceivedEvent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 08f3abf304431564faa9a446da5525be +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnTriggerEnter.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnTriggerEnter.cs new file mode 100644 index 0000000..5b47237 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnTriggerEnter.cs @@ -0,0 +1,60 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Events +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [AllowMultipleTypes] + [NodeIcon("06864c37115f11445b04701c616d0e14", "8b8a2793322238240b4f25171d772003")] + [Opsive.Shared.Utility.Description("Invoked when the agent enters a trigger.")] + public class OnTriggerEnter : EventNode + { + [Tooltip("The tag of the GameObject that the trigger should be checked against.")] + [SerializeField] protected SharedVariable m_Tag; + [Tooltip("The entered trigger GameObject.")] + [SerializeField] protected SharedVariable m_StoredOtherColliderGameObject; + + /// + /// Initializes the node to the specified graph. + /// + /// The graph that is initializing the task. + public override void Initialize(IGraph graph) + { + base.Initialize(graph); + + m_BehaviorTree.OnBehaviorTreeDestroyed += Destroy; + m_BehaviorTree.OnBehaviorTreeTriggerEnter += EnteredTrigger; + } + + /// + /// The agent has entered a trigger. + /// + /// The trigger that the agent entered. + private void EnteredTrigger(Collider other) + { + if (!string.IsNullOrEmpty(m_Tag.Value) && !other.gameObject.CompareTag(m_Tag.Value)) { + return; + } + + if (m_StoredOtherColliderGameObject != null && m_StoredOtherColliderGameObject.IsShared) { m_StoredOtherColliderGameObject.Value = other.gameObject; } + + m_BehaviorTree.StartBranch(this); + } + + /// + /// The behavior tree has been destroyed. + /// + private void Destroy() + { + m_BehaviorTree.OnBehaviorTreeDestroyed -= Destroy; + m_BehaviorTree.OnBehaviorTreeTriggerEnter -= EnteredTrigger; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnTriggerEnter.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnTriggerEnter.cs.meta new file mode 100644 index 0000000..d8045b1 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnTriggerEnter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fedf6996bd7cfba4395c582ba40e2b47 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnTriggerEnter2D.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnTriggerEnter2D.cs new file mode 100644 index 0000000..f0b0a70 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnTriggerEnter2D.cs @@ -0,0 +1,60 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Events +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [AllowMultipleTypes] + [NodeIcon("06864c37115f11445b04701c616d0e14", "8b8a2793322238240b4f25171d772003")] + [Opsive.Shared.Utility.Description("Invoked when the agent enters a 2D trigger.")] + public class OnTriggerEnter2D : EventNode + { + [Tooltip("The tag of the GameObject that the trigger should be checked against.")] + [SerializeField] protected SharedVariable m_Tag; + [Tooltip("The entered trigger GameObject.")] + [SerializeField] protected SharedVariable m_StoredOtherColliderGameObject; + + /// + /// Initializes the node to the specified graph. + /// + /// The graph that is initializing the task. + public override void Initialize(IGraph graph) + { + base.Initialize(graph); + + m_BehaviorTree.OnBehaviorTreeDestroyed += Destroy; + m_BehaviorTree.OnBehaviorTreeTriggerEnter2D += EnteredTrigger2D; + } + + /// + /// The agent has entered a 2D trigger. + /// + /// The trigger that the agent entered. + private void EnteredTrigger2D(Collider2D other) + { + if (!string.IsNullOrEmpty(m_Tag.Value) && !other.gameObject.CompareTag(m_Tag.Value)) { + return; + } + + if (m_StoredOtherColliderGameObject != null && m_StoredOtherColliderGameObject.IsShared) { m_StoredOtherColliderGameObject.Value = other.gameObject; } + + m_BehaviorTree.StartBranch(this); + } + + /// + /// The behavior tree has been destroyed. + /// + private void Destroy() + { + m_BehaviorTree.OnBehaviorTreeDestroyed -= Destroy; + m_BehaviorTree.OnBehaviorTreeTriggerEnter2D -= EnteredTrigger2D; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnTriggerEnter2D.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnTriggerEnter2D.cs.meta new file mode 100644 index 0000000..5ca6b73 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnTriggerEnter2D.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1d33b9315f8977947bcb04bd9eced13e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnTriggerExit.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnTriggerExit.cs new file mode 100644 index 0000000..db4fbae --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnTriggerExit.cs @@ -0,0 +1,60 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Events +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [AllowMultipleTypes] + [NodeIcon("06864c37115f11445b04701c616d0e14", "8b8a2793322238240b4f25171d772003")] + [Opsive.Shared.Utility.Description("Invoked when the agent exits a trigger.")] + public class OnTriggerExit : EventNode + { + [Tooltip("The tag of the GameObject that the trigger should be checked against.")] + [SerializeField] protected SharedVariable m_Tag; + [Tooltip("The exited trigger GameObject.")] + [SerializeField] protected SharedVariable m_StoredOtherColliderGameObject; + + /// + /// Initializes the node to the specified graph. + /// + /// The graph that is initializing the task. + public override void Initialize(IGraph graph) + { + base.Initialize(graph); + + m_BehaviorTree.OnBehaviorTreeDestroyed += Destroy; + m_BehaviorTree.OnBehaviorTreeTriggerExit += ExitedTrigger; + } + + /// + /// The agent has exited a trigger. + /// + /// The trigger that the agent exited. + private void ExitedTrigger(Collider other) + { + if (!string.IsNullOrEmpty(m_Tag.Value) && !other.gameObject.CompareTag(m_Tag.Value)) { + return; + } + + if (m_StoredOtherColliderGameObject != null && m_StoredOtherColliderGameObject.IsShared) { m_StoredOtherColliderGameObject.Value = other.gameObject; } + + m_BehaviorTree.StartBranch(this); + } + + /// + /// The behavior tree has been destroyed. + /// + private void Destroy() + { + m_BehaviorTree.OnBehaviorTreeDestroyed -= Destroy; + m_BehaviorTree.OnBehaviorTreeTriggerExit -= ExitedTrigger; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnTriggerExit.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnTriggerExit.cs.meta new file mode 100644 index 0000000..58d4ef4 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnTriggerExit.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ee0ed271175ff684c8999ca1427a3f43 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnTriggerExit2D.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnTriggerExit2D.cs new file mode 100644 index 0000000..366604a --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnTriggerExit2D.cs @@ -0,0 +1,60 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Events +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using UnityEngine; + + [AllowMultipleTypes] + [NodeIcon("06864c37115f11445b04701c616d0e14", "8b8a2793322238240b4f25171d772003")] + [Opsive.Shared.Utility.Description("Invoked when the agent exits a 2D trigger.")] + public class OnTriggerExit2D : EventNode + { + [Tooltip("The tag of the GameObject that the trigger should be checked against.")] + [SerializeField] protected SharedVariable m_Tag; + [Tooltip("The exited trigger GameObject.")] + [SerializeField] protected SharedVariable m_StoredOtherColliderGameObject; + + /// + /// Initializes the node to the specified graph. + /// + /// The graph that is initializing the task. + public override void Initialize(IGraph graph) + { + base.Initialize(graph); + + m_BehaviorTree.OnBehaviorTreeDestroyed += Destroy; + m_BehaviorTree.OnBehaviorTreeTriggerExit2D += ExitedTrigger2D; + } + + /// + /// The agent has exited a 2D trigger. + /// + /// The trigger that the agent exited. + private void ExitedTrigger2D(Collider2D other) + { + if (!string.IsNullOrEmpty(m_Tag.Value) && !other.gameObject.CompareTag(m_Tag.Value)) { + return; + } + + if (m_StoredOtherColliderGameObject != null && m_StoredOtherColliderGameObject.IsShared) { m_StoredOtherColliderGameObject.Value = other.gameObject; } + + m_BehaviorTree.StartBranch(this); + } + + /// + /// The behavior tree has been destroyed. + /// + private void Destroy() + { + m_BehaviorTree.OnBehaviorTreeDestroyed -= Destroy; + m_BehaviorTree.OnBehaviorTreeTriggerExit2D -= ExitedTrigger2D; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnTriggerExit2D.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnTriggerExit2D.cs.meta new file mode 100644 index 0000000..5f51139 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/OnTriggerExit2D.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: da04e1db385cc9d4ba72bccc9450531c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/Start.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/Start.cs new file mode 100644 index 0000000..693169a --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/Start.cs @@ -0,0 +1,24 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks.Events +{ + using Opsive.GraphDesigner.Runtime; + using UnityEngine; + + /// + /// The EventNode that is invoked when the behavior tree starts. + /// + [NodeIcon("8c35407905159694e8b83df15d3b039b", "df820d6e71423194188c7dcb1c1ae2e2")] + public class Start : IEventNode + { + [Tooltip("The index of the ITreeLogicNode that the IEventNode is connected to. ushort.MaxValue indicates no connection.")] + [SerializeField] protected ushort m_ConnectedIndex; + + public ushort ConnectedIndex { get => m_ConnectedIndex; set => m_ConnectedIndex = value; } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/Start.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/Start.cs.meta new file mode 100644 index 0000000..86749e5 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Events/Start.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a59ed1fcf4540d54fbc57ff4e2a3fe04 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/ISubtreeReference.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/ISubtreeReference.cs new file mode 100644 index 0000000..1cf90f3 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/ISubtreeReference.cs @@ -0,0 +1,34 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + + /// + /// Interface for tasks that can load subtrees. + /// + public interface ISubtreeReference + { + /// + /// A list of mapped SharedVariables. These variables can override the subtree. + /// + SharedVariableOverride[] SharedVariableOverrides { get; set; } + + /// + /// Performs any runtime operations to evaluate the array of subtrees that should be returned. + /// + /// The component that the node is attached to. + void EvaluateSubtrees(IGraphComponent graphComponent); + + /// + /// The Subtrees that should be used at runtime. + /// + Subtree[] Subtrees { get; } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/ISubtreeReference.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/ISubtreeReference.cs.meta new file mode 100644 index 0000000..63289de --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/ISubtreeReference.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 831e8b55811df1749b0416880fc74492 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/PlaceholderTasks.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/PlaceholderTasks.cs new file mode 100644 index 0000000..cbdea11 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/PlaceholderTasks.cs @@ -0,0 +1,71 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks +{ + using Opsive.BehaviorDesigner.Runtime.Tasks.Actions; + using Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals; + using Opsive.BehaviorDesigner.Runtime.Tasks.Composites; + using Opsive.BehaviorDesigner.Runtime.Tasks.Decorators; + using Opsive.GraphDesigner.Runtime; + using Opsive.Shared.Utility; + using UnityEngine; + + [HideInFilterWindow] + [Opsive.Shared.Utility.Description("A temporary placeholder node that represents an action node being created from a template. This node will be replaced with the actual action node after Unity has finished compiling the generated script.")] + public class PlaceholderActionNode : ActionNode, IPlaceholderNode + { + [Tooltip("The type name of the target task that will replace this placeholder.")] + [SerializeField] [HideInInspector] private string m_TargetType; + public string TargetType { get => m_TargetType; set => m_TargetType = value; } + } + + [HideInFilterWindow] + [Opsive.Shared.Utility.Description("A temporary placeholder node that represents a conditional node being created from a template. This node will be replaced with the actual conditional node after Unity has finished compiling the generated script.")] + public class PlaceholderConditionalNode : ConditionalNode, IPlaceholderNode + { + [Tooltip("The type name of the target task that will replace this placeholder.")] + [SerializeField] [HideInInspector] private string m_TargetType; + public string TargetType { get => m_TargetType; set => m_TargetType = value; } + } + + [HideInFilterWindow] + [Opsive.Shared.Utility.Description("A temporary placeholder task that represents an action task being created from a template. This task will be replaced with the actual action task after Unity has finished compiling the generated script.")] + public class PlaceholderAction : Action, IPlaceholderNode + { + [Tooltip("The type name of the target task that will replace this placeholder.")] + [SerializeField] [HideInInspector] private string m_TargetType; + public string TargetType { get => m_TargetType; set => m_TargetType = value; } + } + + [HideInFilterWindow] + [Opsive.Shared.Utility.Description("A temporary placeholder node that represents a composite node being created from a template. This node will be replaced with the actual composite node after Unity has finished compiling the generated script.")] + public class PlaceholderCompositeNode : CompositeNode, IPlaceholderNode + { + [Tooltip("The type name of the target task that will replace this placeholder.")] + [SerializeField] [HideInInspector] private string m_TargetType; + public string TargetType { get => m_TargetType; set => m_TargetType = value; } + } + + [HideInFilterWindow] + [Opsive.Shared.Utility.Description("A temporary placeholder task that represents a conditional task being created from a template. This task will be replaced with the actual conditional task after Unity has finished compiling the generated script.")] + public class PlaceholderConditional : Conditional, IPlaceholderNode + { + [Tooltip("The type name of the target task that will replace this placeholder.")] + [SerializeField] [HideInInspector] private string m_TargetType; + public string TargetType { get => m_TargetType; set => m_TargetType = value; } + } + + [HideInFilterWindow] + [Opsive.Shared.Utility.Description("A temporary placeholder node that represents a decorator node being created from a template. This node will be replaced with the actual decorator node after Unity has finished compiling the generated script.")] + public class PlaceholderDecoratorNode : DecoratorNode, IPlaceholderNode + { + [Tooltip("The type name of the target task that will replace this placeholder.")] + [SerializeField] [HideInInspector] private string m_TargetType; + public string TargetType { get => m_TargetType; set => m_TargetType = value; } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/PlaceholderTasks.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/PlaceholderTasks.cs.meta new file mode 100644 index 0000000..04e3a73 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/PlaceholderTasks.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 55f5ed5135933ae499f48deb2efdbb9e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/StackedTask.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/StackedTask.cs new file mode 100644 index 0000000..10e6093 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/StackedTask.cs @@ -0,0 +1,407 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks +{ + using Opsive.BehaviorDesigner.Runtime; + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using Opsive.Shared.Utility; + using System; + using System.Collections.Generic; + using Unity.Entities; + using UnityEngine; + using static Opsive.BehaviorDesigner.Runtime.BehaviorTreeData; + + /// + /// The StackedTask task allows for multiple tasks to be added to a single node. + /// + [HideInFilterWindow] + [NodeIcon("e0a8f1df788b6274a9a24003859dfa7e")] + public abstract class StackedTask : Task, ITreeLogicNode, IContainerNode + { + [Tooltip("The index of the node.")] + [SerializeField] ushort m_Index; + [Tooltip("The parent index of the node. ushort.MaxValue indicates no parent.")] + [SerializeField] ushort m_ParentIndex; + [Tooltip("The sibling index of the node. ushort.MaxValue indicates no sibling.")] + [SerializeField] ushort m_SiblingIndex; + + public ushort Index { get => m_Index; set => m_Index = value; } + public ushort ParentIndex { get => m_ParentIndex; set => m_ParentIndex = value; } + public ushort SiblingIndex { get => m_SiblingIndex; set => m_SiblingIndex = value; } + public ushort RuntimeIndex { get; set; } + + /// + /// Specifies how the tasks should be compared. + /// + public enum ComparisonType + { + Sequence, // AND. + Selector // OR. + } + + [Tooltip("The tasks that should run.")] + [SerializeField] protected Task[] m_Tasks; + [Tooltip("Specifies if the tasks should be traversed with an AND (Sequence) or an OR (Selector).")] + [SerializeField] protected ComparisonType m_ComparisonType; + + private ushort m_ActiveIndex; + private bool[] m_TaskStarted; + private bool[] m_TaskEnded; + + public ushort ActiveIndex { get => m_ActiveIndex; } + public object[] Nodes { get => m_Tasks; } + public Task[] Tasks { get => m_Tasks; set => m_Tasks = value; } + + /// + /// Adds the object to the action array. + /// + /// The object that should be added. + public void Add(object obj) + { + Task task; + if (obj is System.Reflection.MethodInfo) { + // A delegate action needs to be created. + var methodInfo = obj as System.Reflection.MethodInfo; + var parameters = methodInfo.GetParameters(); + var types = new Type[(parameters != null ? parameters.Length : 0) + ((methodInfo.ReturnType != typeof(void)) ? 1 : 0)]; + if (parameters != null) { + for (int i = 0; i < parameters.Length; ++i) { + types[i] = parameters[i].ParameterType; + } + } + + Type baseType; + if (methodInfo.ReturnType == typeof(void)) { + if (parameters != null && parameters.Length > 0) { + if (parameters.Length == 1) { baseType = typeof(TaskDelegate<>); } + else if (parameters.Length == 2) { baseType = typeof(TaskDelegate<,>); } + else if (parameters.Length == 3) { baseType = typeof(TaskDelegate<,,>); } + else if (parameters.Length == 4) { baseType = typeof(TaskDelegate<,,,>); } + else if (parameters.Length == 5) { baseType = typeof(TaskDelegate<,,,,>); } + else if (parameters.Length == 6) { baseType = typeof(TaskDelegate<,,,,,>); } + else if (parameters.Length == 7) { baseType = typeof(TaskDelegate<,,,,,,>); } + else if (parameters.Length == 8) { baseType = typeof(TaskDelegate<,,,,,,,>); } + else if (parameters.Length == 9) { baseType = typeof(TaskDelegate<,,,,,,,,>); } + else if (parameters.Length == 10) { baseType = typeof(TaskDelegate<,,,,,,,,,>); } + else { Debug.LogError($"Error: Unable to create TaskDelegate with {parameters.Length}. Please send this error to support@opsive.com."); return; } + } else { + baseType = typeof(TaskDelegate); + } + } else { + // The method has a returned parameter. + types[types.Length - 1] = methodInfo.ReturnType; + if (parameters != null && parameters.Length > 0) { + if (parameters.Length == 1) { baseType = typeof(TaskValueDelegate<,>); } + else if (parameters.Length == 2) { baseType = typeof(TaskValueDelegate<,,>); } + else if (parameters.Length == 3) { baseType = typeof(TaskValueDelegate<,,,>); } + else if (parameters.Length == 4) { baseType = typeof(TaskValueDelegate<,,,,>); } + else if (parameters.Length == 5) { baseType = typeof(TaskValueDelegate<,,,,,>); } + else if (parameters.Length == 6) { baseType = typeof(TaskValueDelegate<,,,,,,>); } + else if (parameters.Length == 7) { baseType = typeof(TaskValueDelegate<,,,,,,,>); } + else if (parameters.Length == 8) { baseType = typeof(TaskValueDelegate<,,,,,,,,>); } + else if (parameters.Length == 9) { baseType = typeof(TaskValueDelegate<,,,,,,,,,>); } + else if (parameters.Length == 10) { baseType = typeof(TaskValueDelegate<,,,,,,,,,>); } + else { Debug.LogError($"Error: Unable to create TaskValueDelegate with {parameters.Length}. Please send this error to support@opsive.com."); return; } + } else { + baseType = typeof(TaskValueDelegate<>); + } + } + + Type actionDelegateType; + if (types.Length > 0) { + actionDelegateType = baseType.MakeGenericType(types); + } else { + actionDelegateType = baseType; + } + + // The Action Delegate needs to be initialized to the method. + var actionDelegate = Activator.CreateInstance(actionDelegateType) as TaskDelegateBase; + actionDelegate.Bind(methodInfo); + + task = actionDelegate; + } else if (obj is Type) { + task = Activator.CreateInstance((Type)obj) as Task; + } else { // Task. + task = obj as Task; + } + + task.Reset(); + + if (m_Tasks == null) { + m_Tasks = new Task[] { task }; + } else { + Array.Resize(ref m_Tasks, m_Tasks.Length + 1); + m_Tasks[m_Tasks.Length - 1] = task; + } + } + + /// + /// Removes the action at the specified index. + /// + /// The index of the action that should be removed. + public void Remove(int index) + { + if (index < 0 || index >= m_Tasks.Length) { + return; + } + + m_Tasks[index].OnDestroy(); + for (int i = index; i < m_Tasks.Length - 1; ++i) { + m_Tasks[i] = m_Tasks[i + 1]; + } + Array.Resize(ref m_Tasks, m_Tasks.Length - 1); + } + + /// + /// Resets the task values back to their default. + /// + public override void Reset() + { + if (m_Tasks == null) { + return; + } + + for (int i = 0; i < m_Tasks.Length; ++i) { + m_Tasks[i].Reset(); + } + } + + /// + /// Initializes the base task parameters. + /// + /// A reference to the owning BehaviorTree. + /// The runtime index of the node. + internal override void Initialize(BehaviorTree behaviorTree, ushort runtimeIndex) + { + if (m_Tasks != null) { + m_TaskStarted = new bool[m_Tasks.Length]; + m_TaskEnded = new bool[m_Tasks.Length]; + for (int i = 0; i < m_Tasks.Length; ++i) { + if (m_Tasks[i] == null) { + m_Tasks[i] = new UnknownTask(); + } + if (m_Tasks[i] is TaskDelegateBase taskDelegate) { + taskDelegate.Initialize(behaviorTree, runtimeIndex, this is IConditional); + } else { + m_Tasks[i].Initialize(behaviorTree, runtimeIndex); + } + } + } + + base.Initialize(behaviorTree, runtimeIndex); + } + + /// + /// Called when the task is started. + /// + public override void OnStart() + { + if (m_Tasks == null) { + return; + } + + for (int i = 0; i < m_Tasks.Length; ++i) { + if (m_Tasks[i] == null) { + continue; + } + + m_TaskStarted[i] = false; + m_TaskEnded[i] = false; + } + } + + /// + /// Updates all of the child tasks. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + if (m_Tasks == null || m_Tasks.Length == 0) { + return TaskStatus.Failure; + } + + while (m_ActiveIndex < m_Tasks.Length) { + // Call start when the local task is started, not when the StackedTask starts. + if (!m_TaskStarted[m_ActiveIndex]) { + m_Tasks[m_ActiveIndex].OnStart(); + m_TaskStarted[m_ActiveIndex] = true; + } + + var executionStatus = m_Tasks[m_ActiveIndex].OnUpdate(); + if (executionStatus == TaskStatus.Running) { + return TaskStatus.Running; + } + + if (m_ComparisonType == ComparisonType.Sequence && executionStatus == TaskStatus.Failure) { + return TaskStatus.Failure; + } else if (m_ComparisonType == ComparisonType.Selector && executionStatus == TaskStatus.Success) { + return TaskStatus.Success; + } + + if (!m_TaskEnded[m_ActiveIndex]) { + m_Tasks[m_ActiveIndex].OnEnd(); + m_TaskEnded[m_ActiveIndex] = true; + } + m_ActiveIndex++; + } + + return m_ComparisonType == ComparisonType.Sequence ? TaskStatus.Success : TaskStatus.Failure; + } + + /// + /// Called when the task stops. + /// + public override void OnEnd() + { + if (m_TaskEnded == null) { + return; + } + + for (int i = 0; i < m_Tasks.Length; ++i) { + if (m_Tasks[i] == null) { + continue; + } + if (!m_TaskEnded[i]) { + m_Tasks[i].OnEnd(); + } + + m_TaskStarted[i] = false; + m_TaskEnded[i] = false; + } + m_ActiveIndex = 0; + } + + /// + /// Specifies the type of reflection that should be used to save the task. + /// + /// The index of the sub-task. This is used for the task set allowing each contained task to have their own save type. + public override MemberVisibility GetSaveReflectionType(int index) { return index < 0 || index >= m_Tasks.Length ? MemberVisibility.None : m_Tasks[index].GetSaveReflectionType(index); } + + /// + /// Returns the current task state. + /// + /// The DOTS world. + /// The DOTS entity. + /// The current task state. + public override object Save(World world, Entity entity) + { + if (m_Tasks == null) { + return null; + } + + var saveData = new object[m_Tasks.Length + 1]; + for (int i = 0; i < m_Tasks.Length; ++i) { + if (m_Tasks[i] == null) { + continue; + } + var reflectionType = m_Tasks[i].GetSaveReflectionType(i); + if (reflectionType != MemberVisibility.None) { + saveData[i] = Serialization.Serialize(m_Tasks[i], reflectionType, BehaviorTreeData.ValidateSerializedObject); + } else { + saveData[i] = m_Tasks[i].Save(world, entity); + } + } + saveData[m_Tasks.Length] = m_ActiveIndex; + + return saveData; + } + + /// + /// Loads the previous task state. + /// + /// The previous task state. + /// The DOTS world. + /// The DOTS entity. + /// A reference to the map between the VariableAssignment and SharedVariable. + /// A reference to the list of task references that need to be resolved later. + public override void Load(object saveData, World world, Entity entity, Dictionary variableByNameMap, + ref ResizableArray taskReferences) + { + if (m_Tasks == null || saveData == null) { + return; + } + + var taskData = (object[])saveData; + if (taskData.Length != m_Tasks.Length + 1) { + Debug.LogError("Error: The save data does not match the task data length."); + return; + } + + for (int i = 0; i < m_Tasks.Length; ++i) { + if (taskData[i] == null) { + continue; + } + + Load(m_Tasks[i], i, taskData[i], world, entity, variableByNameMap, ref taskReferences); + } + m_ActiveIndex = (ushort)taskData[m_Tasks.Length]; + } + + /// + /// Loads the previous task state. + /// + /// The task that the saveData belongs to. + /// The index of the task within the Tasks array. + /// The previous task state. + /// The DOTS world. + /// The DOTS entity. + /// A reference to the map between the VariableAssignment and SharedVariable. + /// A reference to the list of task references that need to be resolved later. + protected virtual void Load(Task task, int index, object saveData, World world, Entity entity, + Dictionary variableByNameMap, ref ResizableArray taskReferences) + { + var reflectionType = task.GetSaveReflectionType(index); + if (reflectionType != MemberVisibility.None) { + var localTaskReferences = taskReferences; + (saveData as Serialization).DeserializeFields(task, reflectionType, BehaviorTreeData.ValidateDeserializedTypeObject, + (object fieldInfoObj, object task, object value) => + { + return BehaviorTreeData.ValidateDeserializedObject(fieldInfoObj, task, value, ref variableByNameMap, ref localTaskReferences); + }); + taskReferences = localTaskReferences; + } else { + task.Load(saveData, world, entity, variableByNameMap, ref taskReferences); + } + } + + /// + /// Callback when OnDrawGizmos is triggered. + /// + protected override void OnDrawGizmos() + { + if (m_Tasks == null) { + return; + } + + for (int i = 0; i < m_Tasks.Length; ++i) { + if (m_Tasks[i] == null) { + continue; + } + m_Tasks[i].OnDrawGizmos(m_BehaviorTree); + } + } + + /// + /// Callback when OnDrawGizmosSelected is triggered. + /// + protected override void OnDrawGizmosSelected() + { + if (m_Tasks == null) { + return; + } + + for (int i = 0; i < m_Tasks.Length; ++i) { + if (m_Tasks[i] == null) { + continue; + } + m_Tasks[i].OnDrawGizmosSelected(m_BehaviorTree); + } + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/StackedTask.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/StackedTask.cs.meta new file mode 100644 index 0000000..daf5e5e --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/StackedTask.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f7e3a1fa96850394ab09c7ebf309b0ed +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Task.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Task.cs new file mode 100644 index 0000000..7e49501 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Task.cs @@ -0,0 +1,371 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks +{ + using Opsive.BehaviorDesigner.Runtime.Systems; + using Opsive.GraphDesigner.Runtime.Variables; + using Opsive.Shared.Utility; + using System.Collections.Generic; + using Unity.Entities; + using UnityEngine; + using static Opsive.BehaviorDesigner.Runtime.BehaviorTreeData; + + /// + /// The base class for a GameObject task. + /// + public abstract class Task : ISavableTask + { + protected GameObject m_GameObject; + protected Transform m_Transform; + protected BehaviorTree m_BehaviorTree; + protected ushort m_RuntimeIndex; + + protected virtual GameObject gameObject { get => m_GameObject; } + protected virtual Transform transform { get => m_Transform; } + + private TaskStatus m_Status; + internal TaskStatus Status { get => m_Status; set => m_Status = value; } + + /// + /// Adds the task to the behavior tree buffer. + /// + /// The world that the task runs in. + /// The entity that the task is connected to. + /// The ID of the behavior tree running the task. + /// The index of the task. + public virtual void AddBufferElement(World world, Entity entity, int behaviorTreeID, ushort index) + { + DynamicBuffer buffer; + if (world.EntityManager.HasBuffer(entity)) { + buffer = world.EntityManager.GetBuffer(entity); + } else { + buffer = world.EntityManager.AddBuffer(entity); + } + buffer.Add(new TaskObjectComponent() + { + Index = index, + }); + } + + /// + /// Clears all component buffers from the behavior tree buffer. + /// + /// The world that the task runs in. + /// The entity that the task is connected to. + public virtual void ClearBufferElement(World world, Entity entity) + { + DynamicBuffer buffer; + if (world.EntityManager.HasBuffer(entity)) { + buffer = world.EntityManager.GetBuffer(entity); + buffer.Clear(); + } + } + + /// + /// Resets the task values back to their default. + /// + public virtual void Reset() { } + + /// + /// Initializes the base task parameters. + /// + /// A reference to the owning BehaviorTree. + /// The runtime index of the node. + internal virtual void Initialize(BehaviorTree behaviorTree, ushort runtimeIndex) + { + if (!Application.isPlaying) { + return; + } + + m_BehaviorTree = behaviorTree; + m_GameObject = m_BehaviorTree.gameObject; + m_Transform = m_BehaviorTree.transform; + m_RuntimeIndex = runtimeIndex; + + m_BehaviorTree.OnBehaviorTreeStarted += OnBehaviorTreeStarted; + m_BehaviorTree.OnBehaviorTreeStopped += OnBehaviorTreeStopped; + m_BehaviorTree.OnBehaviorTreeDestroyed += OnDestroy; + if (ReceiveCollisionEnterCallback) { m_BehaviorTree.OnBehaviorTreeCollisionEnter += OnCollisionEnter; } + if (ReceiveCollisionExitCallback) { m_BehaviorTree.OnBehaviorTreeCollisionExit += OnCollisionExit; } + if (ReceiveCollisionEnter2DCallback) { m_BehaviorTree.OnBehaviorTreeCollisionEnter2D += OnCollisionEnter2D; } + if (ReceiveCollisionExit2DCallback) { m_BehaviorTree.OnBehaviorTreeCollisionExit2D += OnCollisionExit2D; } + if (ReceiveTriggerEnterCallback) { m_BehaviorTree.OnBehaviorTreeTriggerEnter += OnTriggerEnter; } + if (ReceiveTriggerExitCallback) { m_BehaviorTree.OnBehaviorTreeTriggerExit += OnTriggerExit; } + if (ReceiveTriggerEnter2DCallback) { m_BehaviorTree.OnBehaviorTreeTriggerEnter2D += OnTriggerEnter2D; } + if (ReceiveTriggerExit2DCallback) { m_BehaviorTree.OnBehaviorTreeTriggerExit2D += OnTriggerExit2D; } + if (ReceiveControllerColliderHitCallback) { m_BehaviorTree.OnBehaviorTreeControllerColliderHit += OnControllerColliderHit; } + + OnAwake(); + } + + /// + /// Callback when the behavior tree is initialized. + /// + public virtual void OnAwake() { } + + /// + /// Callback when the behavior tree is started. + /// + public virtual void OnBehaviorTreeStarted() { } + + /// + /// Callback when the behavior tree is started. + /// + [System.Obsolete("Task.OnStarted has been deprecated. Use Task.OnBehaviorTreeStarted instead.")] + public virtual void OnStarted() { } + + /// + /// Callback when the task is started. + /// + public virtual void OnStart() { } + + /// + /// Executes the task logic. Returns a TaskStatus indicating how the behavior tree flow should proceed. + /// + /// The status of the task. + public virtual TaskStatus OnUpdate() { return TaskStatus.Success; } + + /// + /// Callback when the task stops. + /// + public virtual void OnEnd() { } + + /// + /// Calls Unity's GetComponent method. + /// + /// The retrieved component (can be null). + protected T GetComponent() + { + return gameObject.GetComponent(); + } + + /// + /// Calls Unity's GetComponent method. + /// + /// The component type that should be retrieved. + /// The retrieved component (can be null). + protected Component GetComponent(System.Type type) + { + return gameObject.GetComponent(type); + } + + /// + /// Calls Unity's TryGetComponent method. + /// + /// The type of component that should be retireved. + /// The retrieved component. + protected void TryGetComponent(out T component) where T : Component + { + gameObject.TryGetComponent(out component); + } + + /// + /// Calls Unity's TryGetComponent method. + /// + /// The type of component to get. + /// The retrieved component. + protected void TryGetComponent(System.Type type, out Component component) + { + gameObject.TryGetComponent(type, out component); + } + protected void StartCoroutine(string methodName) { m_BehaviorTree.StartTaskCoroutine(this, methodName); } + protected Coroutine StartCoroutine(System.Collections.IEnumerator routine) { return m_BehaviorTree.StartCoroutine(routine); } + protected Coroutine StartCoroutine(string methodName, object value) { return m_BehaviorTree.StartTaskCoroutine(this, methodName, value); } + protected void StopCoroutine(string methodName) { m_BehaviorTree.StopTaskCoroutine(methodName); } + protected void StopCoroutine(System.Collections.IEnumerator routine) { m_BehaviorTree.StopCoroutine(routine); } + protected void StopAllCoroutines() { m_BehaviorTree.StopAllTaskCoroutines(); } + + protected virtual bool ReceiveCollisionEnterCallback => false; + /// + /// Callback when OnCollisionEnter is triggered. This callback will only be received when ReceiveCollisionEnterCallback is true. + /// + /// The resulting collision. + protected virtual void OnCollisionEnter(Collision collision) { } + + protected virtual bool ReceiveCollisionExitCallback => false; + /// + /// Callback when OnCollisionExit is triggered. This callback will only be received when ReceiveCollisionExitCallback is true. + /// + /// The resulting collision. + protected virtual void OnCollisionExit(Collision collision) { } + + protected virtual bool ReceiveCollisionEnter2DCallback => false; + /// + /// Callback when OnCollisionEnter2D is triggered. This callback will only be received when ReceiveCollisionEnter2DCallback is true. + /// + /// The resulting collision. + protected virtual void OnCollisionEnter2D(Collision2D collision) { } + + protected virtual bool ReceiveCollisionExit2DCallback => false; + /// + /// Callback when OnCollisionExit2D is triggered. This callback will only be received when ReceiveCollisionExit2DCallback is true. + /// + /// The resulting collision. + protected virtual void OnCollisionExit2D(Collision2D collision) { } + + protected virtual bool ReceiveTriggerEnterCallback => false; + /// + /// Callback when OnTriggerEnter is triggered. This callback will only be received when ReceiveTriggerEnterCallback is true. + /// + /// The overlapping collider. + protected virtual void OnTriggerEnter(Collider other) { } + + protected virtual bool ReceiveTriggerExitCallback => false; + /// + /// Callback when OnTriggerExit is triggered. This callback will only be received when ReceiveTriggerExitCallback is true. + /// + /// The overlapping collider. + protected virtual void OnTriggerExit(Collider other) { } + + protected virtual bool ReceiveTriggerEnter2DCallback => false; + /// + /// Callback when OnTriggerEnter2D is triggered. This callback will only be received when ReceiveTriggerEnter2DCallback is true. + /// + /// The overlapping collider. + protected virtual void OnTriggerEnter2D(Collider2D other) { } + + protected virtual bool ReceiveTriggerExit2DCallback => false; + /// + /// Callback when OnTriggerExit2D is triggered. This callback will only be received when ReceiveTriggerExit2DCallback is true. + /// + /// The overlapping collider. + protected virtual void OnTriggerExit2D(Collider2D other) { } + + protected virtual bool ReceiveControllerColliderHitCallback => false; + /// + /// Callback when OnControllerColliderHit is triggered. This callback will only be received when ReceiveControllerColliderHitCallback is true. + /// + /// The hit result. + protected virtual void OnControllerColliderHit(ControllerColliderHit hit) { } + + /// + /// Editor method which will draw the gizmos. + /// + /// A reference to the behavior tree component. + internal void OnDrawGizmos(BehaviorTree behaviorTree) + { + if (m_BehaviorTree == null) { + m_BehaviorTree = behaviorTree; + m_Transform = behaviorTree.transform; + m_GameObject = behaviorTree.gameObject; + } + + OnDrawGizmos(); + } + + /// + /// Callback when OnDrawGizmos is triggered. + /// + + protected virtual void OnDrawGizmos() { } + + /// + /// Editor method which will draw the selected gizmos. + /// + /// A reference to the behavior tree component. + internal void OnDrawGizmosSelected(BehaviorTree behaviorTree) + { + if (m_BehaviorTree == null) { + m_BehaviorTree = behaviorTree; + m_Transform = behaviorTree.transform; + m_GameObject = behaviorTree.gameObject; + } + + OnDrawGizmosSelected(); + } + + /// + /// Callback when OnDrawGizmosSelected is triggered. + /// + protected virtual void OnDrawGizmosSelected() { } + + /// + /// Callback when the behavior tree is stopped. + /// + /// Is the behavior tree paused? + public virtual void OnBehaviorTreeStopped(bool paused) { } + + /// + /// Callback when the behavior tree is stopped. + /// + /// Is the behavior tree paused? + [System.Obsolete("Task.OnStopped has been deprecated. Use Task.OnBehaviorTreeStopped instead.")] + public virtual void OnStopped(bool paused) { } + + /// + /// Callback when the behavior tree is destroyed. + /// + public virtual void OnDestroy() + { + if (m_BehaviorTree == null) { + return; + } + + m_BehaviorTree.OnBehaviorTreeStarted -= OnBehaviorTreeStarted; + m_BehaviorTree.OnBehaviorTreeStopped -= OnBehaviorTreeStopped; + m_BehaviorTree.OnBehaviorTreeDestroyed -= OnDestroy; + if (ReceiveCollisionEnterCallback) { m_BehaviorTree.OnBehaviorTreeCollisionEnter -= OnCollisionEnter; } + if (ReceiveCollisionExitCallback) { m_BehaviorTree.OnBehaviorTreeCollisionExit -= OnCollisionExit; } + if (ReceiveCollisionEnter2DCallback) { m_BehaviorTree.OnBehaviorTreeCollisionEnter2D -= OnCollisionEnter2D; } + if (ReceiveCollisionExit2DCallback) { m_BehaviorTree.OnBehaviorTreeCollisionExit2D -= OnCollisionExit2D; } + if (ReceiveTriggerEnterCallback) { m_BehaviorTree.OnBehaviorTreeTriggerEnter -= OnTriggerEnter; } + if (ReceiveTriggerExitCallback) { m_BehaviorTree.OnBehaviorTreeTriggerExit -= OnTriggerExit; } + if (ReceiveTriggerEnter2DCallback) { m_BehaviorTree.OnBehaviorTreeTriggerEnter2D -= OnTriggerEnter2D; } + if (ReceiveTriggerExit2DCallback) { m_BehaviorTree.OnBehaviorTreeTriggerExit2D -= OnTriggerExit2D; } + if (ReceiveControllerColliderHitCallback) { m_BehaviorTree.OnBehaviorTreeControllerColliderHit -= OnControllerColliderHit; } + } + + /// + /// Overrides ToString providing a nicer string value of the task. + /// + /// The overloaded ToString value. + public override string ToString() + { + return GetType().Name; + } + + /// + /// Specifies the type of reflection that should be used to save the task. + /// + /// The index of the sub-task. This is used for the task set allowing each contained task to have their own save type. + public virtual MemberVisibility GetSaveReflectionType(int index) { return MemberVisibility.Public; } + + /// + /// Returns the current task state. + /// + /// The DOTS world. + /// The DOTS entity. + /// The current task state. + public virtual object Save(World world, Entity entity) + { + return null; + } + + /// + /// Loads the previous task state. + /// + /// The previous task state. + /// The DOTS world. + /// The DOTS entity. + public virtual void Load(object saveData, World world, Entity entity) { } + + /// + /// Loads the previous task state. + /// + /// The previous task state. + /// The DOTS world. + /// The DOTS entity. + /// A reference to the map between the VariableAssignment and SharedVariable. + /// A reference to the list of task references that need to be resolved later. + public virtual void Load(object saveData, World world, Entity entity, Dictionary variableByNameMap, + ref ResizableArray taskReferences) + { + Load(saveData, world, entity); + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Task.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Task.cs.meta new file mode 100644 index 0000000..dc9c35f --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Task.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8ddfd58bb4de183448b245f6fb314fbe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/TaskCoroutine.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/TaskCoroutine.cs new file mode 100644 index 0000000..f0b131e --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/TaskCoroutine.cs @@ -0,0 +1,63 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime +{ + using UnityEngine; + using System.Collections; + + /// + /// A wrapper for the coroutine object in order to add support for coroutines within Tasks. + /// + public class TaskCoroutine + { + private BehaviorTree m_BehaviorTree; + + private IEnumerator m_CoroutineEnumerator; + private Coroutine m_Coroutine; + private string m_Name; + private bool m_Stop; + + public Coroutine Coroutine { get => m_Coroutine; } + + /// + /// Initializes and starts a coroutine. + /// + /// The BehaviorTree that the coroutine has been added to. + /// A reference to the coroutine. + /// The name of the coroutine. + public TaskCoroutine(BehaviorTree behaviorTree, IEnumerator coroutine, string name) + { + m_BehaviorTree = behaviorTree; + m_CoroutineEnumerator = coroutine; + m_Name = name; + + m_Coroutine = m_BehaviorTree.StartCoroutine(RunCoroutine()); + } + + /// + /// Runs the coroutine until it is complete or has been stopped. + /// + /// The active coroutine. + public IEnumerator RunCoroutine() + { + while (!m_Stop) { + if (m_CoroutineEnumerator != null && m_CoroutineEnumerator.MoveNext()) { + yield return m_CoroutineEnumerator.Current; + } else { + break; + } + } + m_BehaviorTree.TaskCoroutineEnded(this, m_Name); + } + + /// + /// Stops the coroutine. + /// + public void Stop() { m_Stop = true; } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/TaskCoroutine.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/TaskCoroutine.cs.meta new file mode 100644 index 0000000..9a39aab --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/TaskCoroutine.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5fcbd45134954664fb7f14527343dfae +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/TaskDelegateBase.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/TaskDelegateBase.cs new file mode 100644 index 0000000..25983ec --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/TaskDelegateBase.cs @@ -0,0 +1,1259 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks +{ + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using Opsive.Shared.Utility; + using System; + using System.Reflection; + using UnityEngine; + + /// + /// The TaskDelegateBase task is an abstract class used for any action classes that use reflection to execute the action. + /// + [HideInFilterWindow] + public abstract class TaskDelegateBase : Task, IAction + { + [Tooltip("The object that the delegate belongs to. Can be null for static variables.")] + [SerializeField] [HideInInspector] protected SharedVariable m_Target; + [Tooltip("The type of delegate that should be created.")] + [SerializeField] [HideInInspector] protected string m_ReflectedType; + [Tooltip("The type of parameters that the delegate uses.")] + [SerializeField] [HideInInspector] protected string[] m_ParameterTypes; + [Tooltip("The name of the method that should be called by the delegate.")] + [SerializeField] [HideInInspector] protected string m_MethodName; + + public SharedVariable Target => m_Target; + public string ReflectedType => m_ReflectedType; + public string[] ParameterTypes => m_ParameterTypes; + public string MethodName => m_MethodName; + + protected bool m_ConditionalTask; + + /// + /// Binds the task to the specified method. + /// + /// The MethodInfo to bind the task to. + internal void Bind(MethodInfo methodInfo) + { + m_ReflectedType = methodInfo.ReflectedType.FullName; + var parameters = methodInfo.GetParameters(); + if (parameters != null && parameters.Length > 0) { + m_ParameterTypes = new string[parameters.Length]; + for (int i = 0; i < parameters.Length; ++i) { + m_ParameterTypes[i] = parameters[i].ParameterType.FullName; + } + } + m_MethodName = methodInfo.Name; + } + + /// + /// Initializes the task. + /// + /// A reference to the owning BehaviorTree. + /// Does the delegate belong to an IConditional task? + /// The runtime index of the node. + internal void Initialize(BehaviorTree behaviorTree, ushort runtimeIndex, bool conditionalTask) + { + m_ConditionalTask = conditionalTask; + + base.Initialize(behaviorTree, runtimeIndex); + } + + /// + /// Callback when the behavior tree is initialized. + /// + public override void OnAwake() + { + base.OnAwake(); + + CreateDelegate(); + if (m_Target != null) { + m_Target.OnValueChange += CreateDelegate; + } + } + + /// + /// Creates the task delegate. + /// + protected virtual void CreateDelegate() { } + + /// + /// Returns the target value. + /// + /// The target value. + protected object GetTargetValue() + { + // The target will be null if no SharedVariable value has been assigned. + var target = m_Target.GetValue(); + if (target == null) { + var targetType = m_ReflectedType.Replace("UnityEngine.", string.Empty); + if (string.Equals(targetType, "GameObject")) { + return m_GameObject; + } + var value = m_GameObject.GetComponent(targetType); + if (value == null) { + var splitType = m_ReflectedType.Split("."); + value = m_GameObject.GetComponent(splitType[splitType.Length - 1]); + if (value == null) { + Debug.LogError($"Error: Unable to find the component {m_ReflectedType} on the {m_GameObject.name} GameObject."); + } + } + return value; + } + return target; + } + + /// + /// Returns the method from the given type and name. + /// + /// The object type that the method belongs to. + /// The name of the method. + /// The types of parameters that the method uses. + /// The method from the given type and name. + protected static MethodInfo GetMethod(string reflectedType, string methodName, string[] parameterTypeNames) + { + var type = TypeUtility.GetType(reflectedType); + if (type == null) { + Debug.LogError($"Error: Unable to find the type {reflectedType}."); + return null; + } + + Type[] parameterTypes; + if (parameterTypeNames != null) { + parameterTypes = new Type[parameterTypeNames.Length]; + for (int i = 0; i < parameterTypeNames.Length; ++i) { + parameterTypes[i] = TypeUtility.GetType(parameterTypeNames[i]); + if (parameterTypes[i] == null) { + Debug.LogError($"Error: Unable to find the parameter type {parameterTypeNames[i]}."); + return null; + } + } + } else { + parameterTypes = new Type[0]; + } + + // Get the method based on the type and parameter types. + var method = type.GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static, null, parameterTypes, null); + if (method == null) { + Debug.LogError($"Error: Unable to find the method {methodName} on type {type}. If you are using code stripping you can prevent Unity from stripping the " + + $"method with a link.xml file: https://docs.unity3d.com/6000.1/Documentation/Manual/managed-code-stripping-xml-formatting.html"); + return null; + } + + return method; + } + + /// + /// Specifies the type of reflection that should be used to save the task. + /// + /// The index of the sub-task. This is used for the task set allowing each contained task to have their own save type. + public override MemberVisibility GetSaveReflectionType(int index) + { + return MemberVisibility.Public; + } + + /// + /// Returns a friendly name for the task. + /// + /// A friendly name for the task. + public override string ToString() + { + return m_MethodName; + } + } + + /// + /// Task which executes a delegate with no parameters. + /// + [NodeIcon("3bbdfa553da4d554e9d74f8d88915aac", "6437308e972f99f48953f20198fd4e94")] + public class TaskDelegate : TaskDelegateBase + { + private Action m_Delegate; + + /// + /// Creates the task delegate. + /// + protected override void CreateDelegate() + { + var method = GetMethod(m_ReflectedType, m_MethodName, m_ParameterTypes); + if (method == null) { + return; + } + + if (method.IsStatic) { + m_Delegate = method.CreateDelegate(typeof(System.Action)) as System.Action; + } else { + m_Delegate = method.CreateDelegate(typeof(System.Action), GetTargetValue()) as System.Action; + } + } + + /// + /// Invokes the delegate. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + m_Delegate(); + return TaskStatus.Success; + } + } + + /// + /// Task which executes a delegate with no parameters but a returned value. + /// + [NodeIcon("3bbdfa553da4d554e9d74f8d88915aac", "6437308e972f99f48953f20198fd4e94")] + public class TaskValueDelegate : TaskDelegateBase + { + [Tooltip("The returned result.")] + [SerializeField] [RequireShared] protected SharedVariable m_Result; + + private Func m_Delegate; + + /// + /// Creates the task delegate. + /// + protected override void CreateDelegate() + { + var method = GetMethod(m_ReflectedType, m_MethodName, m_ParameterTypes); + if (method == null) { + return; + } + + if (method.IsStatic) { + m_Delegate = method.CreateDelegate(typeof(Func)) as Func; + } else { + m_Delegate = method.CreateDelegate(typeof(Func), GetTargetValue()) as Func; + } + } + + /// + /// Invokes the delegate. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + m_Result.Value = m_Delegate(); + if (m_ConditionalTask) { + return Convert.ToBoolean(m_Result.Value) ? TaskStatus.Success : TaskStatus.Failure; + } + return TaskStatus.Success; + } + } + + /// + /// Task which executes a delegate with one parameter. + /// + [NodeIcon("3bbdfa553da4d554e9d74f8d88915aac", "6437308e972f99f48953f20198fd4e94")] + public class TaskDelegate : TaskDelegateBase + { + [Tooltip("The first parameter.")] + [SerializeField] protected SharedVariable m_Parameter1; + + private Action m_Delegate; + + /// + /// Creates the task delegate. + /// + protected override void CreateDelegate() + { + var method = GetMethod(m_ReflectedType, m_MethodName, m_ParameterTypes); + if (method == null) { + return; + } + + if (method.IsStatic) { + m_Delegate = method.CreateDelegate(typeof(Action)) as Action; + } else { + m_Delegate = method.CreateDelegate(typeof(Action), GetTargetValue()) as Action; + } + } + + /// + /// Invokes the delegate. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + m_Delegate(m_Parameter1.Value); + return TaskStatus.Success; + } + } + + /// + /// Task which executes a delegate with one parameter and a returned value. + /// + [NodeIcon("3bbdfa553da4d554e9d74f8d88915aac", "6437308e972f99f48953f20198fd4e94")] + public class TaskValueDelegate : TaskDelegateBase + { + [Tooltip("The first parameter.")] + [SerializeField] protected SharedVariable m_Parameter1; + [Tooltip("The returned result.")] + [SerializeField] [RequireShared] protected SharedVariable m_Result; + + private Func m_Delegate; + + /// + /// Creates the task delegate. + /// + protected override void CreateDelegate() + { + var method = GetMethod(m_ReflectedType, m_MethodName, m_ParameterTypes); + if (method == null) { + return; + } + + if (method.IsStatic) { + m_Delegate = method.CreateDelegate(typeof(Func)) as Func; + } else { + m_Delegate = method.CreateDelegate(typeof(Func), GetTargetValue()) as Func; + } + } + + /// + /// Invokes the delegate. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + m_Result.Value = m_Delegate(m_Parameter1.Value); + if (m_ConditionalTask) { + return Convert.ToBoolean(m_Result.Value) ? TaskStatus.Success : TaskStatus.Failure; + } + return TaskStatus.Success; + } + } + + /// + /// Task which executes a delegate with two parameters. + /// + [NodeIcon("3bbdfa553da4d554e9d74f8d88915aac", "6437308e972f99f48953f20198fd4e94")] + public class TaskDelegate : TaskDelegateBase + { + [Tooltip("The first parameter.")] + [SerializeField] protected SharedVariable m_Parameter1; + [Tooltip("The second parameter.")] + [SerializeField] protected SharedVariable m_Parameter2; + + private Action m_Delegate; + + /// + /// Creates the task delegate. + /// + protected override void CreateDelegate() + { + var method = GetMethod(m_ReflectedType, m_MethodName, m_ParameterTypes); + if (method == null) { + return; + } + + if (method.IsStatic) { + m_Delegate = method.CreateDelegate(typeof(Action)) as Action; + } else { + m_Delegate = method.CreateDelegate(typeof(Action), GetTargetValue()) as Action; + } + } + + /// + /// Invokes the delegate. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + m_Delegate(m_Parameter1.Value, m_Parameter2.Value); + return TaskStatus.Success; + } + } + + /// + /// Task which executes a delegate with two parameters and a returned value. + /// + [NodeIcon("3bbdfa553da4d554e9d74f8d88915aac", "6437308e972f99f48953f20198fd4e94")] + public class TaskValueDelegate : TaskDelegateBase + { + [Tooltip("The first parameter.")] + [SerializeField] protected SharedVariable m_Parameter1; + [Tooltip("The second parameter.")] + [SerializeField] protected SharedVariable m_Parameter2; + [Tooltip("The returned result.")] + [SerializeField] [RequireShared] protected SharedVariable m_Result; + + private Func m_Delegate; + + /// + /// Creates the task delegate. + /// + protected override void CreateDelegate() + { + var method = GetMethod(m_ReflectedType, m_MethodName, m_ParameterTypes); + if (method == null) { + return; + } + + if (method.IsStatic) { + m_Delegate = method.CreateDelegate(typeof(Func)) as Func; + } else { + m_Delegate = method.CreateDelegate(typeof(Func), GetTargetValue()) as Func; + } + } + + /// + /// Invokes the delegate. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + m_Result.Value = m_Delegate(m_Parameter1.Value, m_Parameter2.Value); + if (m_ConditionalTask) { + return Convert.ToBoolean(m_Result.Value) ? TaskStatus.Success : TaskStatus.Failure; + } + return TaskStatus.Success; + } + } + + /// + /// Task which executes a delegate with three parameters. + /// + [NodeIcon("3bbdfa553da4d554e9d74f8d88915aac", "6437308e972f99f48953f20198fd4e94")] + public class TaskDelegate : TaskDelegateBase + { + [Tooltip("The first parameter.")] + [SerializeField] protected SharedVariable m_Parameter1; + [Tooltip("The second parameter.")] + [SerializeField] protected SharedVariable m_Parameter2; + [Tooltip("The third parameter.")] + [SerializeField] protected SharedVariable m_Parameter3; + + private Action m_Delegate; + + /// + /// Creates the task delegate. + /// + protected override void CreateDelegate() + { + var method = GetMethod(m_ReflectedType, m_MethodName, m_ParameterTypes); + if (method == null) { + return; + } + + if (method.IsStatic) { + m_Delegate = method.CreateDelegate(typeof(Action)) as Action; + } else { + m_Delegate = method.CreateDelegate(typeof(Action), GetTargetValue()) as Action; + } + } + + /// + /// Invokes the delegate. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + m_Delegate(m_Parameter1.Value, m_Parameter2.Value, m_Parameter3.Value); + return TaskStatus.Success; + } + } + + /// + /// Task which executes a delegate with three parameters and a returned value. + /// + [NodeIcon("3bbdfa553da4d554e9d74f8d88915aac", "6437308e972f99f48953f20198fd4e94")] + public class TaskValueDelegate : TaskDelegateBase + { + [Tooltip("The first parameter.")] + [SerializeField] protected SharedVariable m_Parameter1; + [Tooltip("The second parameter.")] + [SerializeField] protected SharedVariable m_Parameter2; + [Tooltip("The third parameter.")] + [SerializeField] protected SharedVariable m_Parameter3; + [Tooltip("The returned result.")] + [SerializeField] [RequireShared] protected SharedVariable m_Result; + + private Func m_Delegate; + + /// + /// Creates the task delegate. + /// + protected override void CreateDelegate() + { + var method = GetMethod(m_ReflectedType, m_MethodName, m_ParameterTypes); + if (method == null) { + return; + } + + if (method.IsStatic) { + m_Delegate = method.CreateDelegate(typeof(Func)) as Func; + } else { + m_Delegate = method.CreateDelegate(typeof(Func), GetTargetValue()) as Func; + } + } + + /// + /// Invokes the delegate. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + m_Result.Value = m_Delegate(m_Parameter1.Value, m_Parameter2.Value, m_Parameter3.Value); + if (m_ConditionalTask) { + return Convert.ToBoolean(m_Result.Value) ? TaskStatus.Success : TaskStatus.Failure; + } + return TaskStatus.Success; + } + } + + /// + /// Task which executes a delegate with four parameters. + /// + [NodeIcon("3bbdfa553da4d554e9d74f8d88915aac", "6437308e972f99f48953f20198fd4e94")] + public class TaskDelegate : TaskDelegateBase + { + [Tooltip("The first parameter.")] + [SerializeField] protected SharedVariable m_Parameter1; + [Tooltip("The second parameter.")] + [SerializeField] protected SharedVariable m_Parameter2; + [Tooltip("The third parameter.")] + [SerializeField] protected SharedVariable m_Parameter3; + [Tooltip("The fourth parameter.")] + [SerializeField] protected SharedVariable m_Parameter4; + + private Action m_Delegate; + + /// + /// Creates the task delegate. + /// + protected override void CreateDelegate() + { + var method = GetMethod(m_ReflectedType, m_MethodName, m_ParameterTypes); + if (method == null) { + return; + } + + if (method.IsStatic) { + m_Delegate = method.CreateDelegate(typeof(Action)) as Action; + } else { + m_Delegate = method.CreateDelegate(typeof(Action), GetTargetValue()) as Action; + } + } + + /// + /// Invokes the delegate. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + m_Delegate(m_Parameter1.Value, m_Parameter2.Value, m_Parameter3.Value, m_Parameter4.Value); + return TaskStatus.Success; + } + } + + /// + /// Task which executes a delegate with four parameters and a returned value. + /// + [NodeIcon("3bbdfa553da4d554e9d74f8d88915aac", "6437308e972f99f48953f20198fd4e94")] + public class TaskValueDelegate : TaskDelegateBase + { + [Tooltip("The first parameter.")] + [SerializeField] protected SharedVariable m_Parameter1; + [Tooltip("The second parameter.")] + [SerializeField] protected SharedVariable m_Parameter2; + [Tooltip("The third parameter.")] + [SerializeField] protected SharedVariable m_Parameter3; + [Tooltip("The fourth parameter.")] + [SerializeField] protected SharedVariable m_Parameter4; + [Tooltip("The returned result.")] + [SerializeField] [RequireShared] protected SharedVariable m_Result; + + private Func m_Delegate; + + /// + /// Creates the task delegate. + /// + protected override void CreateDelegate() + { + var method = GetMethod(m_ReflectedType, m_MethodName, m_ParameterTypes); + if (method == null) { + return; + } + + if (method.IsStatic) { + m_Delegate = method.CreateDelegate(typeof(Func)) as Func; + } else { + m_Delegate = method.CreateDelegate(typeof(Func), GetTargetValue()) as Func; + } + } + + /// + /// Invokes the delegate. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + m_Result.Value = m_Delegate(m_Parameter1.Value, m_Parameter2.Value, m_Parameter3.Value, m_Parameter4.Value); + if (m_ConditionalTask) { + return Convert.ToBoolean(m_Result.Value) ? TaskStatus.Success : TaskStatus.Failure; + } + return TaskStatus.Success; + } + } + + /// + /// Task which executes a delegate with five parameters. + /// + [NodeIcon("3bbdfa553da4d554e9d74f8d88915aac", "6437308e972f99f48953f20198fd4e94")] + public class TaskDelegate : TaskDelegateBase + { + [Tooltip("The first parameter.")] + [SerializeField] protected SharedVariable m_Parameter1; + [Tooltip("The second parameter.")] + [SerializeField] protected SharedVariable m_Parameter2; + [Tooltip("The third parameter.")] + [SerializeField] protected SharedVariable m_Parameter3; + [Tooltip("The fourth parameter.")] + [SerializeField] protected SharedVariable m_Parameter4; + [Tooltip("The fifth parameter.")] + [SerializeField] protected SharedVariable m_Parameter5; + + private Action m_Delegate; + + /// + /// Creates the task delegate. + /// + protected override void CreateDelegate() + { + var method = GetMethod(m_ReflectedType, m_MethodName, m_ParameterTypes); + if (method == null) { + return; + } + + if (method.IsStatic) { + m_Delegate = method.CreateDelegate(typeof(Action)) as Action; + } else { + m_Delegate = method.CreateDelegate(typeof(Action), GetTargetValue()) as Action; + } + } + + /// + /// Invokes the delegate. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + m_Delegate(m_Parameter1.Value, m_Parameter2.Value, m_Parameter3.Value, m_Parameter4.Value, m_Parameter5.Value); + return TaskStatus.Success; + } + } + + /// + /// Task which executes a delegate with five parameters and a returned value. + /// + [NodeIcon("3bbdfa553da4d554e9d74f8d88915aac", "6437308e972f99f48953f20198fd4e94")] + public class TaskValueDelegate : TaskDelegateBase + { + [Tooltip("The first parameter.")] + [SerializeField] protected SharedVariable m_Parameter1; + [Tooltip("The second parameter.")] + [SerializeField] protected SharedVariable m_Parameter2; + [Tooltip("The third parameter.")] + [SerializeField] protected SharedVariable m_Parameter3; + [Tooltip("The fourth parameter.")] + [SerializeField] protected SharedVariable m_Parameter4; + [Tooltip("The fifth parameter.")] + [SerializeField] protected SharedVariable m_Parameter5; + [Tooltip("The returned result.")] + [SerializeField] [RequireShared] protected SharedVariable m_Result; + + private Func m_Delegate; + + /// + /// Creates the task delegate. + /// + protected override void CreateDelegate() + { + var method = GetMethod(m_ReflectedType, m_MethodName, m_ParameterTypes); + if (method == null) { + return; + } + + if (method.IsStatic) { + m_Delegate = method.CreateDelegate(typeof(Func)) as Func; + } else { + m_Delegate = method.CreateDelegate(typeof(Func), GetTargetValue()) as Func; + } + } + + /// + /// Invokes the delegate. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + m_Result.Value = m_Delegate(m_Parameter1.Value, m_Parameter2.Value, m_Parameter3.Value, m_Parameter4.Value, m_Parameter5.Value); + if (m_ConditionalTask) { + return Convert.ToBoolean(m_Result.Value) ? TaskStatus.Success : TaskStatus.Failure; + } + return TaskStatus.Success; + } + } + + /// + /// Task which executes a delegate with six parameters. + /// + [NodeIcon("3bbdfa553da4d554e9d74f8d88915aac", "6437308e972f99f48953f20198fd4e94")] + public class TaskDelegate : TaskDelegateBase + { + [Tooltip("The first parameter.")] + [SerializeField] protected SharedVariable m_Parameter1; + [Tooltip("The second parameter.")] + [SerializeField] protected SharedVariable m_Parameter2; + [Tooltip("The third parameter.")] + [SerializeField] protected SharedVariable m_Parameter3; + [Tooltip("The fourth parameter.")] + [SerializeField] protected SharedVariable m_Parameter4; + [Tooltip("The fifth parameter.")] + [SerializeField] protected SharedVariable m_Parameter5; + [Tooltip("The sixth parameter.")] + [SerializeField] protected SharedVariable m_Parameter6; + + private Action m_Delegate; + + /// + /// Creates the task delegate. + /// + protected override void CreateDelegate() + { + var method = GetMethod(m_ReflectedType, m_MethodName, m_ParameterTypes); + if (method == null) { + return; + } + + if (method.IsStatic) { + m_Delegate = method.CreateDelegate(typeof(Action)) as Action; + } else { + m_Delegate = method.CreateDelegate(typeof(Action), GetTargetValue()) as Action; + } + } + + /// + /// Invokes the delegate. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + m_Delegate(m_Parameter1.Value, m_Parameter2.Value, m_Parameter3.Value, m_Parameter4.Value, m_Parameter5.Value, m_Parameter6.Value); + return TaskStatus.Success; + } + } + + /// + /// Task which executes a delegate with six parameters and a returned value. + /// + [NodeIcon("3bbdfa553da4d554e9d74f8d88915aac", "6437308e972f99f48953f20198fd4e94")] + public class TaskValueDelegate : TaskDelegateBase + { + [Tooltip("The first parameter.")] + [SerializeField] protected SharedVariable m_Parameter1; + [Tooltip("The second parameter.")] + [SerializeField] protected SharedVariable m_Parameter2; + [Tooltip("The third parameter.")] + [SerializeField] protected SharedVariable m_Parameter3; + [Tooltip("The fourth parameter.")] + [SerializeField] protected SharedVariable m_Parameter4; + [Tooltip("The fifth parameter.")] + [SerializeField] protected SharedVariable m_Parameter5; + [Tooltip("The sixth parameter.")] + [SerializeField] protected SharedVariable m_Parameter6; + [Tooltip("The returned result.")] + [SerializeField] [RequireShared] protected SharedVariable m_Result; + + private Func m_Delegate; + + /// + /// Creates the task delegate. + /// + protected override void CreateDelegate() + { + var method = GetMethod(m_ReflectedType, m_MethodName, m_ParameterTypes); + if (method == null) { + return; + } + + if (method.IsStatic) { + m_Delegate = method.CreateDelegate(typeof(Func)) as Func; + } else { + m_Delegate = method.CreateDelegate(typeof(Func), GetTargetValue()) as Func; + } + } + + /// + /// Invokes the delegate. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + m_Result.Value = m_Delegate(m_Parameter1.Value, m_Parameter2.Value, m_Parameter3.Value, m_Parameter4.Value, m_Parameter5.Value, m_Parameter6.Value); + if (m_ConditionalTask) { + return Convert.ToBoolean(m_Result.Value) ? TaskStatus.Success : TaskStatus.Failure; + } + return TaskStatus.Success; + } + } + + /// + /// Task which executes a delegate with seven parameters. + /// + [NodeIcon("3bbdfa553da4d554e9d74f8d88915aac", "6437308e972f99f48953f20198fd4e94")] + public class TaskDelegate : TaskDelegateBase + { + [Tooltip("The first parameter.")] + [SerializeField] protected SharedVariable m_Parameter1; + [Tooltip("The second parameter.")] + [SerializeField] protected SharedVariable m_Parameter2; + [Tooltip("The third parameter.")] + [SerializeField] protected SharedVariable m_Parameter3; + [Tooltip("The fourth parameter.")] + [SerializeField] protected SharedVariable m_Parameter4; + [Tooltip("The fifth parameter.")] + [SerializeField] protected SharedVariable m_Parameter5; + [Tooltip("The sixth parameter.")] + [SerializeField] protected SharedVariable m_Parameter6; + [Tooltip("The seventh parameter.")] + [SerializeField] protected SharedVariable m_Parameter7; + + private Action m_Delegate; + + /// + /// Creates the task delegate. + /// + protected override void CreateDelegate() + { + var method = GetMethod(m_ReflectedType, m_MethodName, m_ParameterTypes); + if (method == null) { + return; + } + + if (method.IsStatic) { + m_Delegate = method.CreateDelegate(typeof(Action)) as Action; + } else { + m_Delegate = method.CreateDelegate(typeof(Action), GetTargetValue()) as Action; + } + } + + /// + /// Invokes the delegate. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + m_Delegate(m_Parameter1.Value, m_Parameter2.Value, m_Parameter3.Value, m_Parameter4.Value, m_Parameter5.Value, m_Parameter6.Value, m_Parameter7.Value); + return TaskStatus.Success; + } + } + + /// + /// Task which executes a delegate with seven parameters and a returned value. + /// + [NodeIcon("3bbdfa553da4d554e9d74f8d88915aac", "6437308e972f99f48953f20198fd4e94")] + public class TaskValueDelegate : TaskDelegateBase + { + [Tooltip("The first parameter.")] + [SerializeField] protected SharedVariable m_Parameter1; + [Tooltip("The second parameter.")] + [SerializeField] protected SharedVariable m_Parameter2; + [Tooltip("The third parameter.")] + [SerializeField] protected SharedVariable m_Parameter3; + [Tooltip("The fourth parameter.")] + [SerializeField] protected SharedVariable m_Parameter4; + [Tooltip("The fifth parameter.")] + [SerializeField] protected SharedVariable m_Parameter5; + [Tooltip("The sixth parameter.")] + [SerializeField] protected SharedVariable m_Parameter6; + [Tooltip("The seventh parameter.")] + [SerializeField] protected SharedVariable m_Parameter7; + [Tooltip("The returned result.")] + [SerializeField] [RequireShared] protected SharedVariable m_Result; + + private Func m_Delegate; + + /// + /// Creates the task delegate. + /// + protected override void CreateDelegate() + { + var method = GetMethod(m_ReflectedType, m_MethodName, m_ParameterTypes); + if (method == null) { + return; + } + + if (method.IsStatic) { + m_Delegate = method.CreateDelegate(typeof(Func)) as Func; + } else { + m_Delegate = method.CreateDelegate(typeof(Func), GetTargetValue()) as Func; + } + } + + /// + /// Invokes the delegate. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + m_Result.Value = m_Delegate(m_Parameter1.Value, m_Parameter2.Value, m_Parameter3.Value, m_Parameter4.Value, m_Parameter5.Value, m_Parameter6.Value, m_Parameter7.Value); + if (m_ConditionalTask) { + return Convert.ToBoolean(m_Result.Value) ? TaskStatus.Success : TaskStatus.Failure; + } + return TaskStatus.Success; + } + } + + /// + /// Task which executes a delegate with eight parameters. + /// + [NodeIcon("3bbdfa553da4d554e9d74f8d88915aac", "6437308e972f99f48953f20198fd4e94")] + public class TaskDelegate : TaskDelegateBase + { + [Tooltip("The first parameter.")] + [SerializeField] protected SharedVariable m_Parameter1; + [Tooltip("The second parameter.")] + [SerializeField] protected SharedVariable m_Parameter2; + [Tooltip("The third parameter.")] + [SerializeField] protected SharedVariable m_Parameter3; + [Tooltip("The fourth parameter.")] + [SerializeField] protected SharedVariable m_Parameter4; + [Tooltip("The fifth parameter.")] + [SerializeField] protected SharedVariable m_Parameter5; + [Tooltip("The sixth parameter.")] + [SerializeField] protected SharedVariable m_Parameter6; + [Tooltip("The seventh parameter.")] + [SerializeField] protected SharedVariable m_Parameter7; + [Tooltip("The eigth parameter.")] + [SerializeField] protected SharedVariable m_Parameter8; + + private Action m_Delegate; + + /// + /// Creates the task delegate. + /// + protected override void CreateDelegate() + { + var method = GetMethod(m_ReflectedType, m_MethodName, m_ParameterTypes); + if (method == null) { + return; + } + + if (method.IsStatic) { + m_Delegate = method.CreateDelegate(typeof(Action)) as Action; + } else { + m_Delegate = method.CreateDelegate(typeof(Action), GetTargetValue()) as Action; + } + } + + /// + /// Invokes the delegate. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + m_Delegate(m_Parameter1.Value, m_Parameter2.Value, m_Parameter3.Value, m_Parameter4.Value, m_Parameter5.Value, m_Parameter6.Value, m_Parameter7.Value, m_Parameter8.Value); + return TaskStatus.Success; + } + } + + /// + /// Task which executes a delegate with eight parameters and a returned value. + /// + [NodeIcon("3bbdfa553da4d554e9d74f8d88915aac", "6437308e972f99f48953f20198fd4e94")] + public class TaskValueDelegate : TaskDelegateBase + { + [Tooltip("The first parameter.")] + [SerializeField] protected SharedVariable m_Parameter1; + [Tooltip("The second parameter.")] + [SerializeField] protected SharedVariable m_Parameter2; + [Tooltip("The third parameter.")] + [SerializeField] protected SharedVariable m_Parameter3; + [Tooltip("The fourth parameter.")] + [SerializeField] protected SharedVariable m_Parameter4; + [Tooltip("The fifth parameter.")] + [SerializeField] protected SharedVariable m_Parameter5; + [Tooltip("The sixth parameter.")] + [SerializeField] protected SharedVariable m_Parameter6; + [Tooltip("The seventh parameter.")] + [SerializeField] protected SharedVariable m_Parameter7; + [Tooltip("The eigth parameter.")] + [SerializeField] protected SharedVariable m_Parameter8; + [Tooltip("The returned result.")] + [SerializeField] [RequireShared] protected SharedVariable m_Result; + + private Func m_Delegate; + + /// + /// Creates the task delegate. + /// + protected override void CreateDelegate() + { + var method = GetMethod(m_ReflectedType, m_MethodName, m_ParameterTypes); + if (method == null) { + return; + } + + if (method.IsStatic) { + m_Delegate = method.CreateDelegate(typeof(Func)) as Func; + } else { + m_Delegate = method.CreateDelegate(typeof(Func), GetTargetValue()) as Func; + } + } + + /// + /// Invokes the delegate. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + m_Result.Value = m_Delegate(m_Parameter1.Value, m_Parameter2.Value, m_Parameter3.Value, m_Parameter4.Value, m_Parameter5.Value, m_Parameter6.Value, m_Parameter7.Value, m_Parameter8.Value); + if (m_ConditionalTask) { + return Convert.ToBoolean(m_Result.Value) ? TaskStatus.Success : TaskStatus.Failure; + } + return TaskStatus.Success; + } + } + + /// + /// Task which executes a delegate with nine parameters. + /// + [NodeIcon("3bbdfa553da4d554e9d74f8d88915aac", "6437308e972f99f48953f20198fd4e94")] + public class TaskDelegate : TaskDelegateBase + { + [Tooltip("The first parameter.")] + [SerializeField] protected SharedVariable m_Parameter1; + [Tooltip("The second parameter.")] + [SerializeField] protected SharedVariable m_Parameter2; + [Tooltip("The third parameter.")] + [SerializeField] protected SharedVariable m_Parameter3; + [Tooltip("The fourth parameter.")] + [SerializeField] protected SharedVariable m_Parameter4; + [Tooltip("The fifth parameter.")] + [SerializeField] protected SharedVariable m_Parameter5; + [Tooltip("The sixth parameter.")] + [SerializeField] protected SharedVariable m_Parameter6; + [Tooltip("The seventh parameter.")] + [SerializeField] protected SharedVariable m_Parameter7; + [Tooltip("The eigth parameter.")] + [SerializeField] protected SharedVariable m_Parameter8; + [Tooltip("The ninth parameter.")] + [SerializeField] protected SharedVariable m_Parameter9; + + private Action m_Delegate; + + /// + /// Creates the task delegate. + /// + protected override void CreateDelegate() + { + var method = GetMethod(m_ReflectedType, m_MethodName, m_ParameterTypes); + if (method == null) { + return; + } + + if (method.IsStatic) { + m_Delegate = method.CreateDelegate(typeof(Action)) as Action; + } else { + m_Delegate = method.CreateDelegate(typeof(Action), GetTargetValue()) as Action; + } + } + + /// + /// Invokes the delegate. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + m_Delegate(m_Parameter1.Value, m_Parameter2.Value, m_Parameter3.Value, m_Parameter4.Value, m_Parameter5.Value, m_Parameter6.Value, m_Parameter7.Value, m_Parameter8.Value, m_Parameter9.Value); + return TaskStatus.Success; + } + } + + /// + /// Task which executes a delegate with nine parameters and a returned value. + /// + [NodeIcon("3bbdfa553da4d554e9d74f8d88915aac", "6437308e972f99f48953f20198fd4e94")] + public class TaskValueDelegate : TaskDelegateBase + { + [Tooltip("The first parameter.")] + [SerializeField] protected SharedVariable m_Parameter1; + [Tooltip("The second parameter.")] + [SerializeField] protected SharedVariable m_Parameter2; + [Tooltip("The third parameter.")] + [SerializeField] protected SharedVariable m_Parameter3; + [Tooltip("The fourth parameter.")] + [SerializeField] protected SharedVariable m_Parameter4; + [Tooltip("The fifth parameter.")] + [SerializeField] protected SharedVariable m_Parameter5; + [Tooltip("The sixth parameter.")] + [SerializeField] protected SharedVariable m_Parameter6; + [Tooltip("The seventh parameter.")] + [SerializeField] protected SharedVariable m_Parameter7; + [Tooltip("The eigth parameter.")] + [SerializeField] protected SharedVariable m_Parameter8; + [Tooltip("The ninth parameter.")] + [SerializeField] protected SharedVariable m_Parameter9; + [Tooltip("The returned result.")] + [SerializeField] [RequireShared] protected SharedVariable m_Result; + + private Func m_Delegate; + + /// + /// Creates the task delegate. + /// + protected override void CreateDelegate() + { + var method = GetMethod(m_ReflectedType, m_MethodName, m_ParameterTypes); + if (method == null) { + return; + } + + if (method.IsStatic) { + m_Delegate = method.CreateDelegate(typeof(Func)) as Func; + } else { + m_Delegate = method.CreateDelegate(typeof(Func), GetTargetValue()) as Func; + } + } + + /// + /// Invokes the delegate. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + m_Result.Value = m_Delegate(m_Parameter1.Value, m_Parameter2.Value, m_Parameter3.Value, m_Parameter4.Value, m_Parameter5.Value, m_Parameter6.Value, m_Parameter7.Value, m_Parameter8.Value, m_Parameter9.Value); + if (m_ConditionalTask) { + return Convert.ToBoolean(m_Result.Value) ? TaskStatus.Success : TaskStatus.Failure; + } + return TaskStatus.Success; + } + } + + /// + /// Task which executes a delegate with ten parameters. + /// + [NodeIcon("3bbdfa553da4d554e9d74f8d88915aac", "6437308e972f99f48953f20198fd4e94")] + public class TaskDelegate : TaskDelegateBase + { + [Tooltip("The first parameter.")] + [SerializeField] protected SharedVariable m_Parameter1; + [Tooltip("The second parameter.")] + [SerializeField] protected SharedVariable m_Parameter2; + [Tooltip("The third parameter.")] + [SerializeField] protected SharedVariable m_Parameter3; + [Tooltip("The fourth parameter.")] + [SerializeField] protected SharedVariable m_Parameter4; + [Tooltip("The fifth parameter.")] + [SerializeField] protected SharedVariable m_Parameter5; + [Tooltip("The sixth parameter.")] + [SerializeField] protected SharedVariable m_Parameter6; + [Tooltip("The seventh parameter.")] + [SerializeField] protected SharedVariable m_Parameter7; + [Tooltip("The eigth parameter.")] + [SerializeField] protected SharedVariable m_Parameter8; + [Tooltip("The ninth parameter.")] + [SerializeField] protected SharedVariable m_Parameter9; + [Tooltip("The tenth parameter.")] + [SerializeField] protected SharedVariable m_Parameter10; + + private Action m_Delegate; + + /// + /// Creates the task delegate. + /// + protected override void CreateDelegate() + { + var method = GetMethod(m_ReflectedType, m_MethodName, m_ParameterTypes); + if (method == null) { + return; + } + + if (method.IsStatic) { + m_Delegate = method.CreateDelegate(typeof(Action)) as Action; + } else { + m_Delegate = method.CreateDelegate(typeof(Action), GetTargetValue()) as Action; + } + } + + /// + /// Invokes the delegate. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + m_Delegate(m_Parameter1.Value, m_Parameter2.Value, m_Parameter3.Value, m_Parameter4.Value, m_Parameter5.Value, m_Parameter6.Value, m_Parameter7.Value, m_Parameter8.Value, m_Parameter9.Value, m_Parameter10.Value); + return TaskStatus.Success; + } + } + + /// + /// Task which executes a delegate with ten parameters and a returned value. + /// + [NodeIcon("3bbdfa553da4d554e9d74f8d88915aac", "6437308e972f99f48953f20198fd4e94")] + public class TaskValueDelegate : TaskDelegateBase + { + [Tooltip("The first parameter.")] + [SerializeField] protected SharedVariable m_Parameter1; + [Tooltip("The second parameter.")] + [SerializeField] protected SharedVariable m_Parameter2; + [Tooltip("The third parameter.")] + [SerializeField] protected SharedVariable m_Parameter3; + [Tooltip("The fourth parameter.")] + [SerializeField] protected SharedVariable m_Parameter4; + [Tooltip("The fifth parameter.")] + [SerializeField] protected SharedVariable m_Parameter5; + [Tooltip("The sixth parameter.")] + [SerializeField] protected SharedVariable m_Parameter6; + [Tooltip("The seventh parameter.")] + [SerializeField] protected SharedVariable m_Parameter7; + [Tooltip("The eigth parameter.")] + [SerializeField] protected SharedVariable m_Parameter8; + [Tooltip("The ninth parameter.")] + [SerializeField] protected SharedVariable m_Parameter9; + [Tooltip("The tenth parameter.")] + [SerializeField] protected SharedVariable m_Parameter10; + [Tooltip("The returned result.")] + [SerializeField] [RequireShared] protected SharedVariable m_Result; + + private Func m_Delegate; + + /// + /// Creates the task delegate. + /// + protected override void CreateDelegate() + { + var method = GetMethod(m_ReflectedType, m_MethodName, m_ParameterTypes); + if (method == null) { + return; + } + + if (method.IsStatic) { + m_Delegate = method.CreateDelegate(typeof(Func)) as Func; + } else { + m_Delegate = method.CreateDelegate(typeof(Func), GetTargetValue()) as Func; + } + } + + /// + /// Invokes the delegate. + /// + /// The status of the task. + public override TaskStatus OnUpdate() + { + m_Result.Value = m_Delegate(m_Parameter1.Value, m_Parameter2.Value, m_Parameter3.Value, m_Parameter4.Value, m_Parameter5.Value, m_Parameter6.Value, m_Parameter7.Value, m_Parameter8.Value, m_Parameter9.Value, m_Parameter10.Value); + if (m_ConditionalTask) { + return Convert.ToBoolean(m_Result.Value) ? TaskStatus.Success : TaskStatus.Failure; + } + return TaskStatus.Success; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/TaskDelegateBase.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/TaskDelegateBase.cs.meta new file mode 100644 index 0000000..e7868a8 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/TaskDelegateBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f432dc82c1de72e4dbb4662cbee75a4b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/TaskInterfaces.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/TaskInterfaces.cs new file mode 100644 index 0000000..e8875f4 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/TaskInterfaces.cs @@ -0,0 +1,204 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks +{ + using Opsive.GraphDesigner.Runtime.Variables; + using Opsive.Shared.Utility; + using System.Collections.Generic; + using Unity.Entities; + using static Opsive.BehaviorDesigner.Runtime.BehaviorTreeData; + + /// + /// Interface for action tasks. + /// + [ReflectedType] + [DisplayName("Actions")] + public interface IAction { } + + /// + /// Interface for composite tasks. + /// + [DisplayName("Composites")] + public interface IComposite { } + + /// + /// Interface for conditional tasks. + /// + [ReflectedType(typeof(bool))] + [DisplayName("Conditionals")] + public interface IConditional { } + + /// + /// Interface for reference-based conditional tasks that can be reevaluated. + /// + public interface IConditionalReevaluation + { + /// + /// Reevaluates the task logic. Returns a TaskStatus indicating how the behavior tree flow should proceed. + /// + /// The status of the task during the reevaluation phase. + public TaskStatus OnReevaluateUpdate(); + } + + /// + /// Interface for decorator tasks. + /// + [DisplayName("Decorators")] + public interface IDecorator { } + + /// + /// Interface which specifies that the object is a task. + /// + public interface IAuthoringTask + { + /// + /// The type of flag that should be enabled when the task is running. + /// + public ComponentType Flag { get; } + + /// + /// The system type that the component uses. + /// + public System.Type SystemType { get; } + + /// + /// Adds the IBufferElementData to the entity. + /// + /// The world that the entity exists in. + /// The entity that the IBufferElementData should be assigned to. + /// The GameObject that the entity is attached to. + /// The index of the element within the buffer. + public int AddBufferElement(World world, Entity entity, UnityEngine.GameObject gameObject); + + /// + /// Clears the IBufferElementData from the entity. + /// + /// The world that the entity exists in. + /// The entity that the IBufferElementData should be cleared from. + public void ClearBufferElement(World world, Entity entity); + } + + /// + /// Interface which specifies the IComponentData is a task. + /// + public interface ITaskComponentData + { + /// + /// The type of tag that should be enabled when the task is running. + /// + [System.Obsolete("ITaskComponentData.Tag is deprecated. It has been replaced with IAuthoringTask.Flag.")] + public ComponentType Tag { get; } + + /// + /// The system type that the component uses. + /// + public System.Type SystemType { get; } + + /// + /// Adds the IBufferElementData to the entity. + /// + /// The world that the entity exists in. + /// The entity that the IBufferElementData should be assigned to. + /// The GameObject that the entity is attached to. + /// The index of the element within the buffer. + public int AddBufferElement(World world, Entity entity, UnityEngine.GameObject gameObject); + + /// + /// Clears the IBufferElementData from the entity. + /// + /// The world that the entity exists in. + /// The entity that the IBufferElementData should be cleared from. + public void ClearBufferElement(World world, Entity entity); + } + + /// + /// Interface describing tasks that can be reevaluated. + /// + public interface IReevaluateResponder + { + /// + /// The type of flag that should be enabled when the task is being reevaluated. + /// + public ComponentType ReevaluateFlag { get; } + + /// + /// The system type that the reevaluation component uses. + /// + public System.Type ReevaluateSystemType { get; } + } + + /// + /// Interface describing tasks that can respond to interruptions. + /// + public interface IInterruptResponder + { + /// + /// The system type that the interrupt component uses. + /// + public System.Type InterruptSystemType { get; } + } + + /// + /// Represents a task that can be saved and restored later. + /// + public interface ISavableTask + { + /// + /// Specifies the type of reflection that should be used to save the task. + /// + /// The index of the sub-task. This is used for the task set allowing each contained task to have their own save type. + public MemberVisibility GetSaveReflectionType(int index); + + /// + /// Returns the current task state. + /// + /// The DOTS world. + /// The DOTS entity. + /// The current task state. + public object Save(World world, Entity entity) { return null; } + + /// + /// Loads the previous task state. + /// + /// The previous task state. + /// The DOTS world. + /// The DOTS entity. + public void Load(object saveData, World world, Entity entity) { } + + /// + /// Loads the previous task state. + /// + /// The previous task state. + /// The DOTS world. + /// The DOTS entity. + /// A reference to the map between the VariableAssignment and SharedVariable. + /// A reference to the list of task references that need to be resolved later. + public void Load(object saveData, World world, Entity entity, Dictionary variableByNameMap, + ref ResizableArray taskReferences) { Load(saveData, world, entity); } + } + + /// + /// Represents a task that can be paused and resumed later. + /// + public interface IPausableTask + { + /// + /// The task has been paused. + /// + /// The DOTS world. + /// The DOTS entity. + public void Pause(World world, Entity entity); + + /// + /// The task has been resumed. + /// + /// The DOTS world. + /// The DOTS entity. + public void Resume(World world, Entity entity); + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/TaskInterfaces.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/TaskInterfaces.cs.meta new file mode 100644 index 0000000..3a3dae8 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/TaskInterfaces.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8ec88a004de82ad4d9307c474fd1e828 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/TaskStatus.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/TaskStatus.cs new file mode 100644 index 0000000..2325452 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/TaskStatus.cs @@ -0,0 +1,19 @@ +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks +{ + /// + /// The execution status of the task. + /// + public enum TaskStatus : byte + { + Inactive, // The task is inactive and is not running. + Queued, // The task will run on the next update. + Running, // The task is currently running. + Success, // The task succeeded execution. + Failure, // The task failed execution. + } +} \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/TaskStatus.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/TaskStatus.cs.meta new file mode 100644 index 0000000..08aa71b --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/TaskStatus.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3b2fb3205262cd24c95aac6d0665a689 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Templates.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Templates.meta new file mode 100644 index 0000000..a7508f3 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Templates.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6f3fa88d23176d7409b82d946f3929b4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Templates/ECSNodes.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Templates/ECSNodes.cs new file mode 100644 index 0000000..86ebe1e --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Templates/ECSNodes.cs @@ -0,0 +1,541 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime +{ + using Opsive.BehaviorDesigner.Runtime.Tasks; + using Opsive.GraphDesigner.Runtime; + using Opsive.Shared.Utility; + using System; + + /// + /// Helper class for ECS node templates. + /// + public static class ECSNodeUtility + { + /// + /// Converts a name to camelCase format. + /// + /// The name to convert. + /// The name in camelCase format. + public static string ToCamelCase(string name) + { + if (string.IsNullOrEmpty(name)) + return name; + + return char.ToLowerInvariant(name[0]) + name.Substring(1); + } + } + + /// + /// Template for creating a custom action node. + /// + [Category("ECS")] + [DisplayName("Action")] + [Description("Create a new ECS action node.")] + public class ECSActionNode : INodeTemplate + { + public Type BaseType => typeof(IAction); + public bool IsLogicNode => true; + + /// + /// Returns the script that should be used for the template file. + /// + /// The name of the node. + /// The node script. + public string GetScript(string name) + { + var variableName = ECSNodeUtility.ToCamelCase(name); + return $@"using Opsive.BehaviorDesigner.Runtime.Components; +using Opsive.BehaviorDesigner.Runtime.Tasks; +using Opsive.GraphDesigner.Runtime; +using Unity.Entities; +using Unity.Burst; +using UnityEngine; + +/// +/// A custom ECS action node. +/// +public class {name} : ECSActionTask<{name}TaskSystem, {name}Component> +{{ + /// + /// The type of flag that should be enabled when the task is running. + /// + public override ComponentType Flag {{ get => typeof({name}Flag); }} + + /// + /// Returns a new {name}Component for use by the system. + /// + /// A new {name}Component for use by the system. + public override {name}Component GetBufferElement() + {{ + return new {name}Component() {{ + Index = RuntimeIndex, + }}; + }} +}} + +/// +/// The DOTS data structure for the {name} class. +/// +public struct {name}Component : IBufferElementData +{{ + [Tooltip(""The index of the node."")] + public ushort Index; +}} + +/// +/// A DOTS flag indicating when a {name} node is active. +/// +public struct {name}Flag : IComponentData, IEnableableComponent {{ }} + +/// +/// Runs the {name} logic. +/// +[DisableAutoCreation] +public partial struct {name}TaskSystem : ISystem +{{ + /// + /// Creates the job. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + {{ + var query = SystemAPI.QueryBuilder().WithAllRW().WithAllRW().WithAllRW<{name}Component>().WithAll<{name}Flag, EvaluateFlag>().Build(); + state.Dependency = new {name}Job().ScheduleParallel(query, state.Dependency); + }} + + /// + /// Job which executes the task logic. + /// + [BurstCompile] + private partial struct {name}Job : IJobEntity + {{ + /// + /// Executes the {name} logic. + /// + /// An array of BranchComponents. + /// An array of TaskComponents. + /// An array of {name}Components. + [BurstCompile] + public void Execute(ref DynamicBuffer branchComponents, ref DynamicBuffer taskComponents, ref DynamicBuffer<{name}Component> {variableName}Components) + {{ + for (int i = 0; i < {variableName}Components.Length; ++i) {{ + var {variableName}Component = {variableName}Components[i]; + var taskComponent = taskComponents[{variableName}Component.Index]; + var branchComponent = branchComponents[taskComponent.BranchIndex]; + if (!branchComponent.CanExecute) {{ + continue; + }} + + if (taskComponent.Status == TaskStatus.Queued) {{ + taskComponent.Status = TaskStatus.Success; + taskComponents[{variableName}Component.Index] = taskComponent; + }} + }} + }} + }} +}}"; + } + } + + /// + /// Template for creating a custom composite node. + /// + [Category("ECS")] + [DisplayName("Composite")] + [Description("Create a new ECS composite node.")] + public class ECSCompositeNode : IParentNodeTemplate + { + public Type BaseType => typeof(IComposite); + public bool IsLogicNode => true; + + /// + /// Returns the script that should be used for the template file. + /// + /// The name of the node. + /// The node script. + public string GetScript(string name) + { + var variableName = ECSNodeUtility.ToCamelCase(name); + return $@"using Opsive.BehaviorDesigner.Runtime.Components; +using Opsive.BehaviorDesigner.Runtime.Tasks; +using Opsive.GraphDesigner.Runtime; +using Unity.Entities; +using Unity.Burst; +using UnityEngine; + +/// +/// A custom ECS composite node. +/// +public class {name} : ECSCompositeTask<{name}TaskSystem, {name}Component> +{{ + /// + /// The type of tag that should be enabled when the task is running. + /// + public override ComponentType Flag {{ get => typeof({name}Flag); }} + + /// + /// Returns a new {name}Component for use by the system. + /// + /// A new {name}Component for use by the system. + public override {name}Component GetBufferElement() + {{ + return new {name}Component() {{ + Index = RuntimeIndex, + }}; + }} +}} + +/// +/// The DOTS data structure for the {name} class. +/// +public struct {name}Component : IBufferElementData +{{ + [Tooltip(""The index of the node."")] + public ushort Index; + [Tooltip(""The index of the child that is currently active."")] + public ushort ActiveChildIndex; +}} + +/// +/// A DOTS flag indicating when a {name} node is active. +/// +public struct {name}Flag : IComponentData, IEnableableComponent {{ }} + +/// +/// Runs the {name} logic. +/// +[DisableAutoCreation] +public partial struct {name}TaskSystem : ISystem +{{ + /// + /// Creates the job. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + {{ + var query = SystemAPI.QueryBuilder().WithAllRW().WithAllRW().WithAllRW<{name}Component>().WithAll<{name}Flag, EvaluateFlag>().Build(); + state.Dependency = new {name}Job().ScheduleParallel(query, state.Dependency); + }} + + /// + /// Job which executes the task logic. + /// + [BurstCompile] + private partial struct {name}Job : IJobEntity + {{ + /// + /// Executes the {name} logic. + /// + /// An array of BranchComponents. + /// An array of TaskComponents. + /// An array of {name}Components. + [BurstCompile] + public void Execute(ref DynamicBuffer branchComponents, ref DynamicBuffer taskComponents, ref DynamicBuffer<{name}Component> {variableName}Components) + {{ + for (int i = 0; i < {variableName}Components.Length; ++i) {{ + var {variableName}Component = {variableName}Components[i]; + var taskComponent = taskComponents[{variableName}Component.Index]; + var branchComponent = branchComponents[taskComponent.BranchIndex]; + if (!branchComponent.CanExecute) {{ + continue; + }} + + if (taskComponent.Status == TaskStatus.Queued) {{ + taskComponent.Status = TaskStatus.Success; + taskComponents[{variableName}Component.Index] = taskComponent; + + branchComponent.NextIndex = taskComponent.ParentIndex; + branchComponents[taskComponent.BranchIndex] = branchComponent; + }} + }} + }} + }} +}}"; + } + } + + /// + /// Template for creating a custom conditional node. + /// + [Category("ECS")] + [DisplayName("Conditional")] + [Description("Create a new ECS conditional node.")] + public class ECSConditionalNode : INodeTemplate + { + public Type BaseType => typeof(IConditional); + public bool IsLogicNode => true; + + /// + /// Returns the script that should be used for the template file. + /// + /// The name of the node. + /// The node script. + public string GetScript(string name) + { + var variableName = ECSNodeUtility.ToCamelCase(name); + return $@"using Opsive.BehaviorDesigner.Runtime.Components; +using Opsive.BehaviorDesigner.Runtime.Tasks; +using Opsive.GraphDesigner.Runtime; +using Unity.Burst; +using Unity.Entities; +using UnityEngine; + +/// +/// A custom ECS conditional node. +/// +public class {name} : ECSConditionalTask<{name}TaskSystem, {name}Component>, IReevaluateResponder +{{ + /// + /// The type of flag that should be enabled when the task is running. + /// + public override ComponentType Flag {{ get => typeof({name}Flag); }} + /// + /// The type of flag that should be enabled when the task is being reevaluated. + /// + public ComponentType ReevaluateFlag {{ get => typeof({name}ReevaluateFlag); }} + /// + /// The system type that the reevaluation component uses. + /// + public System.Type ReevaluateSystemType {{ get => typeof({name}ReevaluateTaskSystem); }} + + /// + /// Returns a new {name}Component for use by the system. + /// + /// A new {name}Component for use by the system. + public override {name}Component GetBufferElement() + {{ + return new {name}Component() {{ + Index = RuntimeIndex, + }}; + }} +}} + +/// +/// The DOTS data structure for the {name} class. +/// +public struct {name}Component : IBufferElementData +{{ + [Tooltip(""The index of the node."")] + public ushort Index; +}} + +/// +/// A DOTS flag indicating when a {name} node is active. +/// +public struct {name}Flag : IComponentData, IEnableableComponent {{ }} + +/// +/// Runs the {name} logic. +/// +[DisableAutoCreation] +public partial struct {name}TaskSystem : ISystem +{{ + /// + /// Creates the job. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + {{ + var query = SystemAPI.QueryBuilder().WithAllRW().WithAllRW().WithAllRW<{name}Component>().WithAll<{name}Flag, EvaluateFlag>().Build(); + state.Dependency = new {name}Job().ScheduleParallel(query, state.Dependency); + }} + + /// + /// Job which executes the task logic. + /// + [BurstCompile] + private partial struct {name}Job : IJobEntity + {{ + /// + /// Executes the {name} logic. + /// + /// An array of BranchComponents. + /// An array of TaskComponents. + /// An array of {name}Components. + [BurstCompile] + public void Execute(ref DynamicBuffer branchComponents, ref DynamicBuffer taskComponents, ref DynamicBuffer<{name}Component> {variableName}Components) + {{ + for (int i = 0; i < {variableName}Components.Length; ++i) {{ + var {variableName}Component = {variableName}Components[i]; + var taskComponent = taskComponents[{variableName}Component.Index]; + var branchComponent = branchComponents[taskComponent.BranchIndex]; + if (!branchComponent.CanExecute) {{ + continue; + }} + + if (taskComponent.Status == TaskStatus.Queued || taskComponent.Status == TaskStatus.Running) {{ // Conditional aborts can set the status to Running. + taskComponent.Status = TaskStatus.Success; + taskComponents[{variableName}Component.Index] = taskComponent; + }} + }} + }} + }} +}} + +/// +/// A DOTS flag indicating when an {name} node needs to be reevaluated. +/// +public struct {name}ReevaluateFlag : IComponentData, IEnableableComponent {{ }} + +/// +/// Runs the {name} reevaluation logic. +/// +[DisableAutoCreation] +public partial struct {name}ReevaluateTaskSystem : ISystem +{{ + /// + /// Updates the reevaluation logic. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + {{ + foreach (var (branchComponents, taskComponents, {variableName}Components) in + SystemAPI.Query, DynamicBuffer, DynamicBuffer<{name}Component>>().WithAll<{name}ReevaluateFlag, EvaluateFlag>()) {{ + for (int i = 0; i < {variableName}Components.Length; ++i) {{ + var {variableName}Component = {variableName}Components[i]; + var taskComponent = taskComponents[{variableName}Component.Index]; + var branchComponent = branchComponents[taskComponent.BranchIndex]; + if (!branchComponent.CanExecute) {{ + continue; + }} + + if (!taskComponent.Reevaluate) {{ + continue; + }} + + var status = TaskStatus.Success; + if (status != taskComponent.Status) {{ + taskComponent.Status = status; + var buffer = taskComponents; + buffer[taskComponent.Index] = taskComponent; + }} + }} + }} + }} +}}"; + } + } + + /// + /// Template for creating a custom decorator node. + /// + [Category("ECS")] + [DisplayName("Decorator")] + [Description("Create a new ECS decorator node.")] + public class ECSDecoratorNode : IParentNodeTemplate + { + public Type BaseType => typeof(IDecorator); + public bool IsLogicNode => true; + + /// + /// Returns the script that should be used for the template file. + /// + /// The name of the node. + /// The node script. + public string GetScript(string name) + { + var variableName = ECSNodeUtility.ToCamelCase(name); + return $@"using Opsive.BehaviorDesigner.Runtime.Components; +using Opsive.BehaviorDesigner.Runtime.Tasks; +using Opsive.GraphDesigner.Runtime; +using Unity.Entities; +using Unity.Burst; +using UnityEngine; + +/// +/// A custom ECS decorator node. +/// +public class {name} : ECSDecoratorTask<{name}TaskSystem, {name}Component> +{{ + /// + /// The type of flag that should be enabled when the task is running. + /// + public override ComponentType Flag {{ get => typeof({name}Flag); }} + + /// + /// Returns a new {name}Component for use by the system. + /// + /// A new {name}Component for use by the system. + public override {name}Component GetBufferElement() + {{ + return new {name}Component() {{ + Index = RuntimeIndex, + }}; + }} +}} + +/// +/// The DOTS data structure for the {name} class. +/// +public struct {name}Component : IBufferElementData +{{ + [Tooltip(""The index of the node."")] + public ushort Index; +}} + +/// +/// A DOTS flag indicating when a {name} node is active. +/// +public struct {name}Flag : IComponentData, IEnableableComponent {{ }} + +/// +/// Runs the {name} logic. +/// +[DisableAutoCreation] +public partial struct {name}TaskSystem : ISystem +{{ + /// + /// Creates the job. + /// + /// The current state of the system. + [BurstCompile] + private void OnUpdate(ref SystemState state) + {{ + var query = SystemAPI.QueryBuilder().WithAllRW().WithAllRW().WithAllRW<{name}Component>().WithAll<{name}Flag, EvaluateFlag>().Build(); + state.Dependency = new {name}Job().ScheduleParallel(query, state.Dependency); + }} + + /// + /// Job which executes the task logic. + /// + [BurstCompile] + private partial struct {name}Job : IJobEntity + {{ + /// + /// Executes the {name} logic. + /// + /// An array of BranchComponents. + /// An array of TaskComponents. + /// An array of {name}Components. + [BurstCompile] + public void Execute(ref DynamicBuffer branchComponents, ref DynamicBuffer taskComponents, ref DynamicBuffer<{name}Component> {variableName}Components) + {{ + for (int i = 0; i < {variableName}Components.Length; ++i) {{ + var {variableName}Component = {variableName}Components[i]; + var taskComponent = taskComponents[{variableName}Component.Index]; + var branchComponent = branchComponents[taskComponent.BranchIndex]; + if (!branchComponent.CanExecute) {{ + continue; + }} + + if (taskComponent.Status == TaskStatus.Queued) {{ + taskComponent.Status = TaskStatus.Success; + taskComponents[{variableName}Component.Index] = taskComponent; + }} + }} + }} + }} +}}"; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Templates/ECSNodes.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Templates/ECSNodes.cs.meta new file mode 100644 index 0000000..b390d52 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Templates/ECSNodes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7fc528e1a6212314cb23a55b5a274d49 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Templates/GameObjectNodes.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Templates/GameObjectNodes.cs new file mode 100644 index 0000000..44b32b5 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Templates/GameObjectNodes.cs @@ -0,0 +1,242 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime +{ + using Opsive.BehaviorDesigner.Runtime.Tasks; + using Opsive.GraphDesigner.Runtime; + using Opsive.Shared.Utility; + using System; + + /// + /// Template for creating a custom action node. + /// + [Category("GameObjects")] + [DisplayName("Action")] + [Description("Create a new action node.")] + public class GameObjectActionNode : INodeTemplate + { + public Type BaseType => typeof(IAction); + public bool IsLogicNode => true; + + /// + /// Returns the script that should be used for the template file. + /// + /// The name of the node. + /// The node script. + public string GetScript(string name) + { + return $@"using Opsive.BehaviorDesigner.Runtime.Tasks; +using Opsive.BehaviorDesigner.Runtime.Tasks.Actions; + +/// +/// A custom action node. +/// +public class {name} : ActionNode +{{ + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + {{ + return TaskStatus.Success; + }} +}}"; + } + } + + /// + /// Template for creating a custom action task. + /// + [Category("GameObjects")] + [DisplayName("Stacked Action")] + [Description("Create a new stacked action node.")] + public class GameObjectAction : INodeTemplate + { + public Type BaseType => typeof(IAction); + public bool IsLogicNode => false; + + /// + /// Returns the script that should be used for the template file. + /// + /// The name of the node. + /// The node script. + public string GetScript(string name) + { + return $@"using Opsive.BehaviorDesigner.Runtime.Tasks; +using Opsive.BehaviorDesigner.Runtime.Tasks.Actions; + +/// +/// A custom action task. +/// +public class {name} : Action +{{ + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + {{ + return TaskStatus.Success; + }} +}}"; + } + } + + /// + /// Template for creating a custom composite node. + /// + [Category("GameObjects")] + [DisplayName("Composite")] + [Description("Create a new composite node.")] + public class GameObjectCompositeNode : IParentNodeTemplate + { + public Type BaseType => typeof(IComposite); + public bool IsLogicNode => true; + + /// + /// Returns the script that should be used for the template file. + /// + /// The name of the node. + /// The node script. + public string GetScript(string name) + { + return $@"using Opsive.BehaviorDesigner.Runtime.Tasks; +using Opsive.BehaviorDesigner.Runtime.Tasks.Composites; + +/// +/// A custom composite task. +/// +public class {name} : CompositeNode +{{ + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + {{ + return TaskStatus.Success; + }} +}}"; + } + } + + /// + /// Template for creating a custom conditional node. + /// + [Category("GameObjects")] + [DisplayName("Conditional")] + [Description("Create a new conditional node.")] + public class GameObjectConditionalNode : INodeTemplate + { + public Type BaseType => typeof(IConditional); + public bool IsLogicNode => true; + + /// + /// Returns the script that should be used for the template file. + /// + /// The name of the node. + /// The node script. + public string GetScript(string name) + { + return $@"using Opsive.BehaviorDesigner.Runtime.Tasks; +using Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals; + +/// +/// A custom conditional node. +/// +public class {name} : ConditionalNode +{{ + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + {{ + return TaskStatus.Success; + }} +}}"; + } + } + + /// + /// Template for creating a custom conditional task. + /// + [Category("GameObjects")] + [DisplayName("Stacked Conditional")] + [Description("Create a new stacked conditional node.")] + public class GameObjectConditional : INodeTemplate + { + public Type BaseType => typeof(IConditional); + public bool IsLogicNode => false; + + /// + /// Returns the script that should be used for the template file. + /// + /// The name of the node. + /// The node script. + public string GetScript(string name) + { + return $@"using Opsive.BehaviorDesigner.Runtime.Tasks; +using Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals; + +/// +/// A custom conditional task. +/// +public class {name} : Conditional +{{ + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + {{ + return TaskStatus.Success; + }} +}}"; + } + } + + /// + /// Template for creating a custom decorator node. + /// + [Category("GameObjects")] + [DisplayName("Decorator")] + [Description("Create a new decorator node.")] + public class GameObjectDecoratorNode : IParentNodeTemplate + { + public Type BaseType => typeof(IDecorator); + public bool IsLogicNode => true; + + /// + /// Returns the script that should be used for the template file. + /// + /// The name of the node. + /// The node script. + public string GetScript(string name) + { + return $@"using Opsive.BehaviorDesigner.Runtime.Tasks; +using Opsive.BehaviorDesigner.Runtime.Tasks.Decorators; + +/// +/// A custom decorator task. +/// +public class {name} : DecoratorNode +{{ + /// + /// Executes the task. + /// + /// The execution status of the task. + public override TaskStatus OnUpdate() + {{ + return TaskStatus.Success; + }} +}}"; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Templates/GameObjectNodes.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Templates/GameObjectNodes.cs.meta new file mode 100644 index 0000000..7a1d03f --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/Templates/GameObjectNodes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 930aae40e5a83b84ba865fcf660bcdd7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/UnknownTasks.cs b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/UnknownTasks.cs new file mode 100644 index 0000000..c404b53 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/UnknownTasks.cs @@ -0,0 +1,107 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Tasks +{ + using Opsive.BehaviorDesigner.Runtime.Tasks.Actions; + using Opsive.BehaviorDesigner.Runtime.Tasks.Composites; + using Opsive.GraphDesigner.Runtime; + using Opsive.Shared.Utility; + using UnityEngine; + + /// + /// Represents a task node that can no longer be found. + /// + [HideInFilterWindow] + public class UnknownTaskNode : ActionNode + { + private string m_UnknownType; + + /// + /// Default constructor. + /// + public UnknownTaskNode() { } + + /// + /// UnknownTaskNode constructor. + /// + /// The type that cannot be found. + public UnknownTaskNode(string unknownType) + { + m_UnknownType = unknownType; + } + + /// + /// Called once when the behavior tree is initialized. + /// + public override void OnAwake() + { + base.OnAwake(); + + Debug.LogWarning($"Warning: Unable to find the task of type {m_UnknownType}. An unknown task has been replaced with it."); + } + } + + /// + /// Represents a task that can no longer be found. + /// + [HideInFilterWindow] + public class UnknownTask : Action + { + /// + /// Called once when the behavior tree is initialized. + /// + public override void OnAwake() + { + base.OnAwake(); + + Debug.LogWarning($"Warning: Unable to find the original task. An unknown task has been replaced with it."); + } + } + + /// + /// Represents a parent task node that can no longer be found. + /// + [HideInFilterWindow] + public class UnknownParentTaskNode : CompositeNode + { + private string m_UnknownType; + + /// + /// Default constructor. + /// + public UnknownParentTaskNode() { } + + /// + /// UnknownParentTaskNode constructor. + /// + /// The type that cannot be found. + public UnknownParentTaskNode(string unknownType) + { + m_UnknownType = unknownType; + } + + /// + /// Called once when the behavior tree is initialized. + /// + public override void OnAwake() + { + base.OnAwake(); + + Debug.LogWarning($"Warning: Unable to find the task of type {m_UnknownType}. An unknown task has been replaced with it."); + } + } + + /// + /// Represents an event node that can no longer be found. + /// + [HideInFilterWindow] + public class UnknownEventTask : IEventNode + { + public ushort ConnectedIndex { get => ushort.MaxValue; set { } } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Tasks/UnknownTasks.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/UnknownTasks.cs.meta new file mode 100644 index 0000000..bcc9d81 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Tasks/UnknownTasks.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 291d6f08a99331f48b9f7967ec344afd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Utility.meta b/Packages/com.opsive.behaviordesigner/Runtime/Utility.meta new file mode 100644 index 0000000..244736e --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Utility.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 863e492baa6c6c84e9b200e8e99f575b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Utility/ComponentUtility.cs b/Packages/com.opsive.behaviordesigner/Runtime/Utility/ComponentUtility.cs new file mode 100644 index 0000000..e21a6c0 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Utility/ComponentUtility.cs @@ -0,0 +1,162 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Utility +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Unity.Collections; + using Unity.Entities; + + /// + /// Utility functions that are used throughout the behavior tree execution. + /// + public static class ComponentUtility + { + /// + /// The size of a ulong in bits. + /// + public static int ulongBitSize => sizeof(ulong) * 8; + + /// + /// Adds an evaluation component to the specified entity based on the task count and evaluation type. + /// + /// The ECS world to add the component to. + /// The entity to add the evaluation component to. + /// The total number of tasks in the behavior tree. + /// The type of evaluation to perform. + /// The maximum number of evaluations allowed. + public static void AddEvaluationComponent(World world, Entity entity, int taskCount, EvaluationType evaluationType, int maxEvaluationCount) + { + // Both EvaluationType.EntireTree and EvaluationType.Count use a bitmask to track evaluated tasks. + // For Count mode, an additional element is reserved at the end to store the execution count. + var bitmaskElementCount = taskCount / ulongBitSize + 1; + var countModeExtraElement = evaluationType == EvaluationType.Count ? 1 : 0; + + if (taskCount < 192) { + world.EntityManager.AddComponent(entity); + var evaluatedTasks = new FixedList32Bytes(); + for (int i = 0; i < bitmaskElementCount + countModeExtraElement; ++i) { + evaluatedTasks.Add(0); + } + world.EntityManager.AddComponentData(entity, new EvaluationComponent32() { EvaluationType = evaluationType, MaxEvaluationCount = (ushort)UnityEngine.Mathf.Max(1, maxEvaluationCount), EvaluatedTasks = evaluatedTasks }); + } else if (taskCount < 448) { + world.EntityManager.AddComponent(entity); + var evaluatedTasks = new FixedList64Bytes(); + for (int i = 0; i < bitmaskElementCount + countModeExtraElement; ++i) { + evaluatedTasks.Add(0); + } + world.EntityManager.AddComponentData(entity, new EvaluationComponent64() { EvaluationType = evaluationType, MaxEvaluationCount = (ushort)UnityEngine.Mathf.Max(1, maxEvaluationCount), EvaluatedTasks = evaluatedTasks }); + } else if (taskCount < 960) { + world.EntityManager.AddComponent(entity); + var evaluatedTasks = new FixedList128Bytes(); + for (int i = 0; i < bitmaskElementCount + countModeExtraElement; ++i) { + evaluatedTasks.Add(0); + } + world.EntityManager.AddComponentData(entity, new EvaluationComponent128() { EvaluationType = evaluationType, MaxEvaluationCount = (ushort)UnityEngine.Mathf.Max(1, maxEvaluationCount), EvaluatedTasks = evaluatedTasks }); + } else if (taskCount < 4032) { + world.EntityManager.AddComponent(entity); + var evaluatedTasks = new FixedList512Bytes(); + for (int i = 0; i < bitmaskElementCount + countModeExtraElement; ++i) { + evaluatedTasks.Add(0); + } + world.EntityManager.AddComponentData(entity, new EvaluationComponent512() { EvaluationType = evaluationType, MaxEvaluationCount = (ushort)UnityEngine.Mathf.Max(1, maxEvaluationCount), EvaluatedTasks = evaluatedTasks }); + } else if (taskCount < 32704) { + world.EntityManager.AddComponent(entity); + var evaluatedTasks = new FixedList4096Bytes(); + for (int i = 0; i < bitmaskElementCount + countModeExtraElement; ++i) { + evaluatedTasks.Add(0); + } + world.EntityManager.AddComponentData(entity, new EvaluationComponent4096() { EvaluationType = evaluationType, MaxEvaluationCount = (ushort)UnityEngine.Mathf.Max(1, maxEvaluationCount), EvaluatedTasks = evaluatedTasks }); + } else { + UnityEngine.Debug.LogError("Error: Trees with more than 32,703 tasks are not supported. Please email support@opsive.com."); + } + } + + /// + /// Resets the evaluation component data for the specified entity by clearing all evaluated task flags. + /// + /// The ECS world containing the entity. + /// The entity whose evaluation component should be reset. + public static void ResetEvaluationComponent(World world, Entity entity) + { + if (world.EntityManager.HasComponent(entity)) { + var evaluateComponent = world.EntityManager.GetComponentData(entity); + var evaluatedTasks = evaluateComponent.EvaluatedTasks; + for (int i = 0; i < evaluatedTasks.Length; ++i) { + evaluatedTasks[i] = 0; + } + evaluateComponent.EvaluatedTasks = evaluatedTasks; + world.EntityManager.SetComponentData(entity, evaluateComponent); + } else if (world.EntityManager.HasComponent(entity)) { + var evaluateComponent = world.EntityManager.GetComponentData(entity); + var evaluatedTasks = evaluateComponent.EvaluatedTasks; + for (int i = 0; i < evaluatedTasks.Length; ++i) { + evaluatedTasks[i] = 0; + } + evaluateComponent.EvaluatedTasks = evaluatedTasks; + world.EntityManager.SetComponentData(entity, evaluateComponent); + } else if (world.EntityManager.HasComponent(entity)) { + var evaluateComponent = world.EntityManager.GetComponentData(entity); + var evaluatedTasks = evaluateComponent.EvaluatedTasks; + for (int i = 0; i < evaluatedTasks.Length; ++i) { + evaluatedTasks[i] = 0; + } + evaluateComponent.EvaluatedTasks = evaluatedTasks; + world.EntityManager.SetComponentData(entity, evaluateComponent); + } else if (world.EntityManager.HasComponent(entity)) { + var evaluateComponent = world.EntityManager.GetComponentData(entity); + var evaluatedTasks = evaluateComponent.EvaluatedTasks; + for (int i = 0; i < evaluatedTasks.Length; ++i) { + evaluatedTasks[i] = 0; + } + evaluateComponent.EvaluatedTasks = evaluatedTasks; + world.EntityManager.SetComponentData(entity, evaluateComponent); + } else if (world.EntityManager.HasComponent(entity)) { + var evaluateComponent = world.EntityManager.GetComponentData(entity); + var evaluatedTasks = evaluateComponent.EvaluatedTasks; + for (int i = 0; i < evaluatedTasks.Length; ++i) { + evaluatedTasks[i] = 0; + } + evaluateComponent.EvaluatedTasks = evaluatedTasks; + world.EntityManager.SetComponentData(entity, evaluateComponent); + } + } + + /// + /// Removes the evaluation component from the specified entity. + /// + /// The ECS world containing the entity. + /// The entity whose evaluation component should be removed. + public static void RemoveEvaluationComponent(World world, Entity entity) + { + if (world.EntityManager.HasComponent(entity)) { + world.EntityManager.RemoveComponent(entity); + } else if (world.EntityManager.HasComponent(entity)) { + world.EntityManager.RemoveComponent(entity); + } else if (world.EntityManager.HasComponent(entity)) { + world.EntityManager.RemoveComponent(entity); + } else if (world.EntityManager.HasComponent(entity)) { + world.EntityManager.RemoveComponent(entity); + } else if (world.EntityManager.HasComponent(entity)) { + world.EntityManager.RemoveComponent(entity); + } + } + + /// + /// Adds the components necessary in order to trigger an interrupt. + /// + /// The EntityManager that the entity belongs to. + /// The entity that should have the components added. + public static void AddInterruptComponents(EntityManager entityManager, Entity entity) + { + entityManager.AddComponent(entity); + entityManager.SetComponentEnabled(entity, false); + entityManager.AddComponent(entity); + entityManager.SetComponentEnabled(entity, false); + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Utility/ComponentUtility.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Utility/ComponentUtility.cs.meta new file mode 100644 index 0000000..1a1e278 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Utility/ComponentUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1bfee368f88aa6e4a81281d10c71072d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Utility/SaveManager.cs b/Packages/com.opsive.behaviordesigner/Runtime/Utility/SaveManager.cs new file mode 100644 index 0000000..08a810b --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Utility/SaveManager.cs @@ -0,0 +1,651 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Utility +{ + using Opsive.BehaviorDesigner.Runtime; + using Opsive.BehaviorDesigner.Runtime.Components; + using Opsive.BehaviorDesigner.Runtime.Tasks; + using Opsive.GraphDesigner.Runtime; + using Opsive.GraphDesigner.Runtime.Variables; + using Opsive.Shared.Utility; + using System; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using Unity.Entities; + using UnityEngine; + using static Opsive.BehaviorDesigner.Runtime.BehaviorTreeData; + + /// + /// Helper class which will save and load behavior tree tasks. + /// + public static class SaveManager + { + /// + /// Specifies which objects should be saved. + /// + public enum VariableSaveScope : byte + { + GameObjectVariables = 1, // Saves the GameObjectVariables. + SceneVariables = 2, // Saves the SceneVariables. + ProjectVariables = 4 // Saves the ProjectVariables. + } + + /// + /// The save data associated with the behavior tree and shared variables. + /// + [System.Serializable] + public struct SaveData + { + [Tooltip("The behavior tree save data.")] + public BehaviorTreeSaveData[] BehaviorTreeSaveData; + [Tooltip("The external shared variable save data.")] + public VariableSaveData[] VariableSaveData; + } + + /// + /// The save data associated with the behavior tree. + /// + [System.Serializable] + public struct BehaviorTreeSaveData + { + [Tooltip("The unique ID of the save data. This will change each time the data is serialized")] + public int UniqueID; + [Tooltip("The loaded task components.")] + public Serialization[] TaskComponents; + [Tooltip("The loaded branch components.")] + public Serialization[] BranchComponents; + [Tooltip("The loaded reevaluate task components.")] + public Serialization[] ReevaluateTaskComponents; + [Tooltip("The user task data.")] + public TaskSaveData[] TaskData; + [Tooltip("The values of the graph SharedVariables.")] + public VariableSaveData GraphSharedVariables; + } + + /// + /// The save data associated with the shared variables. + /// + [System.Serializable] + public struct VariableSaveData + { + [Tooltip("The unique ID of the variable data. This will change each time the data is serialized")] + public int UniqueID; + [Tooltip("The values of the SharedVariables.")] + public Serialization[] Values; + [Tooltip("The scope of the variables.")] + public SharedVariable.SharingScope Scope; + } + + /// + /// Container for the task save data. Allows for nested tasks. + /// + [System.Serializable] + public struct TaskSaveData + { + [Tooltip("The save data associated with each task.")] + public Serialization[] Value; + } + + /// + /// Gets the save data from the specified behavior trees. + /// + /// The behavior trees that should be saved. + /// Specifies which variables should be saved. Graph variables will automatically be saved. + /// The resulting save data. Can be null. + public static SaveData? Save(BehaviorTree[] behaviorTrees, VariableSaveScope variableSaveScope = 0) + { + if (!Application.isPlaying) { + Debug.LogWarning($"Warning: Behavior trees can only be saved at runtime."); + return null; + } + + if (behaviorTrees.Length == 0) { + return null; + } + + // Assume all behavior trees can be saved. + var saveData = new SaveData(); + saveData.BehaviorTreeSaveData = new BehaviorTreeSaveData[behaviorTrees.Length]; + var variableSaveDataList = new List(); + HashSet savedGameObjectVariables = null; + var behaviorTreeSaveCount = 0; + for (int i = 0; i < behaviorTrees.Length; ++i) { + if (behaviorTrees[i] == null) { + continue; + } + + // Add the save data to the array if the save is valid. + var behaviorTreeSaveData = Save(behaviorTrees[i]); + if (behaviorTreeSaveData.HasValue) { + saveData.BehaviorTreeSaveData[behaviorTreeSaveCount] = behaviorTreeSaveData.Value; + behaviorTreeSaveCount++; + + // The associated GameObject variables may also need to be saved. + if ((variableSaveScope & VariableSaveScope.GameObjectVariables) != 0) { + // Only save the GameObject variables once. + if (savedGameObjectVariables == null) { + savedGameObjectVariables = new HashSet(); + } + + if (savedGameObjectVariables.Contains(behaviorTrees[i].gameObject)) { + continue; + } + savedGameObjectVariables.Add(behaviorTrees[i].gameObject); + + // The GameObject variables can be saved. + var gameObjectSharedVariables = behaviorTrees[i].gameObject.GetComponent(); + if (gameObjectSharedVariables != null) { + var variableSaveData = Save(gameObjectSharedVariables); + if (variableSaveData.HasValue) { + variableSaveDataList.Add(variableSaveData.Value); + } + } + } + } + } + + // Not all behavior trees can be saved. + if (behaviorTrees.Length != behaviorTreeSaveCount) { + var behaviorTreesSaveData = saveData.BehaviorTreeSaveData; + System.Array.Resize(ref behaviorTreesSaveData, behaviorTreeSaveCount); + saveData.BehaviorTreeSaveData = behaviorTreesSaveData; + } + + // The scene variables can be saved. + if ((variableSaveScope & VariableSaveScope.SceneVariables) != 0) { + if (SceneSharedVariables.Instance != null) { + var variableSaveData = Save(SceneSharedVariables.Instance); + if (variableSaveData.HasValue) { + variableSaveDataList.Add(variableSaveData.Value); + } + } + } + + // The project variables can be saved. + if ((variableSaveScope & VariableSaveScope.ProjectVariables) != 0) { + if (ProjectSharedVariables.Instance != null) { + var variableSaveData = Save(ProjectSharedVariables.Instance); + if (variableSaveData.HasValue) { + variableSaveDataList.Add(variableSaveData.Value); + } + } + } + + // There has to be something to be saved. + if (behaviorTreeSaveCount == 0 && variableSaveDataList.Count == 0) { + return null; + } + + // Persist the variable save data. + if (variableSaveDataList != null && variableSaveDataList.Count > 0) { + saveData.VariableSaveData = variableSaveDataList.ToArray(); + } + + return saveData; + } + + /// + /// Saves the save data from the specified behavior trees to the specified file. + /// + /// The behavior trees that should be saved. + /// The save data path. + /// Specifies which variables should be saved. Graph variables will automatically be saved. + /// True if at least one behavior tree's save data was saved. + public static bool Save(BehaviorTree[] behaviorTrees, string filePath, VariableSaveScope variableSaveScope = 0) + { + var saveData = Save(behaviorTrees, variableSaveScope); + if (!saveData.HasValue) { + return false; + } + + // Save the save data. + if (File.Exists(filePath)) { + File.Delete(filePath); + } + try { + if (!Directory.Exists(Path.GetDirectoryName(filePath))) { + Directory.CreateDirectory(Path.GetDirectoryName(filePath)); + } + var fileStream = File.Create(filePath); + using (var streamWriter = new StreamWriter(fileStream)) { + streamWriter.Write(JsonUtility.ToJson(saveData)); + } + fileStream.Close(); + } catch (System.Exception e) { + Debug.LogException(e); + return false; + } + + return true; + } + + /// + /// Returns the save data associated with the behavior tree. + /// + /// The behavior tree that should be saved. + /// The save data associated with the behavior tree. + private static BehaviorTreeSaveData? Save(BehaviorTree behaviorTree) + { + if (behaviorTree.Entity.Index == 0) { + Debug.LogWarning($"Warning: The behavior tree {behaviorTree.name} must be active in order to be saved.", behaviorTree); + return null; + } + + if (behaviorTree.LogicNodes == null || behaviorTree.LogicNodes.Length == 0) { + Debug.LogWarning($"Warning: The behavior tree {behaviorTree.name} must have tasks in order to be saved.", behaviorTree); + return null; + } + + // The current task status must be serialized. + var taskComponents = behaviorTree.World.EntityManager.GetBuffer(behaviorTree.Entity); + var serializedTaskComponents = new Serialization[taskComponents.Length]; + for (int i = 0; i < taskComponents.Length; ++i) { + serializedTaskComponents[i] = Serialization.Serialize(taskComponents[i]); + } + + // The branch info must be serialized. + var branchComponents = behaviorTree.World.EntityManager.GetBuffer(behaviorTree.Entity); + var serializedBranchComponents = new Serialization[branchComponents.Length]; + for (int i = 0; i < branchComponents.Length; ++i) { + serializedBranchComponents[i] = Serialization.Serialize(branchComponents[i]); + } + + // The reevaluation status must be serialized. + Serialization[] serializedReevaluateTaskComponents = null; + if (behaviorTree.World.EntityManager.HasBuffer(behaviorTree.Entity)) { + var reevaluateTaskComponents = behaviorTree.World.EntityManager.GetBuffer(behaviorTree.Entity); + serializedReevaluateTaskComponents = new Serialization[reevaluateTaskComponents.Length]; + for (int i = 0; i < reevaluateTaskComponents.Length; ++i) { + serializedReevaluateTaskComponents[i] = Serialization.Serialize(reevaluateTaskComponents[i]); + } + } + + // Each task can serialize their own data. + var tasks = behaviorTree.LogicNodes; + var serializedTaskData = new List(); + for (int i = 0; i < tasks.Length; ++i) { + if (!(tasks[i] is ISavableTask)) { + continue; + } + + var saveableTask = tasks[i] as ISavableTask; + var reflectionType = saveableTask.GetSaveReflectionType(-1); + if (reflectionType != MemberVisibility.None) { + var serializedData = Serialization.Serialize(saveableTask, reflectionType, BehaviorTreeData.ValidateSerializedObject); + serializedTaskData.Add(new TaskSaveData() { Value = new Serialization[] { serializedData } }); + } else { + var taskData = saveableTask.Save(behaviorTree.World, behaviorTree.Entity); + if (taskData == null) { + continue; + } + + // Tasks can contain more tasks. Serialize each task element separately. + if (typeof(IList).IsAssignableFrom(taskData.GetType())) { + var taskDataList = taskData as IList; + var taskSaveData = new Serialization[taskDataList.Count]; + for (int j = 0; j < taskDataList.Count; ++j) { + if (taskDataList[j] is Serialization) { + taskSaveData[j] = taskDataList[j] as Serialization; + } else { + taskSaveData[j] = Serialization.Serialize(taskDataList[j]); + } + } + + serializedTaskData.Add(new TaskSaveData() { Value = taskSaveData }); + } else { + var serializedValue = new Serialization[] { (taskData is Serialization) ? (taskData as Serialization) : Serialization.Serialize(taskData) }; + serializedTaskData.Add(new TaskSaveData() { Value = serializedValue }); + } + } + } + + var behaviorTreeSaveData = new BehaviorTreeSaveData() { + UniqueID = behaviorTree.UniqueID, + TaskComponents = serializedTaskComponents, + BranchComponents = serializedBranchComponents, + ReevaluateTaskComponents = serializedReevaluateTaskComponents, + TaskData = serializedTaskData.ToArray(), + }; + var variableSaveData = Save(behaviorTree as ISharedVariableContainer); + if (variableSaveData.HasValue) { + behaviorTreeSaveData.GraphSharedVariables = variableSaveData.Value; + } + return behaviorTreeSaveData; + } + + /// + /// Returns the save data associated with the variable container. + /// + /// The variable container that should be saved. + /// The save data associated with the variable container. + private static VariableSaveData? Save(ISharedVariableContainer variableContainer) + { + if (variableContainer == null) { + return null; + } + + var sharedVariables = variableContainer.SharedVariables; + if (sharedVariables == null || sharedVariables.Length == 0) { + return null; + } + + Serialization[] serializedSharedVariablesData = null; + if (sharedVariables != null) { + serializedSharedVariablesData = new Serialization[sharedVariables.Length]; + for (int i = 0; i < sharedVariables.Length; ++i) { + serializedSharedVariablesData[i] = Serialization.Serialize(sharedVariables[i].GetValue(), BehaviorTreeData.ValidateSerializedObject); + } + } + + return new VariableSaveData() { + UniqueID = variableContainer.UniqueID, + Values = serializedSharedVariablesData, + Scope = variableContainer.VariableScope + }; + } + + /// + /// Loads the save data contained within the specified file. + /// + /// The behavior trees that should be loaded. + /// The save data path. + /// Optional callback after the graph variables have been restored. + /// True if at least one behavior tree's save data was loaded. + public static bool Load(BehaviorTree[] behaviorTrees, string filePath, Action afterVariablesRestored = null) + { + if (!Application.isPlaying) { + Debug.LogWarning($"Warning: Behavior trees can only be loaded at runtime."); + return false; + } + + if (!File.Exists(filePath)) { + Debug.LogWarning($"Warning: The file at path {filePath} does not exist."); + return false; + } + + var fileStream = File.Open(filePath, FileMode.Open); + var saveData = new SaveData(); + using (var streamReader = new StreamReader(fileStream)) { + var fileData = streamReader.ReadToEnd(); + saveData = JsonUtility.FromJson(fileData); + } + fileStream.Close(); + + return Load(behaviorTrees, saveData, afterVariablesRestored); + } + + /// + /// Loads the save data. + /// + /// The behavior trees that should be loaded. + /// The loaded save data. + /// Optional callback after the graph variables have been restored. + /// True if at least one behavior tree's save data was loaded. + public static bool Load(BehaviorTree[] behaviorTrees, SaveData saveData, Action afterVariablesRestored = null) + { + // Load the shared variables before the behavior trees so the trees can reference the variables. + var loadedSceneVariables = false; + var loadedProjectVariables = false; + var loadCount = 0; + Dictionary variableSaveDataByID = null; + if (saveData.VariableSaveData != null && saveData.VariableSaveData.Length > 0) { + // The save data is unique to the variable container specified by the unique ID. + for (int i = 0; i < saveData.VariableSaveData.Length; ++i) { + // Remember the scope to determine if the variable scope needs to be checked again when loading. + if (saveData.VariableSaveData[i].Scope == SharedVariable.SharingScope.GameObject) { + // The GameObject SharedVariables will be loaded with the behavior tree. + if (variableSaveDataByID == null) { + variableSaveDataByID = new Dictionary(); + } + variableSaveDataByID.Add(saveData.VariableSaveData[i].UniqueID, saveData.VariableSaveData[i]); + } else if (saveData.VariableSaveData[i].Scope == SharedVariable.SharingScope.Scene) { + // Restore the SceneSharedVariables if it hasn't already been loaded. + if (!loadedSceneVariables) { + if (SceneSharedVariables.Instance != null) { + if (Load(SceneSharedVariables.Instance, saveData.VariableSaveData[i])) { + loadCount++; + } + } + loadedSceneVariables = true; + } + } else if (saveData.VariableSaveData[i].Scope == SharedVariable.SharingScope.Project) { + // Restore the ProjectSharedVariables if it hasn't already been loaded. + if (!loadedProjectVariables) { + if (ProjectSharedVariables.Instance != null) { + if (Load(ProjectSharedVariables.Instance, saveData.VariableSaveData[i])) { + loadCount++; + } + } + } + } + } + } + + if (saveData.BehaviorTreeSaveData != null && saveData.BehaviorTreeSaveData.Length > 0) { + // The save data is unique to the behavior tree specified by the unique ID. + var behaviorTreeSaveDataByID = new Dictionary(); + for (int i = 0; i < saveData.BehaviorTreeSaveData.Length; ++i) { + behaviorTreeSaveDataByID.Add(saveData.BehaviorTreeSaveData[i].UniqueID, saveData.BehaviorTreeSaveData[i]); + } + + // Load the save data for each behavior tree. + for (int i = 0; i < behaviorTrees.Length; ++i) { + var behaviorTree = behaviorTrees[i]; + if (behaviorTreeSaveDataByID.TryGetValue(behaviorTree.UniqueID, out var behaviorTreeSaveData)) { + // Restore the GameObjectSharedVariables if they haven't already been restored. + if (variableSaveDataByID != null) { + var gameObjectSharedVariables = behaviorTree.GetComponent(); + if (gameObjectSharedVariables != null) { + if (variableSaveDataByID.TryGetValue(gameObjectSharedVariables.UniqueID, out var variableSaveData)) { + if (Load(gameObjectSharedVariables, variableSaveData)) { + loadCount++; + } + // Remove the ID after it has been loaded so the variables aren't loaded again. This can happen if multiple + // trees on the same GameObject reference the same GameObject variable. + variableSaveDataByID.Remove(gameObjectSharedVariables.UniqueID); + } + } + } + + // Restore the Graph SharedVariables. + if (Load(behaviorTree, behaviorTreeSaveData.GraphSharedVariables)) { + loadCount++; + } + + // Callback after the variables have been restored. + afterVariablesRestored?.Invoke(behaviorTree); + + // Populate the variables in an internal mapping for quick lookup. + var variableByNameMap = BehaviorTreeData.PopulateSharedVariablesMapping(behaviorTree, true); + + // Restore the tree after the variables have been restored. + if (Load(behaviorTree, behaviorTreeSaveData, afterVariablesRestored, variableByNameMap)) { + loadCount++; + } + } + } + } + + return loadCount > 0; + } + + /// + /// Loads the behavior tree from the specified save data. + /// + /// The behavior tree that should be restored. + /// The save data associated with the behavior tree. + /// Optional callback after the graph variables have been restored. + /// A mapping between the variable name and the variable reference. + /// True if the behavior tree was successfully loaded. + private static bool Load(BehaviorTree behaviorTree, BehaviorTreeSaveData saveData, Action afterVariablesRestored, Dictionary variableByNameMap) + { + // The ID must match. + if (behaviorTree.UniqueID != saveData.UniqueID) { + Debug.LogError($"Error: The behavior tree {behaviorTree.name} cannot be loaded due to being saved in a different version of the behavior tree."); + return false; + } + + // The behavior tree must be initialized in order to be loaded. + if (!behaviorTree.InitializeTree()) { + return false; + } + + // Stop the behavior tree so all tasks issue their end callback. + var enableEntity = behaviorTree.World.EntityManager.HasComponent(behaviorTree.Entity) && behaviorTree.World.EntityManager.IsComponentEnabled(behaviorTree.Entity); + var evaluateEntity = behaviorTree.World.EntityManager.HasComponent(behaviorTree.Entity) && behaviorTree.World.EntityManager.IsComponentEnabled(behaviorTree.Entity); + var active = behaviorTree.IsActive(); + if (active) { + behaviorTree.StopBehavior(); + } + + // Restore the task component status. + var taskComponents = behaviorTree.World.EntityManager.GetBuffer(behaviorTree.Entity); + for (int i = 0; i < saveData.TaskComponents.Length; ++i) { + taskComponents[i] = (TaskComponent)saveData.TaskComponents[i].DeserializeFields(MemberVisibility.Public); + } + + var branchComponents = behaviorTree.World.EntityManager.GetBuffer(behaviorTree.Entity); + // Restore the branch info components. + for (int i = 0; i < saveData.BranchComponents.Length; ++i) { + branchComponents[i] = (BranchComponent)saveData.BranchComponents[i].DeserializeFields(MemberVisibility.Public); + if (branchComponents[i].ActiveFlagComponentType.TypeIndex == TypeIndex.Null) { + continue; + } + behaviorTree.World.EntityManager.SetComponentEnabled(behaviorTree.Entity, branchComponents[i].ActiveFlagComponentType, true); + } + + if (behaviorTree.World.EntityManager.HasBuffer(behaviorTree.Entity)) { + var reevaluatedTaskComponents = behaviorTree.World.EntityManager.GetBuffer(behaviorTree.Entity); + // Restore the reevaluated components. + for (int i = 0; i < saveData.ReevaluateTaskComponents.Length; ++i) { + reevaluatedTaskComponents[i] = (ReevaluateTaskComponent)saveData.ReevaluateTaskComponents[i].DeserializeFields(MemberVisibility.Public); + if (reevaluatedTaskComponents[i].ReevaluateFlagComponentType.TypeIndex == TypeIndex.Null) { + continue; + } + behaviorTree.World.EntityManager.SetComponentEnabled(behaviorTree.Entity, reevaluatedTaskComponents[i].ReevaluateFlagComponentType, true); + } + } + + // Each task can serialize their own data. + var tasks = behaviorTree.LogicNodes; + var saveDataIndex = 0; + ResizableArray taskReferences = null; + for (int i = 0; i < tasks.Length; ++i) { + if (!(tasks[i] is ISavableTask)) { + if (tasks[i] is Task) { + (tasks[i] as Task).Initialize(behaviorTree, (ushort)i); + } + continue; + } + + var taskSaveData = saveData.TaskData[saveDataIndex]; + saveDataIndex++; + if (taskSaveData.Value == null || taskSaveData.Value.Length == 0) { + if (tasks[i] is Task) { + (tasks[i] as Task).Initialize(behaviorTree, (ushort)i); + } + continue; + } + + var saveableTask = tasks[i] as ISavableTask; + var reflectionType = saveableTask.GetSaveReflectionType(-1); + if (reflectionType != MemberVisibility.None) { + taskSaveData.Value[0].DeserializeFields(saveableTask, saveableTask.GetSaveReflectionType(0), BehaviorTreeData.ValidateDeserializedTypeObject, + (object fieldInfoObj, object task, object value) => + { + return BehaviorTreeData.ValidateDeserializedObject(fieldInfoObj, task, value, ref variableByNameMap, ref taskReferences); + }); + } else { + if (taskSaveData.Value.Length == 1) { + if (saveableTask.GetSaveReflectionType(0) != MemberVisibility.None) { + saveableTask.Load(taskSaveData.Value[0], behaviorTree.World, behaviorTree.Entity, variableByNameMap, ref taskReferences); + } else { + saveableTask.Load(taskSaveData.Value[0].DeserializeFields(MemberVisibility.Public, BehaviorTreeData.ValidateDeserializedTypeObject, + (object fieldInfoObj, object task, object value) => + { + return BehaviorTreeData.ValidateDeserializedObject(fieldInfoObj, task, value, ref variableByNameMap, ref taskReferences); + }), behaviorTree.World, behaviorTree.Entity, variableByNameMap, ref taskReferences); + } + } else { + var taskData = new object[taskSaveData.Value.Length]; + for (int j = 0; j < taskSaveData.Value.Length; ++j) { + if (taskSaveData.Value[j] == null) { + continue; + } + + if (saveableTask.GetSaveReflectionType(j) != MemberVisibility.None) { + // The task is responsible for deserializing the fields. + taskData[j] = taskSaveData.Value[j]; + } else { + taskData[j] = taskSaveData.Value[j].DeserializeFields(MemberVisibility.Public, BehaviorTreeData.ValidateDeserializedTypeObject, + (object fieldInfoObj, object task, object value) => + { + return BehaviorTreeData.ValidateDeserializedObject(fieldInfoObj, task, value, ref variableByNameMap, ref taskReferences); + }); + } + } + saveableTask.Load(taskData, behaviorTree.World, behaviorTree.Entity, variableByNameMap, ref taskReferences); + } + } + if (tasks[i] is Task) { + (tasks[i] as Task).Initialize(behaviorTree, (ushort)i); + } + } + + // After the tree has been loaded the task references need to be assigned. + BehaviorTreeData.AssignTaskReferences(behaviorTree.LogicNodes, taskReferences); + + if (active) { + behaviorTree.StartBehavior(); + } + if (enableEntity) { + behaviorTree.World.EntityManager.SetComponentEnabled(behaviorTree.Entity, true); + } + if (evaluateEntity) { + behaviorTree.World.EntityManager.SetComponentEnabled(behaviorTree.Entity, true); + } + + return true; + } + + /// + /// Loads the variable from the specified file path. + /// + /// The variable container that should be restored. + /// The save data associated with the variable container. + /// True if the variable container was successfully loaded. + private static bool Load(ISharedVariableContainer variableContainer, VariableSaveData saveData) + { + // There may not be any variables saved. + if (saveData.UniqueID == 0) { + return false; + } + + // The ID must match. + if (variableContainer.UniqueID != saveData.UniqueID) { + Debug.LogError($"Error: The variables {variableContainer} cannot be loaded due to being saved in a different version of the variable container."); + return false; + } + + var sharedVariables = variableContainer.SharedVariables; + if (sharedVariables != null) { + for (int i = 0; i < saveData.Values.Length; ++i) { + if (saveData.Values[i] == null) { + continue; + } + + var sharedVariableValue = saveData.Values[i].DeserializeFields(MemberVisibility.Public); + sharedVariables[i].SetValue(sharedVariableValue); + } + } + + return true; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Utility/SaveManager.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Utility/SaveManager.cs.meta new file mode 100644 index 0000000..7e9425d --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Utility/SaveManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6c5777d50e5756a4b85d335f81c9d301 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Utility/TraversalUtility.cs b/Packages/com.opsive.behaviordesigner/Runtime/Utility/TraversalUtility.cs new file mode 100644 index 0000000..0cfbb97 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Utility/TraversalUtility.cs @@ -0,0 +1,108 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Utility +{ + using Opsive.BehaviorDesigner.Runtime.Components; + using Unity.Burst; + using Unity.Entities; + + /// + /// Utility functions that are used throughout the behavior tree execution. + /// + [BurstCompile] + public static class TraversalUtility + { + /// + /// Returns true if the specified index is a child of the parent index. + /// + /// The index to determine if it is a child. + /// The index of the parent. + /// The array of nodes. + /// True if the specified index is a child of the parent index. + [BurstCompile] + public static bool IsParent(ushort index, ushort parentIndex, ref DynamicBuffer taskComponents) + { + if (parentIndex == ushort.MaxValue || index == ushort.MaxValue) { + return false; + } + + // The child can be considered a parent of itself. + if (parentIndex == index) { + return true; + } + + // Return true as soon as there is a parent. + while (index != ushort.MaxValue) { + if (index == parentIndex) { + return true; + } + + index = taskComponents[index].ParentIndex; + } + + return false; + } + + /// + /// Returns the total number of children belonging to the specified node. + /// + /// The index of the task to retrieve the child count of. + /// The array of nodes. + /// The total number of children belonging to the specified node. + public static int GetChildCount(int index, ref DynamicBuffer taskComponents) + { + if (index == ushort.MaxValue) { + return 0; + } + + var taskComponent = taskComponents[index]; + if (taskComponent.SiblingIndex != ushort.MaxValue) { + return taskComponent.SiblingIndex - taskComponent.Index - 1; + } + + if (taskComponent.Index + 1 == taskComponents.Length) { + return 0; + } + + var childTaskComponent = taskComponents[taskComponent.Index + 1]; + if (childTaskComponent.ParentIndex != taskComponent.Index) { + return 0; + } + + // Determine the child count based off of the sibling index. + var lastChildTaskComponent = childTaskComponent; + while (childTaskComponent.ParentIndex == taskComponent.Index) { + lastChildTaskComponent = childTaskComponent; + if (childTaskComponent.SiblingIndex == ushort.MaxValue) { + break; + } + childTaskComponent = taskComponents[childTaskComponent.SiblingIndex]; + } + + return lastChildTaskComponent.Index - taskComponent.Index + GetChildCount(lastChildTaskComponent.Index, ref taskComponents); + } + + /// + /// Returns the immediate number of children belonging to the specified task. + /// + /// The task to retrieve the children of. + /// The list of tasks. + /// The number of immediate children belonging to the specified task. + [BurstCompile] + public static int GetImmediateChildCount(ref TaskComponent task, ref DynamicBuffer taskComponents) + { + var count = 0; + var siblingIndex = task.Index + 1; + while (siblingIndex < taskComponents.Length && taskComponents[siblingIndex].ParentIndex == task.Index) { + count++; + siblingIndex = taskComponents[siblingIndex].SiblingIndex; + } + return count; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Utility/TraversalUtility.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Utility/TraversalUtility.cs.meta new file mode 100644 index 0000000..9b59ceb --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Utility/TraversalUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: be274f359e2db764998eb36f2adeaed9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Utility/Types.cs b/Packages/com.opsive.behaviordesigner/Runtime/Utility/Types.cs new file mode 100644 index 0000000..d3906be --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Utility/Types.cs @@ -0,0 +1,42 @@ +#if GRAPH_DESIGNER +/// --------------------------------------------- +/// Behavior Designer +/// Copyright (c) Opsive. All Rights Reserved. +/// https://www.opsive.com +/// --------------------------------------------- +namespace Opsive.BehaviorDesigner.Runtime.Utility +{ + using UnityEngine; + using System; + + /// + /// Specifies a range between two floats. + /// + public struct RangeFloat + { + [Tooltip("The minimal float value (inclusive).")] + [SerializeField] public float Min; + [Tooltip("The maximum float value (inclusive).")] + [SerializeField] public float Max; + + public float RandomValue { get => UnityEngine.Random.Range(Min, Max); } + + /// + /// RangeFloat constructor. + /// + /// The minimal float value. + /// The maximal float value. + public RangeFloat(float min, float max) + { + Min = min; + Max = max; + } + } + + /// + /// Specifies that the task name should be hidden in the node view. + /// + [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)] + public class HideNameInTaskControlAttribute : Attribute { } +} +#endif \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/Runtime/Utility/Types.cs.meta b/Packages/com.opsive.behaviordesigner/Runtime/Utility/Types.cs.meta new file mode 100644 index 0000000..6ef0ed1 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/Runtime/Utility/Types.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9d76db679b119fe4c9359f9b9b0c2869 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.opsive.behaviordesigner/package.json b/Packages/com.opsive.behaviordesigner/package.json new file mode 100644 index 0000000..9310dd6 --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/package.json @@ -0,0 +1,25 @@ +{ + "name": "com.opsive.behaviordesigner", + "version": "2.1.12", + "displayName": "Opsive Behavior Designer", + "description": "A behavior tree implementation based on DOTS.", + "documentationUrl": "https://opsive.com/support/documentation/behavior-designer-pro/", + "author": { + "name": "Opsive", + "email": "support@opsive.com", + "url": "https://opsive.com" + }, + "dependencies": { + "com.opsive.shared": "2.0.0", + "com.opsive.graphdesigner": "2.0.0", + "com.unity.burst": "1.8.17", + "com.unity.entities": "1.3.8" + }, + "samples": [ + { + "displayName": "Sample", + "description": "Sample scenes that show a variety of use cases.", + "path": "Samples~" + } + ] +} \ No newline at end of file diff --git a/Packages/com.opsive.behaviordesigner/package.json.meta b/Packages/com.opsive.behaviordesigner/package.json.meta new file mode 100644 index 0000000..264d86b --- /dev/null +++ b/Packages/com.opsive.behaviordesigner/package.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: af982e6bd82bf7b4893755d01662c156 +PackageManifestImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index 785cdcc..c0592c6 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -15,6 +15,17 @@ "com.unity.modules.animation": "1.0.0" } }, + "com.opsive.behaviordesigner": { + "version": "file:com.opsive.behaviordesigner", + "depth": 0, + "source": "embedded", + "dependencies": { + "com.opsive.shared": "2.0.0", + "com.opsive.graphdesigner": "2.0.0", + "com.unity.burst": "1.8.17", + "com.unity.entities": "1.3.8" + } + }, "com.opsive.graphdesigner": { "version": "file:com.opsive.graphdesigner", "depth": 0, @@ -167,18 +178,42 @@ "url": "https://packages.unity.cn" }, "com.unity.collections": { - "version": "1.2.4", + "version": "2.5.1", "depth": 2, "source": "registry", "dependencies": { - "com.unity.burst": "1.6.6", - "com.unity.test-framework": "1.1.31" + "com.unity.burst": "1.8.17", + "com.unity.nuget.mono-cecil": "1.11.4", + "com.unity.test-framework": "1.4.5", + "com.unity.test-framework.performance": "3.0.3" + }, + "url": "https://packages.unity.cn" + }, + "com.unity.entities": { + "version": "1.3.8", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.burst": "1.8.18", + "com.unity.collections": "2.5.1", + "com.unity.mathematics": "1.3.2", + "com.unity.modules.audio": "1.0.0", + "com.unity.serialization": "3.1.1", + "com.unity.profiling.core": "1.0.2", + "com.unity.modules.physics": "1.0.0", + "com.unity.nuget.mono-cecil": "1.11.4", + "com.unity.modules.uielements": "1.0.0", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.unityanalytics": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.scriptablebuildpipeline": "1.21.21", + "com.unity.test-framework.performance": "3.0.3" }, "url": "https://packages.unity.cn" }, "com.unity.ext.nunit": { - "version": "1.0.6", - "depth": 1, + "version": "2.0.3", + "depth": 4, "source": "registry", "dependencies": {}, "url": "https://packages.unity.cn" @@ -226,8 +261,15 @@ "url": "https://packages.unity.cn" }, "com.unity.mathematics": { - "version": "1.2.6", - "depth": 1, + "version": "1.3.2", + "depth": 2, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.cn" + }, + "com.unity.nuget.mono-cecil": { + "version": "1.11.4", + "depth": 2, "source": "registry", "dependencies": {}, "url": "https://packages.unity.cn" @@ -239,6 +281,13 @@ "dependencies": {}, "url": "https://packages.unity.cn" }, + "com.unity.profiling.core": { + "version": "1.0.2", + "depth": 2, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.cn" + }, "com.unity.render-pipelines.core": { "version": "14.0.12", "depth": 1, @@ -284,6 +333,16 @@ "dependencies": {}, "url": "https://packages.unity.cn" }, + "com.unity.serialization": { + "version": "3.1.1", + "depth": 2, + "source": "registry", + "dependencies": { + "com.unity.collections": "2.1.4", + "com.unity.burst": "1.7.2" + }, + "url": "https://packages.unity.cn" + }, "com.unity.settings-manager": { "version": "2.1.0", "depth": 2, @@ -312,16 +371,26 @@ "url": "https://packages.unity.cn" }, "com.unity.test-framework": { - "version": "1.1.33", - "depth": 0, + "version": "1.4.5", + "depth": 3, "source": "registry", "dependencies": { - "com.unity.ext.nunit": "1.0.6", + "com.unity.ext.nunit": "2.0.3", "com.unity.modules.imgui": "1.0.0", "com.unity.modules.jsonserialize": "1.0.0" }, "url": "https://packages.unity.cn" }, + "com.unity.test-framework.performance": { + "version": "3.0.3", + "depth": 2, + "source": "registry", + "dependencies": { + "com.unity.test-framework": "1.1.31", + "com.unity.modules.jsonserialize": "1.0.0" + }, + "url": "https://packages.unity.cn" + }, "com.unity.textmeshpro": { "version": "3.0.9", "depth": 0, diff --git a/zeling_v2.sln b/zeling_v2.sln index 7ef6349..e509af5 100644 --- a/zeling_v2.sln +++ b/zeling_v2.sln @@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Micosmo.SensorToolkit", "Mi EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kybernetik.Animancer", "Kybernetik.Animancer.csproj", "{EB7355A3-BDAA-C485-B7C1-9B903FA5AD60}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Opsive.BehaviorDesigner.Runtime", "Opsive.BehaviorDesigner.Runtime.csproj", "{AB534E4D-E307-E5F5-29A3-E636CA9EA9B7}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaseGames.Equipment", "BaseGames.Equipment.csproj", "{5D5E5DE0-4DD3-2C37-6721-825F717F5BB3}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kybernetik.Animancer.Editor", "Kybernetik.Animancer.Editor.csproj", "{651ACFAE-F0CD-6ABB-E0CE-10529F18B4DB}" @@ -51,6 +53,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaseGames.Player", "BaseGam EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaseGames.Audio", "BaseGames.Audio.csproj", "{F9D314BA-E5AD-4A05-04AB-93799B5E95AE}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Opsive.BehaviorDesigner.Editor.Managers", "Opsive.BehaviorDesigner.Editor.Managers.csproj", "{14945582-FEE1-FBE7-F2F4-63A8E55E6EB6}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaseGames.Parry", "BaseGames.Parry.csproj", "{CFD59BED-321E-6F34-65CA-408816F768FA}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaseGames.Quest", "BaseGames.Quest.csproj", "{4D3050DE-F729-61B6-5E21-4D4D1BAA9DD5}" @@ -75,6 +79,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Opsive.GraphDesigner.Runtim EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaseGames.EventChain", "BaseGames.EventChain.csproj", "{E66CCC51-3F0E-5321-D038-01CE529A5818}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Opsive.BehaviorDesigner.Editor.Controls.NodeViews", "Opsive.BehaviorDesigner.Editor.Controls.NodeViews.csproj", "{8BAE8B7D-DF32-F95B-4854-25895C8AF89E}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaseGames.Combat", "BaseGames.Combat.csproj", "{8BEFFA97-0E4E-2B59-7C2F-634A5BA5B0E5}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaseGames.Tests.PlayMode", "BaseGames.Tests.PlayMode.csproj", "{E3F8AFC1-C10D-B715-91EF-4AD9F9B46B1F}" @@ -135,6 +141,10 @@ Global {EB7355A3-BDAA-C485-B7C1-9B903FA5AD60}.Debug|Any CPU.Build.0 = Debug|Any CPU {EB7355A3-BDAA-C485-B7C1-9B903FA5AD60}.Release|Any CPU.ActiveCfg = Release|Any CPU {EB7355A3-BDAA-C485-B7C1-9B903FA5AD60}.Release|Any CPU.Build.0 = Release|Any CPU + {AB534E4D-E307-E5F5-29A3-E636CA9EA9B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AB534E4D-E307-E5F5-29A3-E636CA9EA9B7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AB534E4D-E307-E5F5-29A3-E636CA9EA9B7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AB534E4D-E307-E5F5-29A3-E636CA9EA9B7}.Release|Any CPU.Build.0 = Release|Any CPU {5D5E5DE0-4DD3-2C37-6721-825F717F5BB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5D5E5DE0-4DD3-2C37-6721-825F717F5BB3}.Debug|Any CPU.Build.0 = Debug|Any CPU {5D5E5DE0-4DD3-2C37-6721-825F717F5BB3}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -223,6 +233,10 @@ Global {F9D314BA-E5AD-4A05-04AB-93799B5E95AE}.Debug|Any CPU.Build.0 = Debug|Any CPU {F9D314BA-E5AD-4A05-04AB-93799B5E95AE}.Release|Any CPU.ActiveCfg = Release|Any CPU {F9D314BA-E5AD-4A05-04AB-93799B5E95AE}.Release|Any CPU.Build.0 = Release|Any CPU + {14945582-FEE1-FBE7-F2F4-63A8E55E6EB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {14945582-FEE1-FBE7-F2F4-63A8E55E6EB6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {14945582-FEE1-FBE7-F2F4-63A8E55E6EB6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {14945582-FEE1-FBE7-F2F4-63A8E55E6EB6}.Release|Any CPU.Build.0 = Release|Any CPU {CFD59BED-321E-6F34-65CA-408816F768FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CFD59BED-321E-6F34-65CA-408816F768FA}.Debug|Any CPU.Build.0 = Debug|Any CPU {CFD59BED-321E-6F34-65CA-408816F768FA}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -271,6 +285,10 @@ Global {E66CCC51-3F0E-5321-D038-01CE529A5818}.Debug|Any CPU.Build.0 = Debug|Any CPU {E66CCC51-3F0E-5321-D038-01CE529A5818}.Release|Any CPU.ActiveCfg = Release|Any CPU {E66CCC51-3F0E-5321-D038-01CE529A5818}.Release|Any CPU.Build.0 = Release|Any CPU + {8BAE8B7D-DF32-F95B-4854-25895C8AF89E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8BAE8B7D-DF32-F95B-4854-25895C8AF89E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8BAE8B7D-DF32-F95B-4854-25895C8AF89E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8BAE8B7D-DF32-F95B-4854-25895C8AF89E}.Release|Any CPU.Build.0 = Release|Any CPU {8BEFFA97-0E4E-2B59-7C2F-634A5BA5B0E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8BEFFA97-0E4E-2B59-7C2F-634A5BA5B0E5}.Debug|Any CPU.Build.0 = Debug|Any CPU {8BEFFA97-0E4E-2B59-7C2F-634A5BA5B0E5}.Release|Any CPU.ActiveCfg = Release|Any CPU