public void Build(IDungeonSceneObjectInstantiator objectInstantiator) { NotifyPreBuild(); Initialize(); dungeonModel.ResetModel(); dungeonBuilder.BuildDungeon(config, dungeonModel); markers = dungeonBuilder.PropSockets; NotifyPostLayoutBuild(); if (dungeonBuilder.IsThemingSupported()) { ReapplyTheme(objectInstantiator); } else { dungeonBuilder.BuildNonThemedDungeon(sceneProvider, objectInstantiator); } // Build the navigation var navigation = GetComponent <DungeonRuntimeNavigation>(); if (navigation != null) { navigation.BuildNavMesh(); } NotifyPostBuild(); }
/// <summary> /// Runs the theming engine over the existing layout to rebuild the game objects from the theme file. /// The layout is not built in this stage /// </summary> public void ReapplyTheme(IDungeonSceneObjectInstantiator objectInstantiator) { // Emit markers defined by this builder dungeonBuilder.EmitMarkers(); // Emit markers defined by the users (by attaching implementation of DungeonMarkerEmitter behaviors) dungeonBuilder.EmitCustomMarkers(); NotifyMarkersEmitted(dungeonBuilder.PropSockets); var themes = GetThemeAssets(); sceneProvider.OnDungeonBuildStart(); dungeonBuilder.ApplyTheme(themes, sceneProvider, objectInstantiator); sceneProvider.OnDungeonBuildStop(); }
// This is called by the builders that do not support theming public virtual void BuildNonThemedDungeon(DungeonSceneProvider sceneProvider, IDungeonSceneObjectInstantiator objectInstantiator) { }
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 override GameObject AddSprite(SpritePropTypeData spriteProp, Matrix4x4 transform, IDungeonSceneObjectInstantiator objectInstantiator) { if (spriteProp == null) { return(null); } string NodeId = spriteProp.NodeId; if (spriteProp.sprite == null) { return(null); } FlipSpriteTransform(ref transform, spriteProp.sprite); GameObject item = null; // Try to reuse an object from the pool if (pooledObjects.ContainsKey(NodeId) && pooledObjects [NodeId].Count > 0) { item = pooledObjects [NodeId].Dequeue(); SetTransform(item.transform, transform); } else { // Pool is exhausted for this object item = BuildSpriteObject(spriteProp, transform, NodeId); } item.isStatic = spriteProp.IsStaticObject; return(item); }
public override GameObject AddGameObjectFromArray(GameObjectArrayPropTypeData gameObjectArrayProp, int index, Matrix4x4 transform, IDungeonSceneObjectInstantiator objectInstantiator) { if (gameObjectArrayProp == null) { return(null); } string NodeId = gameObjectArrayProp.NodeId + "_" + index.ToString(); // If we are in 2D mode, then flip the YZ axis { var mode2D = false; if (config != null) { mode2D = config.Mode2D; } if (mode2D) { var position = Matrix.GetTranslation(ref transform); FlipSpritePosition(ref position); Matrix.SetTranslation(ref transform, position); } } GameObject item = null; // Try to reuse an object from the pool if (pooledObjects.ContainsKey(NodeId) && pooledObjects [NodeId].Count > 0) { item = pooledObjects [NodeId].Dequeue(); SetTransform(item.transform, transform); } else { // Pool is exhausted for this object item = BuildGameObjectFromArray(gameObjectArrayProp, index, transform, objectInstantiator); } item.isStatic = gameObjectArrayProp.IsStaticObject; if (gameObjectArrayProp.IsStaticObject) { RecursivelySetStatic(item.transform); } return(item); }
protected GameObject BuildGameObject(GameObjectPropTypeData gameObjectProp, Matrix4x4 transform, IDungeonSceneObjectInstantiator objectInstantiator) { return(BuildGameObject(gameObjectProp.Template, gameObjectProp.NodeId, gameObjectProp.affectsNavigation, transform, objectInstantiator)); }
/// <summary> /// Request the creation of a sprite object /// </summary> /// <param name="spriteProp">The sprite game object template reference</param> /// <param name="transform">The transform of the prop</param> public virtual GameObject AddSprite(SpritePropTypeData spriteProp, Matrix4x4 transform, IDungeonSceneObjectInstantiator objectInstantiator) { return(null); }
/// <summary> /// Requests the creation of a game object from the provided list /// </summary> /// <returns>The game object from array.</returns> /// <param name="gameObjectArrayProp">Game object array property.</param> /// <param name="index">Index.</param> /// <param name="transform">Transform.</param> public virtual GameObject AddGameObjectFromArray(GameObjectArrayPropTypeData gameObjectArrayProp, int index, Matrix4x4 transform, IDungeonSceneObjectInstantiator objectInstantiator) { return(null); }
protected GameObject BuildGameObject(GameObject template, string nodeId, bool affectsNavigation, Matrix4x4 transform, IDungeonSceneObjectInstantiator objectInstantiator) { Matrix.DecomposeMatrix(ref transform, out _position, out _rotation, out _scale); var MeshTemplate = template; string NodeId = nodeId; var gameObj = objectInstantiator.Instantiate(MeshTemplate, _position, _rotation, _scale); /* * var gameObj = Instantiate(MeshTemplate) as GameObject; * gameObj.transform.position = _position; * gameObj.transform.rotation = _rotation; * gameObj.transform.localScale = _scale; */ if (itemParent != null) { gameObj.transform.parent = itemParent.transform; } var data = gameObj.AddComponent <DungeonSceneProviderData> (); data.NodeId = NodeId; data.dungeon = dungeon; data.affectsNavigation = affectsNavigation; return(gameObj); }
protected GameObject BuildGameObjectFromArray(GameObjectArrayPropTypeData gameObjectArrayProp, int index, Matrix4x4 transform, IDungeonSceneObjectInstantiator objectInstantiator) { if (index < 0 || index >= gameObjectArrayProp.Templates.Length) { // Invalid index return(null); } GameObject template = gameObjectArrayProp.Templates[index]; return(BuildGameObject(template, gameObjectArrayProp.NodeId, gameObjectArrayProp.affectsNavigation, transform, objectInstantiator)); }
// This is called by the builders that do not support theming public override void BuildNonThemedDungeon(DungeonSceneProvider sceneProvider, IDungeonSceneObjectInstantiator objectInstantiator) { random = new System.Random((int)config.Seed); propSockets.Clear(); // We know that the dungeon prefab would have the appropriate config and models attached to it // Cast and save it for future reference snapConfig = config as SnapConfig; snapModel = model as SnapModel; if (snapConfig == null) { Debug.LogError("No snap config script found in dungeon game object"); return; } if (snapModel == null) { Debug.LogError("No snap model script found in dungeon game object"); return; } // Generate the module info list var ModuleInfos = new List <ModuleInfo>(); { var RegisteredModuleList = new List <GameObject>(); RegisteredModuleList.AddRange(snapConfig.Modules); RegisteredModuleList.AddRange(snapConfig.StartModules); RegisteredModuleList.AddRange(snapConfig.EndModules); RegisteredModuleList.AddRange(snapConfig.BranchEndModules); var RegisteredModules = new HashSet <GameObject>(RegisteredModuleList); foreach (var RegisteredModule in RegisteredModules) { var moduleInfo = GenerateModuleInfo(RegisteredModule); ModuleInfos.Add(moduleInfo); } } var StartNode = new ModuleGrowthNode(); StartNode.IncomingModuleDoorIndex = -1; StartNode.startNode = true; StartNode.ModuleTransform = Matrix4x4.identity; var OccupiedBounds = new List <Bounds>(); var LayoutBuildState = new SnapLayoutBuildState(); LayoutBuildState.ModuleInfoList = ModuleInfos; // Build the main branch ModuleBuildNode BuildNode = BuildLayoutRecursive(StartNode, OccupiedBounds, 1, snapConfig.MainBranchSize, true, false, LayoutBuildState); // Build the side branches { var MainBranchNodes = new List <ModuleBuildNode>(); // Grab the nodes in the main branch { ModuleBuildNode BranchNode = BuildNode; while (BranchNode != null) { BranchNode.bMainBranch = true; MainBranchNodes.Add(BranchNode); // Move forward if (BranchNode.Extensions.Count == 0) { break; } BranchNode = BranchNode.Extensions[0]; } } // Iterate through the nodes in the main branch and start branching out for (int i = 0; i < MainBranchNodes.Count; i++) { ModuleBuildNode BranchStartNode = MainBranchNodes[i]; ModuleBuildNode BranchNextNode = i + 1 < MainBranchNodes.Count ? MainBranchNodes[i + 1] : null; ModuleInfo BranchModule = BranchStartNode.Module; int IncomingDoorIndex = BranchStartNode.IncomingDoorIndex; int OutgoingDoorIndex = BranchNextNode != null ? BranchNextNode.IncomingDoorIndex : -1; int NumDoors = BranchModule.ConnectionTransforms.Length; for (int DoorIndex = 0; DoorIndex < NumDoors; DoorIndex++) { if (DoorIndex == IncomingDoorIndex || DoorIndex == OutgoingDoorIndex) { // These doors are already extended continue; } bool bGrowFromHere = (random.NextFloat() < snapConfig.SideBranchProbability); if (!bGrowFromHere) { continue; } // TODO: Optimize me. it recalculates the the bounds for the whole tree for every main branch node OccupiedBounds.Clear(); CalculateOccupiedBounds(BuildNode, OccupiedBounds); var BranchGrowNode = new ModuleGrowthNode(); BranchGrowNode.IncomingModuleDoorIndex = DoorIndex; BranchGrowNode.IncomingModule = BranchStartNode.Module; BranchGrowNode.ModuleTransform = BranchStartNode.AttachmentConfig.AttachedModuleTransform; LayoutBuildState = new SnapLayoutBuildState(); LayoutBuildState.ModuleInfoList = ModuleInfos; ModuleBuildNode BranchBuildNode = BuildLayoutRecursive(BranchGrowNode, OccupiedBounds, 1, snapConfig.SideBranchSize, false, false, LayoutBuildState); if (BranchBuildNode != null) { // Make sure we don't end up with an undesirable leaf node if (BranchBuildNode.Extensions.Count == 0 && BranchBuildNode.Module != null && snapConfig.SideBranchSize > 1) { continue; } BranchBuildNode.Parent = BranchStartNode; BranchStartNode.Extensions.Add(BranchBuildNode); } } } } snapModel.ResetModel(); sceneProvider.OnDungeonBuildStart(); // Spawn the modules and register them in the model { var spawnedModuleList = new List <SnapModuleInstance>(); TraverseTree(BuildNode, delegate(ModuleBuildNode Node) { // Spawn a module at this location ModuleInfo moduleInfo = Node.Module; var templateInfo = new GameObjectPropTypeData(); templateInfo.Template = moduleInfo.ModuleTemplate; templateInfo.NodeId = moduleInfo.ModuleGuid.ToString(); templateInfo.Offset = Matrix4x4.identity; templateInfo.IsStaticObject = true; Node.spawnedModule = sceneProvider.AddGameObject(templateInfo, Node.AttachmentConfig.AttachedModuleTransform, objectInstantiator); // Register this in the model var snapModule = new SnapModuleInstance(); snapModule.InstanceID = Node.ModuleInstanceID; spawnedModuleList.Add(snapModule); }); snapModel.modules = spawnedModuleList.ToArray(); } // Generate the list of connections { var connectionList = new List <SnapModuleConnection>(); TraverseTree(BuildNode, delegate(ModuleBuildNode Node) { if (Node.Parent != null) { var Connection = new SnapModuleConnection(); Connection.ModuleAInstanceID = Node.ModuleInstanceID; Connection.DoorAIndex = Node.AttachmentConfig.AttachedModuleDoorIndex; Connection.ModuleBInstanceID = Node.Parent.ModuleInstanceID; Connection.DoorBIndex = Node.IncomingDoorIndex; connectionList.Add(Connection); } }); snapModel.connections = connectionList.ToArray(); } sceneProvider.OnDungeonBuildStop(); FixupDoorStates(BuildNode); }