ManiaMap.Unity
Procedural generation of metroidvania style maps for Unity.
RoomTemplateDatabase.cs
1using MPewsey.ManiaMap;
2using MPewsey.ManiaMap.Exceptions;
3using System.Collections.Generic;
4using System.Linq;
5using System.Threading.Tasks;
6using UnityEngine;
7using UnityEngine.ResourceManagement.AsyncOperations;
8
10{
14 [CreateAssetMenu(menuName = "Mania Map/Room Template Database")]
15 public class RoomTemplateDatabase : ScriptableObject
16 {
17 [SerializeField]
18 private List<TemplateGroup> _templateGroups = new List<TemplateGroup>();
22 public List<TemplateGroup> TemplateGroups { get => _templateGroups; set => _templateGroups = value; }
23
27 private Dictionary<int, RoomTemplateResource> RoomTemplates { get; } = new Dictionary<int, RoomTemplateResource>();
28
32 public bool IsDirty { get; private set; } = true;
33
34 private void Awake()
35 {
36 IsDirty = true;
37 }
38
39 private void OnValidate()
40 {
41 IsDirty = true;
42 }
43
47 public IReadOnlyDictionary<int, RoomTemplateResource> GetRoomTemplates()
48 {
50 return RoomTemplates;
51 }
52
56 public void MarkDirty()
57 {
58 IsDirty = true;
59 }
60
64 private void PopulateIfDirty()
65 {
66 if (IsDirty)
67 {
69 IsDirty = false;
70 }
71 }
72
77 private void PopulateRoomTemplates()
78 {
79 RoomTemplates.Clear();
80
81 foreach (var group in TemplateGroups)
82 {
83 foreach (var entry in group.Entries)
84 {
85 var id = entry.Template.Id;
86
87 if (!RoomTemplates.TryGetValue(id, out var template))
88 RoomTemplates.Add(id, entry.Template);
89 else if (template != entry.Template)
90 throw new DuplicateIdException($"Duplicate room template ID: (ID = {id}, Template1 = {template}, Template2 = {entry.Template}).");
91 }
92 }
93 }
94
100 {
102 return RoomTemplates[id];
103 }
104
111 {
112 var room = layoutPack.Layout.Rooms[id];
113 return GetRoomTemplate(room.Template.Id);
114 }
115
121 public async Task<List<RoomComponent>> InstantiateAllRoomsAsync(LayoutPack layoutPack, Transform parent = null)
122 {
123 var result = new List<RoomComponent>(layoutPack.Layout.Rooms.Count);
124
125 foreach (var room in layoutPack.Layout.Rooms.Values)
126 {
127 var prefab = GetRoomTemplate(room.Template.Id).GetAssetReference();
128 var handle = RoomComponent.InstantiateRoomAsync(room.Id, layoutPack, prefab, parent, true);
129 handle.Completed += handle => OnInstantiationComplete(handle, result);
130 await handle.Task;
131 }
132
133 ActivateRooms(result);
134 return result;
135 }
136
142 public List<RoomComponent> InstantiateAllRooms(LayoutPack layoutPack, Transform parent = null)
143 {
144 var result = new List<RoomComponent>(layoutPack.Layout.Rooms.Count);
145
146 foreach (var room in layoutPack.Layout.Rooms.Values)
147 {
148 var prefab = GetRoomTemplate(room.Template.Id).GetAssetReference();
149 var handle = RoomComponent.InstantiateRoomAsync(room.Id, layoutPack, prefab, parent, true);
150 var roomInstance = handle.WaitForCompletion();
151 result.Add(roomInstance.GetComponent<RoomComponent>());
152 }
153
154 return result;
155 }
156
163 public async Task<List<RoomComponent>> InstantiateRoomsAsync(LayoutPack layoutPack, Transform parent = null, int? z = null)
164 {
165 z ??= layoutPack.Layout.Rooms.Values.Select(x => x.Position.Z).First();
166 var result = new List<RoomComponent>();
167
168 foreach (var room in layoutPack.Layout.Rooms.Values)
169 {
170 if (room.Position.Z == z)
171 {
172 var prefab = GetRoomTemplate(room.Template.Id).GetAssetReference();
173 var handle = RoomComponent.InstantiateRoomAsync(room.Id, layoutPack, prefab, parent, true);
174 handle.Completed += handle => OnInstantiationComplete(handle, result);
175 await handle.Task;
176 }
177 }
178
179 ActivateRooms(result);
180 return result;
181 }
182
187 private static void ActivateRooms(List<RoomComponent> rooms)
188 {
189 foreach (var room in rooms)
190 {
191 room.gameObject.SetActive(true);
192 }
193 }
194
200 private static void OnInstantiationComplete(AsyncOperationHandle<GameObject> handle, List<RoomComponent> results)
201 {
202 var room = handle.Result.GetComponent<RoomComponent>();
203 room.gameObject.SetActive(false);
204 results.Add(room);
205 }
206
213 public List<RoomComponent> InstantiateRooms(LayoutPack layoutPack, Transform parent = null, int? z = null)
214 {
215 z ??= layoutPack.Layout.Rooms.Values.Select(x => x.Position.Z).First();
216 var result = new List<RoomComponent>();
217
218 foreach (var room in layoutPack.Layout.Rooms.Values)
219 {
220 if (room.Position.Z == z)
221 {
222 var prefab = GetRoomTemplate(room.Template.Id).GetAssetReference();
223 var handle = RoomComponent.InstantiateRoomAsync(room.Id, layoutPack, prefab, parent, true);
224 var roomInstance = handle.WaitForCompletion();
225 result.Add(roomInstance.GetComponent<RoomComponent>());
226 }
227 }
228
229 return result;
230 }
231
239 public AsyncOperationHandle<GameObject> InstantiateRoomAsync(Uid id, LayoutPack layoutPack, Transform parent = null, bool assignLayoutPosition = false)
240 {
241 var prefab = GetRoomTemplate(id, layoutPack).GetAssetReference();
242 return RoomComponent.InstantiateRoomAsync(id, layoutPack, prefab, parent, assignLayoutPosition);
243 }
244
252 public RoomComponent InstantiateRoom(Uid id, LayoutPack layoutPack, Transform parent = null, bool assignLayoutPosition = false)
253 {
254 var result = InstantiateRoomAsync(id, layoutPack, parent, assignLayoutPosition).WaitForCompletion();
255 return result.GetComponent<RoomComponent>();
256 }
257 }
258}
A manager for maintaining the current map data and state.
Definition: LayoutPack.cs:12
A component for creating a room.
static AsyncOperationHandle< GameObject > InstantiateRoomAsync(Uid id, LayoutPack layoutPack, AssetReferenceGameObject prefab, Transform parent=null, bool assignLayoutPosition=false)
Instantiates and initializes a room asynchronously. Returns the operation handle.
A database of room templates whose room can be instantiated via Addressables.
RoomComponent InstantiateRoom(Uid id, LayoutPack layoutPack, Transform parent=null, bool assignLayoutPosition=false)
Instantiates the specified room and returns it.
List< RoomComponent > InstantiateRooms(LayoutPack layoutPack, Transform parent=null, int? z=null)
Instantiates the rooms in the specified layer of the layout.
IReadOnlyDictionary< int, RoomTemplateResource > GetRoomTemplates()
Returns the dictionary of room templates by ID.
void PopulateIfDirty()
If the object is dirty, populates the room templates dictionary.
Dictionary< int, RoomTemplateResource > RoomTemplates
A dictionary of room templates by ID.
AsyncOperationHandle< GameObject > InstantiateRoomAsync(Uid id, LayoutPack layoutPack, Transform parent=null, bool assignLayoutPosition=false)
Instantiates the specified room asynchronously. Returns an operation handle with the result.
RoomTemplateResource GetRoomTemplate(Uid id, LayoutPack layoutPack)
Returns the room template for the specified room ID.
async Task< List< RoomComponent > > InstantiateRoomsAsync(LayoutPack layoutPack, Transform parent=null, int? z=null)
Instantiates the rooms in a specified layer of the layout asynchronously. Returns the rooms as a resu...
static void ActivateRooms(List< RoomComponent > rooms)
Activates the rooms in the specified list.
List< TemplateGroup > TemplateGroups
A list of template groups.
RoomTemplateResource GetRoomTemplate(int id)
Returns the room template with the specified ID.
void PopulateRoomTemplates()
Populates the room templates dictionary.
async Task< List< RoomComponent > > InstantiateAllRoomsAsync(LayoutPack layoutPack, Transform parent=null)
Instantiates all rooms in the layout asynchronously and returns the rooms as a result of the task.
static void OnInstantiationComplete(AsyncOperationHandle< GameObject > handle, List< RoomComponent > results)
Adds the room from the operation handle result to the results list and deactivates it.
List< RoomComponent > InstantiateAllRooms(LayoutPack layoutPack, Transform parent=null)
Instantiates all rooms in the layout and returns a list of them.
void MarkDirty()
Sets the object as dirty.
bool IsDirty
If true, the object is dirty and requires population.
A container for storing a serialized room template.
AssetReferenceGameObject GetAssetReference()
Returns the asset reference based on the assigned prefab GUID.