forked from Shardstone/trail-into-darkness
117 lines
3.4 KiB
C#
117 lines
3.4 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
|
|
namespace Jovian.InGameLogging.UI {
|
|
public class GameLogView : MonoBehaviour {
|
|
[SerializeField] ScrollRect scrollRect;
|
|
[SerializeField] RectTransform content;
|
|
[SerializeField] LogEntryView entryPrefab;
|
|
[SerializeField] int poolSize = 20;
|
|
|
|
IGameLogStore store;
|
|
LogChannel? channelFilter;
|
|
bool autoScroll = true;
|
|
|
|
readonly List<LogEntryView> activeEntries = new();
|
|
readonly Stack<LogEntryView> pool = new();
|
|
|
|
public void Initialize(IGameLogStore store, LogChannel? channelFilter = null) {
|
|
this.store = store;
|
|
this.channelFilter = channelFilter;
|
|
|
|
WarmPool();
|
|
store.OnEntryAdded += HandleEntryAdded;
|
|
store.OnCleared += HandleCleared;
|
|
scrollRect.onValueChanged.AddListener(HandleScrollChanged);
|
|
|
|
RebuildFromStore();
|
|
}
|
|
|
|
void OnDestroy() {
|
|
if(store != null) {
|
|
store.OnEntryAdded -= HandleEntryAdded;
|
|
store.OnCleared -= HandleCleared;
|
|
}
|
|
if(scrollRect != null) {
|
|
scrollRect.onValueChanged.RemoveListener(HandleScrollChanged);
|
|
}
|
|
}
|
|
|
|
void WarmPool() {
|
|
for(int i = 0; i < poolSize; i++) {
|
|
var entry = Instantiate(entryPrefab, content);
|
|
entry.gameObject.SetActive(false);
|
|
pool.Push(entry);
|
|
}
|
|
}
|
|
|
|
LogEntryView GetFromPool() {
|
|
LogEntryView entry;
|
|
if(pool.Count > 0) {
|
|
entry = pool.Pop();
|
|
}
|
|
else {
|
|
entry = activeEntries[0];
|
|
activeEntries.RemoveAt(0);
|
|
}
|
|
entry.gameObject.SetActive(true);
|
|
entry.transform.SetAsLastSibling();
|
|
return entry;
|
|
}
|
|
|
|
void ReturnToPool(LogEntryView entry) {
|
|
entry.ClearEntry();
|
|
entry.gameObject.SetActive(false);
|
|
pool.Push(entry);
|
|
}
|
|
|
|
void HandleEntryAdded(LogEntry entry) {
|
|
if(channelFilter.HasValue && entry.channel != channelFilter.Value) {
|
|
return;
|
|
}
|
|
|
|
var view = GetFromPool();
|
|
view.SetEntry(in entry);
|
|
activeEntries.Add(view);
|
|
|
|
if(autoScroll) {
|
|
Canvas.ForceUpdateCanvases();
|
|
scrollRect.verticalNormalizedPosition = 0f;
|
|
}
|
|
}
|
|
|
|
void HandleCleared() {
|
|
for(int i = activeEntries.Count - 1; i >= 0; i--) {
|
|
ReturnToPool(activeEntries[i]);
|
|
}
|
|
activeEntries.Clear();
|
|
|
|
if(store.Count > 0) {
|
|
RebuildFromStore();
|
|
}
|
|
}
|
|
|
|
void RebuildFromStore() {
|
|
var entries = store.GetEntries();
|
|
for(int i = 0; i < entries.Length; i++) {
|
|
if(channelFilter.HasValue && entries[i].channel != channelFilter.Value) {
|
|
continue;
|
|
}
|
|
var view = GetFromPool();
|
|
view.SetEntry(in entries[i]);
|
|
activeEntries.Add(view);
|
|
}
|
|
|
|
if(autoScroll) {
|
|
Canvas.ForceUpdateCanvases();
|
|
scrollRect.verticalNormalizedPosition = 0f;
|
|
}
|
|
}
|
|
|
|
void HandleScrollChanged(Vector2 position) {
|
|
autoScroll = position.y <= 0.01f;
|
|
}
|
|
}
|
|
}
|