using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering; public class GameState { private readonly UniQuake uq; private GameObject worldGameObject; private readonly Dictionary entities = new Dictionary(); public GameState(UniQuake uniQuake) { uq = uniQuake; } public void Destroy() { DestroyEntities(); DestroyWorld(); } public void NewMap(BrushModel worldModel) { Destroy(); worldGameObject = new GameObject(worldModel.Name); // The first sub-model contains all of the static geometry var subModel = worldModel.GetSubModel(0); var subModelGO = CreateBrushGameObject(subModel); subModelGO.transform.SetParent(worldGameObject.transform); } private GameObject CreateBrushGameObject(BrushModel.SubModel subModel) { var subModelGO = new GameObject(subModel.Name); // DEBUG - we'll want to instantiate prefabs for each sub-model and assign materials from a preset collection foreach (var surfaceMesh in subModel.SurfaceMeshes) { var meshGO = new GameObject(surfaceMesh.Mesh.name); meshGO.transform.SetParent(subModelGO.transform); var mf = meshGO.AddComponent(); mf.sharedMesh = surfaceMesh.Mesh; var material = new Material(Shader.Find("Universal Render Pipeline/Simple Lit")); uint texNum = surfaceMesh.Texture.TextureNum; if (uq.GameAssets.TryGetTexture(texNum, out var texture)) { material.mainTexture = texture; } var mr = meshGO.AddComponent(); mr.sharedMaterial = material; mr.shadowCastingMode = ShadowCastingMode.Off; mr.receiveShadows = false; mr.lightProbeUsage = LightProbeUsage.Off; mr.reflectionProbeUsage = ReflectionProbeUsage.Off; } return subModelGO; } private void DestroyWorld() { if (worldGameObject != null) { Object.Destroy(worldGameObject); worldGameObject = null; } } public Entity GetEntity(int entityNum) { entities.TryGetValue(entityNum, out var entity); return entity; } private Entity GetOrCreateEntity(int entityNum) { if (!entities.TryGetValue(entityNum, out var entity)) { entity = new Entity(entityNum); entities.Add(entityNum, entity); } return entity; } public void SetEntityAliasModel(int entityNum, string modelName) { var entity = GetOrCreateEntity(entityNum); if (!uq.GameAssets.TryGetAliasModel(modelName, out var aliasModel)) { Debug.LogWarning($"Unknown alias model name: {modelName}"); return; } entity.SetAliasModel(aliasModel); } public void SetEntityBrushModel(int entityNum, string modelName) { var entity = GetOrCreateEntity(entityNum); if (!uq.GameAssets.TryGetBrushModel(modelName, out var brushModel)) { Debug.LogWarning($"Unknown brush model name: {modelName}"); return; } var brushModelGO = new GameObject(brushModel.Name); for (int i = 0; i < brushModel.SubModelCount; ++i) { var subModelGO = CreateBrushGameObject(brushModel.GetSubModel(i)); subModelGO.transform.SetParent(brushModelGO.transform); } entity.SetBrushModel(brushModelGO); } public void SetEntityWorldModel(int entityNum, int subModelNum) { var entity = GetOrCreateEntity(entityNum); if (!uq.GameAssets.TryGetWorldSubModel(subModelNum, out var subModel)) { Debug.LogWarning($"Invalid world sub-model number: {subModelNum}"); return; } // TODO: these relatively complex world game objects are going to get destroyed and re-created all the time // as the player moves through the map and moves in and out of range of these entities. This can and should // be done more efficiently by creating the game objects only once and enabling/disabling them on demand. var worldModelGO = CreateBrushGameObject(subModel); entity.SetWorldModel(worldModelGO); } public void RemoveEntity(int entityNum) { if (entities.TryGetValue(entityNum, out var entity)) { entity.Destroy(); entities.Remove(entityNum); } } private void DestroyEntities() { foreach (var entity in entities.Values) { entity.Destroy(); } entities.Clear(); } }