You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
156 lines
4.8 KiB
156 lines
4.8 KiB
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<int, Entity> entities = new Dictionary<int, Entity>();
|
|
|
|
public GameState(UniQuake uniQuake)
|
|
{
|
|
uq = uniQuake;
|
|
}
|
|
|
|
public void Destroy()
|
|
{
|
|
DestroyEntities();
|
|
DestroyWorld();
|
|
}
|
|
|
|
public void NewMap(BrushModel worldModel)
|
|
{
|
|
Destroy();
|
|
Resources.UnloadUnusedAssets();
|
|
|
|
worldGameObject = new GameObject(worldModel.Name) { layer = (int)uq.GameLayer };
|
|
|
|
// 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) { layer = (int)uq.GameLayer };
|
|
|
|
foreach (var surfaceMesh in subModel.SurfaceMeshes)
|
|
{
|
|
var meshGO = new GameObject(surfaceMesh.Mesh.name) { layer = (int)uq.GameLayer };
|
|
meshGO.transform.SetParent(subModelGO.transform);
|
|
|
|
var mf = meshGO.AddComponent<MeshFilter>();
|
|
var mr = meshGO.AddComponent<MeshRenderer>();
|
|
mf.sharedMesh = surfaceMesh.Mesh;
|
|
|
|
// TODO FIXME This is wrong for brush model entities
|
|
uq.CurrentStyle.SetupWorldRenderer(mr);
|
|
mr.material = uq.CurrentStyle.CreateWorldMaterial(); // TODO FIXME this currently leaks Materials
|
|
|
|
uint texNum = surfaceMesh.TextureNum;
|
|
if (uq.GameAssets.TryGetTexture(texNum, out var texture))
|
|
{
|
|
uint fbNum = surfaceMesh.FullBrightNum;
|
|
uq.GameAssets.TryGetTexture(fbNum, out var fullBright);
|
|
|
|
uq.CurrentStyle.SetWorldTextures(mr.material, texture, fullBright, null);
|
|
}
|
|
}
|
|
|
|
return subModelGO;
|
|
}
|
|
|
|
private void DestroyWorld()
|
|
{
|
|
if (worldGameObject != null)
|
|
{
|
|
Object.Destroy(worldGameObject);
|
|
worldGameObject = null;
|
|
}
|
|
}
|
|
|
|
public Entity GetEntity(int entityNum)
|
|
{
|
|
if (!entities.TryGetValue(entityNum, out var entity))
|
|
{
|
|
entity = new Entity(entityNum, uq.CurrentStyle, entityNum == 0 ? uq.ViewModelLayer : uq.GameLayer);
|
|
entities.Add(entityNum, entity);
|
|
}
|
|
|
|
return entity;
|
|
}
|
|
|
|
public void SetEntityAliasModel(int entityNum, string modelName)
|
|
{
|
|
var entity = GetEntity(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 = GetEntity(entityNum);
|
|
|
|
if (!uq.GameAssets.TryGetBrushModel(modelName, out var brushModel))
|
|
{
|
|
Debug.LogWarning($"Unknown brush model name: {modelName}");
|
|
return;
|
|
}
|
|
|
|
var brushModelGO = new GameObject(brushModel.Name) { layer = (int)Layers.Game1 };
|
|
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 = GetEntity(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();
|
|
}
|
|
}
|