// Picks a theme from the list that has a definition for the defined socket protected DungeonPropDataAsset GetBestMatchedTheme(List <DungeonPropDataAsset> Themes, PropSocket socket, PropBySocketTypeByTheme_t PropBySocketTypeByTheme) { var ValidThemes = new List <DungeonPropDataAsset>(); foreach (DungeonPropDataAsset Theme in Themes) { if (PropBySocketTypeByTheme.ContainsKey(Theme)) { PropBySocketType_t PropBySocketType = PropBySocketTypeByTheme[Theme]; if (PropBySocketType.Count > 0) { if (PropBySocketType.ContainsKey(socket.SocketType) && PropBySocketType[socket.SocketType].Count > 0) { ValidThemes.Add(Theme); } } } } if (ValidThemes.Count == 0) { return(null); } int index = Mathf.FloorToInt(random.GetNextUniformFloat() * ValidThemes.Count) % ValidThemes.Count; return(ValidThemes[index]); }
protected void CreatePropLookup(DungeonPropDataAsset PropAsset, PropBySocketTypeByTheme_t PropBySocketTypeByTheme) { if (PropAsset == null || PropBySocketTypeByTheme.ContainsKey(PropAsset)) { // Lookup for this theme has already been built return; } PropBySocketType_t PropBySocketType = new PropBySocketType_t(); PropBySocketTypeByTheme.Add(PropAsset, PropBySocketType); foreach (PropTypeData Prop in PropAsset.Props) { if (!PropBySocketType.ContainsKey(Prop.AttachToSocket)) { PropBySocketType.Add(Prop.AttachToSocket, new List <PropTypeData>()); } PropBySocketType[Prop.AttachToSocket].Add(Prop); } }
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); } }
public virtual void ApplyTheme(List <DungeonPropDataAsset> Themes, DungeonSceneProvider SceneProvider) { var instanceCache = new InstanceCache(); var constraintProcessor = GetComponent <SpatialConstraintProcessor>(); if (constraintProcessor != null) { constraintProcessor.Initialize(model, propSockets); } 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 themeOverride in themeOverrides) { if (themeOverride.dungeon != dungeon) { continue; } overrideVolumes.Add(themeOverride); var graph = themeOverride.overrideTheme; if (graph != null && !GraphToThemeMapping.ContainsKey(graph)) { DungeonPropDataAsset theme = new DungeonPropDataAsset(); theme.BuildFromGraph(themeOverride.overrideTheme); GraphToThemeMapping.Add(themeOverride.overrideTheme, theme); CreatePropLookup(theme, PropBySocketTypeByTheme); } } var srandom = new PMRandom(config.Seed); // Fill up the prop sockets with the defined mesh data for (int i = 0; i < PropSockets.Count; i++) { PropSocket socket = PropSockets[i]; 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) { continue; } PropBySocketType_t PropBySocketType = PropBySocketTypeByTheme[ThemeToUse]; if (PropBySocketType.ContainsKey(socket.SocketType)) { List <PropTypeData> props = PropBySocketType[socket.SocketType]; foreach (PropTypeData prop in props) { bool insertMesh = false; Matrix4x4 transform = socket.Transform * prop.Offset; if (prop.UseSelectionRule && prop.SelectorRuleClassName != null) { var selectorRule = instanceCache.GetInstance(prop.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 = srandom.GetNextUniformFloat(); insertMesh = (probability < prop.Affinity); } if (insertMesh && prop.useSpatialConstraint && prop.spatialConstraint != null) { Matrix4x4 spatialOffset; if (!ProcessSpatialConstraint(constraintProcessor, prop.spatialConstraint, socket, out spatialOffset)) { // Fails spatial constraint insertMesh = false; } else { // Apply the offset var markerOffset = socket.Transform; if (prop.spatialConstraint != null && !prop.spatialConstraint.applyMarkerRotation) { var markerPosition = Matrix.GetTranslation(ref markerOffset); var markerScale = Matrix.GetScale(ref markerOffset); markerOffset = Matrix4x4.TRS(markerPosition, Quaternion.identity, markerScale); } transform = markerOffset * spatialOffset * prop.Offset; } } if (insertMesh) { // Attach this prop to the socket // Apply transformation logic, if specified if (prop.UseTransformRule && prop.TransformRuleClassName != null && prop.TransformRuleClassName.Length > 0) { var transformer = instanceCache.GetInstance(prop.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; } } if (prop is GameObjectPropTypeData) { var gameObjectProp = prop as GameObjectPropTypeData; SceneProvider.AddGameObject(gameObjectProp, transform); } else if (prop is GameObjectArrayPropTypeData) { var gameObjectArrayProp = prop as GameObjectArrayPropTypeData; int count = gameObjectArrayProp.Templates.Length; int index = Mathf.FloorToInt(random.GetNextUniformFloat() * count) % count; SceneProvider.AddGameObjectFromArray(gameObjectArrayProp, index, transform); } else if (prop is SpritePropTypeData) { var spriteProp = prop as SpritePropTypeData; SceneProvider.AddSprite(spriteProp, transform); } // TODO: Handle light creation // Add child sockets if any foreach (PropChildSocketData ChildSocket in prop.ChildSockets) { Matrix4x4 childTransform = transform * ChildSocket.Offset; EmitMarker(ChildSocket.SocketType, childTransform, socket.gridPosition, socket.cellId); } if (prop.ConsumeOnAttach) { // Attach no more on this socket break; } } } } } if (constraintProcessor != null) { constraintProcessor.Cleanup(); } }