using System; using System.Collections.Generic; using UnityEngine; namespace Assets.ThoMagic.Renderer { public class TileObjectStreamer : InstanceStreamer { private readonly GameObject objectContainer; private Bounds worldBounds; private float maxDistance; private Dictionary registeredPrefabs = new Dictionary(); private Dictionary instanceToGameObject = new Dictionary(); private bool isDirty = true; public TileObjectStreamer(GameObject objectContainer) : base() { this.objectContainer = objectContainer; } public void Recycle() { Clear(); int ownerHash = GetHashCode(); foreach (var item in registeredPrefabs) { RendererPool.RemoveObject(item.Value, ownerHash); } foreach (var item in instanceToGameObject) { var mrs = item.Value.gameObject.GetComponentsInChildren(); foreach(var mr in mrs) mr.enabled = true; var lod = item.Value.gameObject.GetComponent(); if (lod != null) lod.enabled = true; } registeredPrefabs.Clear(); instanceToGameObject.Clear(); } public void Load() { isDirty = false; Recycle(); worldBounds.SetMinMax(Vector3.zero, Vector3.zero); registeredPrefabs.Clear(); instanceToGameObject.Clear(); int ownerHash = GetHashCode(); foreach (Transform child in objectContainer.transform) { var hash = CalculateHash(child.gameObject); if(hash != 0) { int objectId; if (registeredPrefabs.ContainsKey(hash)) { objectId = registeredPrefabs[hash]; } else { var settings = GetSettingsOrDefault(child.gameObject); objectId = RendererPool.RegisterObject(child.gameObject, settings, this, ownerHash); registeredPrefabs.Add(hash, objectId); if (settings.Settings.RenderDistance == 0) maxDistance = float.MaxValue; maxDistance = Mathf.Max(maxDistance, settings.Settings.RenderDistance); } var mrs = child.gameObject.GetComponentsInChildren(); Bounds bounds = new Bounds(); bool first = true; foreach (var mr in mrs) { if (first) { bounds = mr.bounds; } else { bounds.Encapsulate(mr.bounds); } mr.enabled = false; } var lod = child.gameObject.GetComponent(); if(lod != null) lod.enabled = false; var instanceId = AddInstance(objectId, new Vector3(child.position.x, child.position.y, child.position.z), child.rotation, child.lossyScale.x, child.lossyScale.z); instanceToGameObject.Add(instanceId, child.gameObject); if (instanceToGameObject.Count == 1) worldBounds = bounds; else worldBounds.Encapsulate(bounds); } } } private IInstanceRenderSettings GetSettingsOrDefault(GameObject gameObject) { IInstanceRenderSettings instanceRenderSettings; return gameObject.TryGetComponent(out instanceRenderSettings) ? instanceRenderSettings : new DefaultRenderSettings(); } private int CalculateHash(GameObject gameObject) { int num = 13; var lodGroup = gameObject.GetComponent(); LOD[] lodArray; if (lodGroup == null) { var mr = gameObject.GetComponentsInChildren(); if (mr == null) return 0; lodArray = new LOD[1] { new LOD(0.0001f, mr) }; } else lodArray = lodGroup.GetLODs(); foreach (var loD in lodArray) num = HashCode.Combine(num, CalcualteContentHash(loD)); return num; } private int CalcualteContentHash(LOD lod) { int num = 13; if (lod.renderers != null) { foreach (var renderer in lod.renderers) { if (renderer == null) { num = HashCode.Combine(num, 13); } else { MeshFilter component = renderer.GetComponent(); num = HashCode.Combine(HashCode.Combine( num, component == null || component.sharedMesh == null ? 13 : component.sharedMesh.GetHashCode(), renderer.shadowCastingMode.GetHashCode(), CalculateContentHash(renderer.sharedMaterials), renderer.motionVectorGenerationMode.GetHashCode(), renderer.receiveShadows.GetHashCode(), renderer.rendererPriority.GetHashCode(), renderer.renderingLayerMask.GetHashCode()), renderer.gameObject.layer.GetHashCode(), lod.screenRelativeTransitionHeight.GetHashCode()); } } } return num; } private int CalculateContentHash(Material[] materials) { int num = 13; if (materials != null) { foreach (Material material in materials) num = HashCode.Combine(num, material != null ? material.GetHashCode() : 13); } return num; } public override bool IsInRange(Camera referenceCamera, Plane[] planes) { var eyePos = referenceCamera.transform.position; if ((eyePos - worldBounds.ClosestPoint(eyePos)).magnitude <= Mathf.Min(referenceCamera.farClipPlane, maxDistance)) return true; return false; } public override int GetHashCode() { return streamerInstanceId.GetHashCode();//HashCode.Combine(streamerInstanceId, objectInstanceIds.Count); } public void Destroy() { Recycle(); } public void LateUpdate() { if (isDirty) { Load(); } } public void MarkDirty() { isDirty = true; } private class DefaultRenderSettings : IInstanceRenderSettings { public InstanceRenderSettings Settings => new InstanceRenderSettings() { Render = true, DensityInDistance = 1f, DensityInDistanceFalloff = Vector2.zero, RenderDistance = 0.0f, ShadowDistance = 0.0f, Shadows = true, Supported = true }; } } }