void ExecuteNodesUnderMarker(NodeListExecutionData data, NodeListExecutionContext context, List <NodeSpawnData> spawnDataList) { var socket = data.socket; var nodeDataList = data.nodeDataList; foreach (PropTypeData nodeData in nodeDataList) { bool insertMesh = false; Matrix4x4 transform = socket.Transform * nodeData.Offset; if (nodeData.UseSelectionRule && nodeData.SelectorRuleClassName != null) { var selectorRule = context.instanceCache.GetInstance(nodeData.SelectorRuleClassName) as SelectorRule; if (selectorRule != null) { // Run the selection rule logic to determine if we need to insert this mesh in the scene insertMesh = selectorRule.CanSelect(socket, transform, model, random.UniformRandom); } } else { // Perform probability based selection logic float probability = context.srandom.GetNextUniformFloat(); insertMesh = (probability < nodeData.Affinity); } if (insertMesh && nodeData.useSpatialConstraint && nodeData.spatialConstraint != null) { Matrix4x4 spatialOffset; PropSocket[] markersToRemove; if (!ProcessSpatialConstraint(context.constraintProcessor, nodeData.spatialConstraint, socket, out spatialOffset, out markersToRemove)) { // Fails spatial constraint insertMesh = false; } else { // Apply the offset var markerOffset = socket.Transform; if (nodeData.spatialConstraint != null && !nodeData.spatialConstraint.applyMarkerRotation) { var markerPosition = Matrix.GetTranslation(ref markerOffset); var markerScale = Matrix.GetScale(ref markerOffset); markerOffset = Matrix4x4.TRS(markerPosition, Quaternion.identity, markerScale); } transform = markerOffset * spatialOffset * nodeData.Offset; foreach (var markerToRemove in markersToRemove) { markerToRemove.markForDeletion = true; } } } if (insertMesh) { // Attach this prop to the socket // Apply transformation logic, if specified if (nodeData.UseTransformRule && nodeData.TransformRuleClassName != null && nodeData.TransformRuleClassName.Length > 0) { var transformer = context.instanceCache.GetInstance(nodeData.TransformRuleClassName) as TransformationRule; if (transformer != null) { Vector3 _position, _scale; Quaternion _rotation; transformer.GetTransform(socket, model, transform, random.UniformRandom, out _position, out _rotation, out _scale); var offset = Matrix4x4.TRS(_position, _rotation, _scale); transform = transform * offset; } } // Create a spawn request var spawnData = new NodeSpawnData(); spawnData.nodeData = nodeData; spawnData.transform = transform; spawnData.socket = socket; spawnDataList.Add(spawnData); // Add child sockets if any foreach (PropChildSocketData ChildSocket in nodeData.ChildSockets) { Matrix4x4 childTransform = transform * ChildSocket.Offset; var childMarker = EmitMarker(ChildSocket.SocketType, childTransform, socket.gridPosition, socket.cellId); data.socket.childMarkers.Add(childMarker); } if (nodeData.ConsumeOnAttach) { // Attach no more on this socket break; } } } }
public virtual void ApplyTheme(List <DungeonPropDataAsset> Themes, DungeonSceneProvider SceneProvider, IDungeonSceneObjectInstantiator objectInstantiator) { var instanceCache = new InstanceCache(); var constraintProcessor = GetComponent <SpatialConstraintProcessor>(); PropBySocketTypeByTheme_t PropBySocketTypeByTheme = new PropBySocketTypeByTheme_t(); foreach (DungeonPropDataAsset Theme in Themes) { CreatePropLookup(Theme, PropBySocketTypeByTheme); } // Collect all the theme override volumes and prepare their theme lookup var overrideVolumes = new List <ThemeOverrideVolume>(); Dictionary <Graph, DungeonPropDataAsset> GraphToThemeMapping = new Dictionary <Graph, DungeonPropDataAsset>(); var dungeon = GetComponent <Dungeon>(); // Process the theme override volumes var themeOverrides = GameObject.FindObjectsOfType <ThemeOverrideVolume>(); foreach (var volume in themeOverrides) { if (volume.dungeon != dungeon) { continue; } overrideVolumes.Add(volume); var graph = volume.overrideTheme; if (graph != null && !GraphToThemeMapping.ContainsKey(graph)) { DungeonPropDataAsset theme = new DungeonPropDataAsset(); theme.BuildFromGraph(volume.overrideTheme); GraphToThemeMapping.Add(volume.overrideTheme, theme); CreatePropLookup(theme, PropBySocketTypeByTheme); } } var srandom = new PMRandom(config.Seed); var nodesExecutionContext = new NodeListExecutionContext(); nodesExecutionContext.instanceCache = instanceCache; nodesExecutionContext.constraintProcessor = constraintProcessor; nodesExecutionContext.srandom = srandom; nodesExecutionContext.SceneProvider = SceneProvider; nodesExecutionContext.objectInstantiator = objectInstantiator; var spawnDataList = new List <NodeSpawnData>(); var delayedExecutionList = new Queue <NodeListExecutionData>(); // Fill up the prop sockets with the defined mesh data for (int i = 0; i < PropSockets.Count; i++) { PropSocket socket = PropSockets[i]; if (!socket.markForDeletion) { DungeonPropDataAsset themeToUse = GetBestMatchedTheme(Themes, socket, PropBySocketTypeByTheme); // PropAsset; // Check if this socket resides within a override volume { var socketPosition = Matrix.GetTranslation(ref socket.Transform); foreach (var volume in overrideVolumes) { if (volume.GetBounds().Contains(socketPosition)) { var graph = volume.overrideTheme; if (graph != null && GraphToThemeMapping.ContainsKey(graph)) { themeToUse = GraphToThemeMapping[volume.overrideTheme]; break; } } } } if (themeToUse != null) { PropBySocketType_t PropBySocketType = PropBySocketTypeByTheme[themeToUse]; if (PropBySocketType.ContainsKey(socket.SocketType)) { var data = new NodeListExecutionData(); data.socket = socket; data.nodeDataList = PropBySocketType[socket.SocketType]; if (ShouldDelayExecution(data.nodeDataList)) { delayedExecutionList.Enqueue(data); } else { ExecuteNodesUnderMarker(data, nodesExecutionContext, spawnDataList); } } } } // We execute the delayed node list (that have spatial constraints) at the very end of the list // Each execution of the delayed node however, can add more items to this list bool isLastIndex = (i == PropSockets.Count - 1); while (isLastIndex && delayedExecutionList.Count > 0) { var data = delayedExecutionList.Dequeue(); if (!data.socket.markForDeletion) { ExecuteNodesUnderMarker(data, nodesExecutionContext, spawnDataList); } isLastIndex = (i == PropSockets.Count - 1); } } RecursivelyTagMarkersForDeletion(); // Spawn the items foreach (var spawnData in spawnDataList) { if (spawnData.socket.markForDeletion) { continue; } SpawnNodeItem(spawnData, nodesExecutionContext); } }