protected void ProcessMarkerOverrideVolumes() { var dungeon = GetComponent <Dungeon>(); // Process the theme override volumes var replacementVolumes = GameObject.FindObjectsOfType <MarkerReplaceVolume>(); foreach (var replacementVolume in replacementVolumes) { if (replacementVolume.dungeon == dungeon) { // Fill up the prop sockets with the defined mesh data for (int i = 0; i < propSockets.Count; i++) { PropSocket socket = propSockets[i]; var socketPosition = Matrix.GetTranslation(ref socket.Transform); if (replacementVolume.GetBounds().Contains(socketPosition)) { foreach (var replacementEntry in replacementVolume.replacements) { if (socket.SocketType == replacementEntry.fromMarker) { socket.SocketType = replacementEntry.toMarker; } } } } } } }
public static void DrawMarker(PropSocket marker, Color color) { var start = Matrix.GetTranslation(ref marker.Transform); var end = start + new Vector3(0, 0.2f, 0); Debug.DrawLine(start, end, color); }
public override void Remove(PropSocket marker) { base.Remove(marker); var partitionCoord = GetBucketCoord(marker); if (buckets.ContainsKey(partitionCoord)) { buckets[partitionCoord].Remove(marker); } }
public override void Add(PropSocket marker) { base.Add(marker); var partitionCoord = GetBucketCoord(marker); if (!buckets.ContainsKey(partitionCoord)) { buckets.Add(partitionCoord, new List <PropSocket>()); } buckets[partitionCoord].Add(marker); }
void RecursivelyTagMarkerForDeletion(PropSocket marker, HashSet <int> visited) { visited.Add(marker.Id); marker.markForDeletion = true; foreach (var childMarker in marker.childMarkers) { if (!visited.Contains(childMarker.Id)) { RecursivelyTagMarkerForDeletion(childMarker, visited); } } }
protected void EmitMarker(List <PropSocket> pPropSockets, string SocketType, Matrix4x4 transform, IntVector gridPosition, int cellId) { PropSocket socket = new PropSocket(); socket.Id = ++_SocketIdCounter; socket.IsConsumed = false; socket.SocketType = SocketType; socket.Transform = transform; socket.gridPosition = gridPosition; socket.cellId = cellId; pPropSockets.Add(socket); }
public PropSocket EmitMarker(string SocketType, Matrix4x4 transform, IntVector gridPosition, int cellId) { PropSocket socket = new PropSocket(); socket.Id = ++_SocketIdCounter; socket.IsConsumed = false; socket.SocketType = SocketType; socket.Transform = transform; socket.gridPosition = gridPosition; socket.cellId = cellId; PropSockets.Add(socket); return(socket); }
protected virtual bool ProcessSpatialConstraint(SpatialConstraintProcessor constraintProcessor, SpatialConstraintAsset constraint, PropSocket socket, out Matrix4x4 OutOffset, out PropSocket[] outMarkersToRemove) { if (constraintProcessor == null) { OutOffset = Matrix4x4.identity; outMarkersToRemove = new PropSocket[0]; return(false); } var context = new SpatialConstraintProcessorContext(); context.constraintAsset = constraint; context.marker = socket; context.model = model; context.config = config; context.builder = this; context.levelMarkers = propSockets; return(constraintProcessor.ProcessSpatialConstraint(context, out OutOffset, out outMarkersToRemove)); }
/// <summary> /// Implementations should override this and determine if the node should be selected (inserted into the scene) /// </summary> /// <param name="socket">The marker data-structure</param> /// <param name="propTransform">The combined transform of the visual node that invoked this rule</param> /// <param name="model">The dungeon model</param> /// <param name="random">The random stream used by the builder. User this random stream for any randomness for consistancy</param> /// <returns></returns> public virtual bool CanSelect(PropSocket socket, Matrix4x4 propTransform, DungeonModel model, System.Random random) { return(true); }
IntVector2 GetBucketCoord(PropSocket marker) { var position = Matrix.GetTranslation(ref marker.Transform); return(GetBucketCoord(position.x, position.z)); }
/// <summary> /// Implement this method to provide a transform based on your logic. /// </summary> /// <param name="socket">The marker data structure</param> /// <param name="model">The dungeon model</param> /// <param name="propTransform">The combined transform of the visual node that invoked this rule</param> /// <param name="random">The random stream used by the builder. User this random stream for any randomness for consistancy</param> /// <param name="outPosition">Set your position offset here</param> /// <param name="outRotation">Set your rotation offset here</param> /// <param name="outScale">Set your scale offset here</param> public virtual void GetTransform(PropSocket socket, DungeonModel model, Matrix4x4 propTransform, System.Random random, out Vector3 outPosition, out Quaternion outRotation, out Vector3 outScale) { outPosition = Vector3.zero; outRotation = Quaternion.identity; outScale = Vector3.one; }
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); } }
// 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]); }
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(); } }
protected virtual bool ProcessSpatialConstraint(SpatialConstraintProcessor constraintProcessor, SpatialConstraint constraint, PropSocket socket, out Matrix4x4 OutOffset) { if (constraintProcessor == null) { OutOffset = Matrix4x4.identity; return(false); } return(constraintProcessor.ProcessSpatialConstraint(constraint, socket, model, propSockets, out OutOffset)); }