added code from unity

This commit is contained in:
Sebastian Bularca
2026-04-06 20:45:22 +02:00
parent a66b4471fa
commit 2872300873
34 changed files with 2164 additions and 2 deletions

8
Editor.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1e182a45ed498c445b141e9ec6395805
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,338 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using Jovian.SaveSystem;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using UnityEditor;
using UnityEngine;
namespace Jovian.InGameLogging.Editor {
public class GameLogViewerWindow : EditorWindow {
private static readonly Regex richTextRegex = new(@"<[^>]+>", RegexOptions.Compiled);
private Vector2 slotListScroll;
private Vector2 logEntriesScroll;
private List<SessionGroup> sessions = new();
private SaveSlotEntry selectedSlot;
private List<LogEntry> loadedEntries = new();
private List<LogEntry> filteredEntries = new();
private List<string> channelNames = new();
private int selectedChannelIndex;
private string savePath;
private GUIStyle channelTagStyle;
private GUIStyle timeStyle;
private GUIStyle messageStyle;
private GUIStyle slotButtonStyle;
private GUIStyle noDataStyle;
private bool stylesInitialized;
[MenuItem("Jovian/In-Game Logging/Log Viewer")]
public static void ShowWindow() {
var window = GetWindow<GameLogViewerWindow>("In-Game Log Viewer");
window.minSize = new Vector2(500, 400);
window.Show();
}
private void OnEnable() {
ScanSaves();
}
private void InitStyles() {
if(stylesInitialized) {
return;
}
channelTagStyle = new GUIStyle(EditorStyles.miniLabel) {
fontStyle = FontStyle.Bold,
normal = { textColor = new Color(0.5f, 0.8f, 1f) },
fixedWidth = 120,
alignment = TextAnchor.MiddleLeft
};
timeStyle = new GUIStyle(EditorStyles.miniLabel) {
normal = { textColor = new Color(0.6f, 0.6f, 0.6f) },
fixedWidth = 70,
alignment = TextAnchor.MiddleRight
};
messageStyle = new GUIStyle(EditorStyles.label) {
wordWrap = false,
richText = false
};
slotButtonStyle = new GUIStyle(EditorStyles.toolbarButton) {
alignment = TextAnchor.MiddleLeft,
fixedHeight = 22
};
noDataStyle = new GUIStyle(EditorStyles.centeredGreyMiniLabel) {
fontSize = 12,
wordWrap = true
};
stylesInitialized = true;
}
private void OnGUI() {
InitStyles();
DrawToolbar();
if(sessions.Count == 0) {
EditorGUILayout.LabelField("No save files found.\nPlay the game and save to generate log data.",
noDataStyle, GUILayout.ExpandHeight(true));
return;
}
DrawSlotList();
DrawChannelFilter();
DrawLogEntries();
}
private void DrawToolbar() {
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
GUILayout.FlexibleSpace();
if(GUILayout.Button("Refresh", EditorStyles.toolbarButton, GUILayout.Width(60))) {
ScanSaves();
}
EditorGUILayout.EndHorizontal();
}
private void DrawSlotList() {
EditorGUILayout.LabelField("Save Slots", EditorStyles.boldLabel);
slotListScroll = EditorGUILayout.BeginScrollView(slotListScroll, GUILayout.MaxHeight(200));
foreach(var session in sessions) {
session.foldout = EditorGUILayout.Foldout(session.foldout, session.displayName, true);
if(!session.foldout) {
continue;
}
EditorGUI.indentLevel++;
foreach(var slot in session.slots) {
var isSelected = selectedSlot != null && selectedSlot.filePath == slot.filePath;
var style = new GUIStyle(slotButtonStyle);
if(isSelected) {
style.fontStyle = FontStyle.Bold;
}
if(GUILayout.Button($" {slot.displayName}", style)) {
SelectSlot(slot);
}
}
EditorGUI.indentLevel--;
}
EditorGUILayout.EndScrollView();
DrawSeparator();
}
private void DrawChannelFilter() {
if(loadedEntries.Count == 0) {
return;
}
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Channel filter:", GUILayout.Width(90));
var newIndex = EditorGUILayout.Popup(selectedChannelIndex, channelNames.ToArray());
if(newIndex != selectedChannelIndex) {
selectedChannelIndex = newIndex;
ApplyChannelFilter();
}
EditorGUILayout.EndHorizontal();
}
private void DrawLogEntries() {
if(selectedSlot == null) {
EditorGUILayout.LabelField("Select a save slot to view its log entries.", noDataStyle, GUILayout.ExpandHeight(true));
return;
}
if(filteredEntries.Count == 0) {
EditorGUILayout.LabelField("No log entries in this save.", noDataStyle, GUILayout.ExpandHeight(true));
return;
}
EditorGUILayout.LabelField($"{filteredEntries.Count} entries", EditorStyles.miniLabel);
logEntriesScroll = EditorGUILayout.BeginScrollView(logEntriesScroll, GUILayout.ExpandHeight(true));
foreach(var entry in filteredEntries) {
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField($"[{entry.channel}]", channelTagStyle);
EditorGUILayout.LabelField(FormatTime(entry.gameTime), timeStyle);
EditorGUILayout.LabelField(StripRichText(entry.message), messageStyle);
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.EndScrollView();
}
private void DrawSeparator() {
var rect = EditorGUILayout.GetControlRect(false, 1);
EditorGUI.DrawRect(rect, new Color(0.3f, 0.3f, 0.3f));
}
private void ScanSaves() {
sessions.Clear();
selectedSlot = null;
loadedEntries.Clear();
filteredEntries.Clear();
channelNames.Clear();
selectedChannelIndex = 0;
var settings = SaveSystemSettings.Load();
savePath = Path.Combine(Application.persistentDataPath, settings.saveDirectoryName);
var indexPath = Path.Combine(savePath, "index.json");
if(!File.Exists(indexPath)) {
return;
}
try {
var indexJson = File.ReadAllText(indexPath);
var index = JsonConvert.DeserializeObject<SaveIndex>(indexJson);
if(index?.sessions == null || index.slots == null) {
return;
}
var slotsBySession = new Dictionary<string, List<SaveSlotEntry>>();
foreach(var slot in index.slots) {
if(!slotsBySession.ContainsKey(slot.sessionId)) {
slotsBySession[slot.sessionId] = new List<SaveSlotEntry>();
}
slotsBySession[slot.sessionId].Add(new SaveSlotEntry {
sessionId = slot.sessionId,
displayName = slot.DisplayLabel + " " + DateTimeOffset.FromUnixTimeMilliseconds(slot.timestampUtc).LocalDateTime.ToString("HH:mm"),
filePath = slot.filePath,
timestampUtc = slot.timestampUtc
});
}
foreach(var session in index.sessions) {
if(!slotsBySession.TryGetValue(session.sessionId, out var slots)) {
continue;
}
slots.Sort((a, b) => b.timestampUtc.CompareTo(a.timestampUtc));
sessions.Add(new SessionGroup {
sessionId = session.sessionId,
displayName = $"Session ({DateTimeOffset.FromUnixTimeMilliseconds(session.lastSaveDateUtc).LocalDateTime:yyyy-MM-dd HH:mm})",
foldout = true,
slots = slots
});
}
sessions.Sort((a, b) => string.Compare(b.sessionId, a.sessionId, StringComparison.Ordinal));
}
catch(Exception e) {
Debug.LogError($"[GameLogViewer] Failed to read save index: {e.Message}");
}
}
private void SelectSlot(SaveSlotEntry slot) {
selectedSlot = slot;
loadedEntries.Clear();
filteredEntries.Clear();
channelNames.Clear();
channelNames.Add("All");
selectedChannelIndex = 0;
var fullPath = Path.Combine(savePath, slot.filePath);
if(!File.Exists(fullPath)) {
Debug.LogWarning($"[GameLogViewer] Save file not found: {fullPath}");
return;
}
try {
var bytes = File.ReadAllBytes(fullPath);
var serializer = new JsonSaveSerializer();
var envelope = serializer.Deserialize<SaveEnvelope>(bytes);
if(envelope?.payload == null) {
return;
}
// Navigate via JToken to avoid coupling to NoxSavedDataSet
var gameLogToken = envelope.payload["gameLogData"];
if(gameLogToken == null) {
return;
}
var entriesToken = gameLogToken["entries"];
if(entriesToken == null) {
return;
}
var logData = entriesToken.ToObject<List<LogEntry>>();
if(logData == null) {
return;
}
loadedEntries.AddRange(logData);
// Build channel list
var uniqueChannels = new HashSet<string>();
foreach(var entry in loadedEntries) {
var channelId = entry.channel.Id;
if(!string.IsNullOrEmpty(channelId) && uniqueChannels.Add(channelId)) {
channelNames.Add(channelId);
}
}
ApplyChannelFilter();
}
catch(Exception e) {
Debug.LogError($"[GameLogViewer] Failed to load save: {e.Message}");
}
}
private void ApplyChannelFilter() {
filteredEntries.Clear();
if(selectedChannelIndex == 0) {
filteredEntries.AddRange(loadedEntries);
}
else {
var channelId = channelNames[selectedChannelIndex];
foreach(var entry in loadedEntries) {
if(entry.channel.Id == channelId) {
filteredEntries.Add(entry);
}
}
}
}
private static string StripRichText(string text) {
return string.IsNullOrEmpty(text) ? string.Empty : richTextRegex.Replace(text, string.Empty);
}
private static string FormatTime(float gameTime) {
var minutes = (int)(gameTime / 60f);
var seconds = gameTime % 60f;
return $"{minutes}:{seconds:00.0}";
}
// Internal types for deserialization -- mirrors save system index structure
[Serializable]
private sealed class SaveIndex {
public List<SaveSessionInfo> sessions;
public List<SaveSlotInfo> slots;
}
private sealed class SessionGroup {
public string sessionId;
public string displayName;
public bool foldout;
public List<SaveSlotEntry> slots;
}
private sealed class SaveSlotEntry {
public string sessionId;
public string displayName;
public string filePath;
public long timestampUtc;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 6f19bfe069d21db41a998154aa0876fb

View File

@@ -0,0 +1,19 @@
{
"name": "Jovian.InGameLogging.Editor",
"rootNamespace": "Jovian.InGameLogging.Editor",
"references": [
"Jovian.InGameLogging",
"Jovian.SaveSystem"
],
"includePlatforms": ["Editor"],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": true,
"precompiledReferences": [
"Newtonsoft.Json.dll"
],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 48c945ba5ea83b144b5bbf4eaf33fe29
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

261
README.md
View File

@@ -1,3 +1,262 @@
# unity-ingame-logging # Jovian In-Game Logging
A low-allocation in-game logging system for Unity with channel-based filtering, pooled UI, and save system integration. This is a player-facing game log (combat feed, event history), not a debug logger. A low-allocation in-game logging system for Unity with channel-based filtering, pooled UI, and save system integration. This is a player-facing game log (combat feed, event history), not a debug logger.
## Requirements
- Unity 2022.3 or later
- Dependencies:
- `com.unity.textmeshpro` 3.0.6+
- `com.unity.nuget.newtonsoft-json` 3.2.1+
- `com.jovian.savesystem` 0.1.0+
## Quick Start
### 1. Create the store
`GameLogStore` is the central service that holds log entries in a ring buffer. Create it once and pass it via constructor injection.
```csharp
// Default capacity of 500 entries
var logStore = new GameLogStore();
// Or specify a custom capacity
var logStore = new GameLogStore(capacity: 1000);
```
### 2. Create a logger
`InGameLogger` is a lightweight facade bound to a specific channel. Create one per system or class that needs to write log entries.
```csharp
var combatLogger = new InGameLogger(logStore, LogChannel.Combat);
var worldLogger = new InGameLogger(logStore, LogChannel.World);
```
### 3. Log messages
```csharp
combatLogger.Log("Kael strikes the skeleton for 12 damage.");
combatLogger.Log("Critical hit!", "#FF4444");
```
### 4. Set up the UI
Add a `GameLogView` component to a GameObject with a `ScrollRect`. Assign the `ScrollRect`, a content `RectTransform`, and a `LogEntryView` prefab in the Inspector. Then initialize from code:
```csharp
// Show all channels
gameLogView.Initialize(logStore);
// Or filter to a single channel
gameLogView.Initialize(logStore, LogChannel.Combat);
```
The view uses object pooling internally. It auto-scrolls to the bottom as new entries arrive and pauses auto-scroll when the player scrolls up manually.
## Prefab Setup
The UI requires two prefabs: a **LogEntryView prefab** (the individual log row) and a **GameLogView prefab** (the scrollable container).
### LogEntryView prefab
1. Create a new GameObject, rename it `LogEntry`
2. Add a `LayoutElement` component. Set `Preferred Height` to your desired row height (e.g. 24). Enable `Flexible Width` so it stretches to the scroll content width
3. Add a child GameObject with a `TextMeshPro - Text (UI)` component
- Set `Overflow` to `Ellipsis` or `Truncate` (prevents text from spilling outside the row)
- Anchor and stretch it to fill the parent (`Left: 0, Right: 0, Top: 0, Bottom: 0`)
- Set font, font size, and color to match your game's UI style
- `Rich Text` should remain enabled (default)
4. Add the `LogEntryView` component to the root `LogEntry` GameObject
5. Drag the child `TMP_Text` into the `LogEntryView.messageText` field
6. Save as a prefab
### GameLogView prefab
1. Create a new UI GameObject with a `ScrollRect` component
- Disable `Horizontal` scrolling, keep `Vertical` enabled
- Set `Movement Type` to `Clamped` or `Elastic` as preferred
- Set `Scroll Sensitivity` to a comfortable value (e.g. 20)
2. Add a child `Content` GameObject as the scroll content area
- Add a `RectTransform` anchored top-left, pivot `(0, 1)`, with a `VerticalLayoutGroup`:
- `Child Alignment`: Upper Left
- `Child Force Expand Width`: true, `Height`: false
- `Spacing`: 2 (gap between log rows)
- `Padding`: set as needed
- Add a `ContentSizeFitter` with `Vertical Fit` set to `Preferred Size` (so it grows as entries are added)
- Assign this as the `ScrollRect.Content`
3. Optionally add a `Scrollbar` child for the vertical scrollbar, and assign it to `ScrollRect.Vertical Scrollbar`
4. Optionally add a `Mask` or `RectMask2D` on the scroll viewport to clip entries outside the visible area
5. Add the `GameLogView` component to the root GameObject
6. Assign the fields in the Inspector:
- `scrollRect`: the `ScrollRect` component
- `content`: the `Content` child's `RectTransform`
- `entryPrefab`: your `LogEntryView` prefab
- `poolSize`: number of pre-instantiated entries (default 20, increase for taller views)
### Initialization from code
After instantiating or finding the `GameLogView` in the scene:
```csharp
var gameLogView = Object.FindFirstObjectByType<GameLogView>();
gameLogView.Initialize(logStore);
// Or filtered to a single channel:
gameLogView.Initialize(logStore, LogChannel.Combat);
```
## Log Channels
### Built-in channels
| Channel | Usage |
|---------|-------|
| `LogChannel.Combat` | Combat events, damage, abilities |
| `LogChannel.CharacterCreation` | Character creation flow |
| `LogChannel.World` | World events, exploration |
| `LogChannel.General` | General-purpose messages |
### Custom channels
`LogChannel` is a readonly struct keyed by a string ID. Define custom channels as static fields:
```csharp
public static class MyLogChannels {
public static readonly LogChannel Trading = new("Trading");
public static readonly LogChannel Dialogue = new("Dialogue");
}
```
Then use them like any built-in channel:
```csharp
var tradeLogger = new InGameLogger(logStore, MyLogChannels.Trading);
tradeLogger.Log("Sold Iron Sword for 50 gold.");
```
## Enable / Disable Channels
Each logger can be toggled on or off. When disabled, calls to `Log` are silently dropped (no allocation, no entry added). All channels are enabled by default.
```csharp
var combatLog = new InGameLogger(logStore, LogChannel.Combat);
combatLog.Disable();
combatLog.Log("This message is silently dropped.");
combatLog.Enable();
combatLog.Log("Back online.");
if(combatLog.IsEnabled) {
// check state
}
```
The state lives in the `IGameLogStore`, so disabling a channel from one `InGameLogger` instance disables it for all instances using the same store and channel. You can also call the store directly:
```csharp
logStore.DisableChannel(LogChannel.World);
logStore.EnableChannel(LogChannel.World);
bool enabled = logStore.IsChannelEnabled(LogChannel.World);
```
## Rich Text
Log messages support TextMeshPro rich text tags. The `InGameLogger.Log(message, hexColor)` overload wraps the message in a `<color>` tag automatically:
```csharp
logger.Log("Poisoned!", "#00FF00");
// Stored as: <color=#00FF00>Poisoned!</color>
```
You can also embed TMP tags directly in the message string:
```csharp
logger.Log("Gained <b>+5</b> <color=#FFD700>experience</color>.");
```
## Save / Load Integration
`GameLogStore` supports serializing its contents for use with a save system.
### Save
```csharp
GameLogSaveData saveData = logStore.GetSaveData();
// Serialize saveData into your save file
```
### Load
```csharp
// Deserialize saveData from your save file
logStore.RestoreFromSaveData(saveData);
```
`RestoreFromSaveData` replaces the current buffer contents. If the save data contains more entries than the store's capacity, only the most recent entries are kept. The `OnCleared` event fires after restoration so the UI can rebuild.
### JSON serialization
`LogChannel` is serialized as a plain string via the included `LogChannelJsonConverter` (Newtonsoft.Json). The converter is applied via attribute on `LogEntry.channel`, so no manual converter registration is needed.
## API Reference
### LogChannel (readonly struct)
- `LogChannel(string id)` -- constructor
- `string Id` -- the channel identifier
- Static fields: `Combat`, `CharacterCreation`, `World`, `General`
- Implements `IEquatable<LogChannel>`, ordinal string comparison
### LogEntry (readonly struct)
- `string message` -- the log message (may contain TMP rich text)
- `LogChannel channel` -- the channel this entry belongs to
- `float gameTime` -- `Time.time` when the entry was added
### InGameLogger (readonly struct)
- `InGameLogger(IGameLogStore store, LogChannel channel)` -- constructor
- `void Log(string message)` -- add an entry to the store
- `void Log(string message, string hexColor)` -- add a color-wrapped entry
- `void Enable()` -- enable this logger's channel
- `void Disable()` -- disable this logger's channel (Log calls are silently dropped)
- `bool IsEnabled` -- whether this logger's channel is currently enabled
### IGameLogStore / GameLogStore
- `GameLogStore(int capacity = 500)` -- constructor with ring buffer size
- `int Count` -- current number of entries
- `int Capacity` -- maximum entries before oldest are overwritten
- `void Add(LogChannel channel, string message)` -- add an entry (silently dropped if channel is disabled)
- `void EnableChannel(LogChannel channel)` -- enable a channel
- `void DisableChannel(LogChannel channel)` -- disable a channel
- `bool IsChannelEnabled(LogChannel channel)` -- check if a channel is enabled
- `void Clear()` -- remove all entries
- `void Clear(LogChannel channel)` -- remove entries for a specific channel
- `ReadOnlySpan<LogEntry> GetEntries()` -- all entries in chronological order
- `int GetEntries(LogChannel channel, List<LogEntry> results)` -- filtered entries, returns count
- `event Action<LogEntry> OnEntryAdded` -- fires after each new entry
- `event Action OnCleared` -- fires after `Clear()` or `RestoreFromSaveData()`
- `GameLogSaveData GetSaveData()` -- snapshot for serialization
- `void RestoreFromSaveData(GameLogSaveData data)` -- replace contents from save data
### GameLogSaveData
- `List<LogEntry> entries` -- serializable entry list
### GameLogView (MonoBehaviour) -- `Jovian.InGameLogging.UI`
- `void Initialize(IGameLogStore store, LogChannel? channelFilter = null)` -- bind to a store, optionally filtering to one channel
- Requires: `ScrollRect`, content `RectTransform`, and `LogEntryView` prefab assigned in Inspector
### LogEntryView (MonoBehaviour) -- `Jovian.InGameLogging.UI`
- `void SetEntry(in LogEntry entry)` -- display an entry
- `void ClearEntry()` -- reset the text
- Requires: `TMP_Text` reference assigned in Inspector
### LogChannelJsonConverter
- Newtonsoft.Json `JsonConverter<LogChannel>` -- serializes `LogChannel` as its string ID

7
README.md.meta Normal file
View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 8a8d67e42da5eea4a873d8f632bacbbe
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
Runtime.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 51325b1e7a05b6740a458bdcae9f8998
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
namespace Jovian.InGameLogging {
[Serializable]
public sealed class GameLogSaveData {
public List<LogEntry> entries;
public GameLogSaveData() {
entries = new List<LogEntry>();
}
public GameLogSaveData(List<LogEntry> entries) {
this.entries = entries;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 965eab6edce9dbc49b93d0bda0ad6f6c

122
Runtime/GameLogStore.cs Normal file
View File

@@ -0,0 +1,122 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Jovian.InGameLogging {
public sealed class GameLogStore : IGameLogStore {
private readonly LogEntry[] buffer;
private readonly HashSet<LogChannel> disabledChannels = new();
private int head;
private int count;
public int Count => count;
public int Capacity => buffer.Length;
public event Action<LogEntry> OnEntryAdded;
public event Action OnCleared;
public GameLogStore(int capacity = 500) {
buffer = new LogEntry[capacity];
head = 0;
count = 0;
}
public void Add(LogChannel channel, string message) {
if(disabledChannels.Contains(channel)) {
return;
}
var entry = new LogEntry(message, channel, Time.time);
buffer[head] = entry;
head = (head + 1) % buffer.Length;
if(count < buffer.Length) {
count++;
}
OnEntryAdded?.Invoke(entry);
}
public void EnableChannel(LogChannel channel) {
disabledChannels.Remove(channel);
}
public void DisableChannel(LogChannel channel) {
disabledChannels.Add(channel);
}
public bool IsChannelEnabled(LogChannel channel) {
return !disabledChannels.Contains(channel);
}
public void Clear() {
head = 0;
count = 0;
OnCleared?.Invoke();
}
public void Clear(LogChannel channel) {
var kept = new List<LogEntry>(count);
var entries = GetEntries();
for(var i = 0; i < entries.Length; i++) {
if(entries[i].channel != channel) {
kept.Add(entries[i]);
}
}
head = 0;
count = 0;
for(var i = 0; i < kept.Count; i++) {
buffer[i] = kept[i];
count++;
}
head = count % buffer.Length;
OnCleared?.Invoke();
}
public ReadOnlySpan<LogEntry> GetEntries() {
if(count < buffer.Length) {
return new ReadOnlySpan<LogEntry>(buffer, 0, count);
}
var result = new LogEntry[count];
var start = head;
for(var i = 0; i < count; i++) {
result[i] = buffer[(start + i) % buffer.Length];
}
return result;
}
public int GetEntries(LogChannel channel, List<LogEntry> results) {
results.Clear();
var entries = GetEntries();
for(var i = 0; i < entries.Length; i++) {
if(entries[i].channel == channel) {
results.Add(entries[i]);
}
}
return results.Count;
}
public GameLogSaveData GetSaveData() {
var entries = GetEntries();
var list = new List<LogEntry>(entries.Length);
foreach(var t in entries) {
list.Add(t);
}
return new GameLogSaveData(list);
}
public void RestoreFromSaveData(GameLogSaveData data) {
head = 0;
count = 0;
if(data?.entries == null) {
OnCleared?.Invoke();
return;
}
var startIndex = Math.Max(0, data.entries.Count - buffer.Length);
for(var i = startIndex; i < data.entries.Count; i++) {
buffer[count] = data.entries[i];
count++;
}
head = count % buffer.Length;
OnCleared?.Invoke();
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 1eb9ff03ddd225e46852cb92ba213bc7

25
Runtime/IGameLogStore.cs Normal file
View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
namespace Jovian.InGameLogging {
public interface IGameLogStore {
int Count { get; }
int Capacity { get; }
void Add(LogChannel channel, string message);
void EnableChannel(LogChannel channel);
void DisableChannel(LogChannel channel);
bool IsChannelEnabled(LogChannel channel);
void Clear();
void Clear(LogChannel channel);
ReadOnlySpan<LogEntry> GetEntries();
int GetEntries(LogChannel channel, List<LogEntry> results);
event Action<LogEntry> OnEntryAdded;
event Action OnCleared;
GameLogSaveData GetSaveData();
void RestoreFromSaveData(GameLogSaveData data);
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: b5fac89eac17e874e888928c9618e812

36
Runtime/InGameLogger.cs Normal file
View File

@@ -0,0 +1,36 @@
using System.Runtime.CompilerServices;
namespace Jovian.InGameLogging {
public readonly struct InGameLogger {
private readonly IGameLogStore store;
private readonly LogChannel channel;
public InGameLogger(IGameLogStore store, LogChannel channel) {
this.store = store;
this.channel = channel;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Log(string message) {
store.Add(channel, message);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Log(string message, string hexColor) {
var prefix = hexColor.Length > 0 && hexColor[0] == '#' ? "" : "#";
store.Add(channel, $"<color={prefix}{hexColor}>{message}</color>");
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Enable() {
store.EnableChannel(channel);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Disable() {
store.DisableChannel(channel);
}
public bool IsEnabled => store.IsChannelEnabled(channel);
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 79d11c151d20d2c41a4ad5e288a4f16f

View File

@@ -0,0 +1,19 @@
{
"name": "Jovian.InGameLogging",
"rootNamespace": "Jovian.InGameLogging",
"references": [
"Unity.TextMeshPro",
"Jovian.SaveSystem"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": true,
"precompiledReferences": [
"Newtonsoft.Json.dll"
],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 6053f37e557f955418ef96fdf46f7d6b
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

44
Runtime/LogChannel.cs Normal file
View File

@@ -0,0 +1,44 @@
using System;
using UnityEngine;
namespace Jovian.InGameLogging {
[Serializable]
public readonly struct LogChannel : IEquatable<LogChannel> {
private readonly string id;
public string Id => id;
public LogChannel(string id) {
this.id = id;
}
public static readonly LogChannel Combat = new("Combat");
public static readonly LogChannel CharacterCreation = new("CharacterCreation");
public static readonly LogChannel World = new("World");
public static readonly LogChannel General = new("General");
public bool Equals(LogChannel other) {
return string.Equals(id, other.id, StringComparison.Ordinal);
}
public override bool Equals(object obj) {
return obj is LogChannel other && Equals(other);
}
public override int GetHashCode() {
return id != null ? id.GetHashCode() : 0;
}
public override string ToString() {
return id ?? string.Empty;
}
public static bool operator ==(LogChannel left, LogChannel right) {
return left.Equals(right);
}
public static bool operator !=(LogChannel left, LogChannel right) {
return !left.Equals(right);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 08b1132b10325ce4d922fa7b207db4e0

View File

@@ -0,0 +1,15 @@
using System;
using Newtonsoft.Json;
namespace Jovian.InGameLogging {
public sealed class LogChannelJsonConverter : JsonConverter<LogChannel> {
public override void WriteJson(JsonWriter writer, LogChannel value, JsonSerializer serializer) {
writer.WriteValue(value.Id);
}
public override LogChannel ReadJson(JsonReader reader, Type objectType, LogChannel existingValue, bool hasExistingValue, JsonSerializer serializer) {
var id = reader.Value as string;
return new LogChannel(id);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 3c3eb6d23e195e345a3546749ca4e96f

20
Runtime/LogEntry.cs Normal file
View File

@@ -0,0 +1,20 @@
using System;
using Newtonsoft.Json;
namespace Jovian.InGameLogging {
[Serializable]
public readonly struct LogEntry {
[JsonProperty] public readonly string message;
[JsonProperty] [JsonConverter(typeof(LogChannelJsonConverter))]
public readonly LogChannel channel;
[JsonProperty] public readonly float gameTime;
public LogEntry(string message, LogChannel channel, float gameTime) {
this.message = message;
this.channel = channel;
this.gameTime = gameTime;
}
}
}

2
Runtime/LogEntry.cs.meta Normal file
View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 0f79543f908769543ac8fc14e138df62

8
Runtime/UI.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b1125aedc37d43948aeef186bccbeac8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

137
Runtime/UI/GameLogView.cs Normal file
View File

@@ -0,0 +1,137 @@
using System.Collections;
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;
bool scrollingToBottom;
Coroutine scrollCoroutine;
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) {
RequestScrollToBottom();
}
}
void RequestScrollToBottom() {
if(scrollCoroutine != null) {
StopCoroutine(scrollCoroutine);
}
scrollCoroutine = StartCoroutine(ScrollToBottomRoutine());
}
IEnumerator ScrollToBottomRoutine() {
scrollingToBottom = true;
yield return null;
LayoutRebuilder.ForceRebuildLayoutImmediate(content);
scrollRect.verticalNormalizedPosition = 0f;
yield return null;
scrollingToBottom = false;
scrollCoroutine = null;
}
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) {
RequestScrollToBottom();
}
}
void HandleScrollChanged(Vector2 position) {
if(scrollingToBottom) {
return;
}
autoScroll = position.y <= 0.01f;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 786fb23f28122964cb30678ea785bd40

View File

@@ -0,0 +1,16 @@
using TMPro;
using UnityEngine;
namespace Jovian.InGameLogging.UI {
public class LogEntryView : MonoBehaviour {
[SerializeField] TMP_Text messageText;
public void SetEntry(in LogEntry entry) {
messageText.text = entry.message;
}
public void ClearEntry() {
messageText.text = string.Empty;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 5526887cdf77a54439357be8b5754ffc

View File

@@ -0,0 +1,790 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &1447740470325782801
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 6286131802514671469}
- component: {fileID: 7279458507301375298}
- component: {fileID: 7180659085512946289}
- component: {fileID: 1194623820596100263}
m_Layer: 0
m_Name: Viewport
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &6286131802514671469
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1447740470325782801}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 3059084814696477984}
m_Father: {fileID: 6248177754200331468}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0, y: 1}
--- !u!222 &7279458507301375298
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1447740470325782801}
m_CullTransparentMesh: 1
--- !u!114 &7180659085512946289
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1447740470325782801}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 10917, guid: 0000000000000000f000000000000000, type: 0}
m_Type: 1
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!114 &1194623820596100263
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1447740470325782801}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3}
m_Name:
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Mask
m_ShowMaskGraphic: 0
--- !u!1 &1525412503934350410
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2417638750186197328}
- component: {fileID: 6899372841946195929}
m_Layer: 0
m_Name: LogContainer
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &2417638750186197328
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1525412503934350410}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 6248177754200331468}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 1.0002, y: -252.13}
m_SizeDelta: {x: 737.42, y: 504.25}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &6899372841946195929
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1525412503934350410}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 786fb23f28122964cb30678ea785bd40, type: 3}
m_Name:
m_EditorClassIdentifier: Jovian.InGameLogging::Jovian.InGameLogging.UI.GameLogView
scrollRect: {fileID: 2554617498295089481}
content: {fileID: 3059084814696477984}
entryPrefab: {fileID: 4832918257971952213, guid: 9d1c7837b0b5a9f45baa84f326fc247c, type: 3}
poolSize: 20
--- !u!1 &2405629305058117087
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 3059084814696477984}
- component: {fileID: 1744225011043606462}
m_Layer: 0
m_Name: Content
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &3059084814696477984
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2405629305058117087}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 6286131802514671469}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 487.26}
m_Pivot: {x: 0, y: 1}
--- !u!114 &1744225011043606462
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2405629305058117087}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 59f8146938fff824cb5fd77236b75775, type: 3}
m_Name:
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.VerticalLayoutGroup
m_Padding:
m_Left: 0
m_Right: 0
m_Top: 0
m_Bottom: 0
m_ChildAlignment: 0
m_Spacing: 2
m_ChildForceExpandWidth: 1
m_ChildForceExpandHeight: 0
m_ChildControlWidth: 0
m_ChildControlHeight: 0
m_ChildScaleWidth: 0
m_ChildScaleHeight: 0
m_ReverseArrangement: 0
--- !u!1 &3952660362247579954
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2688140319784364735}
- component: {fileID: 7390804912840202258}
- component: {fileID: 5246482949485489637}
- component: {fileID: 529710424251508929}
m_Layer: 0
m_Name: Scrollbar Horizontal
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &2688140319784364735
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3952660362247579954}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 3366448768354673732}
m_Father: {fileID: 6248177754200331468}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 20}
m_Pivot: {x: 0, y: 0}
--- !u!222 &7390804912840202258
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3952660362247579954}
m_CullTransparentMesh: 1
--- !u!114 &5246482949485489637
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3952660362247579954}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0}
m_Type: 1
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!114 &529710424251508929
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3952660362247579954}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 2a4db7a114972834c8e4117be1d82ba3, type: 3}
m_Name:
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Scrollbar
m_Navigation:
m_Mode: 3
m_WrapAround: 0
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
m_SelectOnRight: {fileID: 0}
m_Transition: 1
m_Colors:
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
m_ColorMultiplier: 1
m_FadeDuration: 0.1
m_SpriteState:
m_HighlightedSprite: {fileID: 0}
m_PressedSprite: {fileID: 0}
m_SelectedSprite: {fileID: 0}
m_DisabledSprite: {fileID: 0}
m_AnimationTriggers:
m_NormalTrigger: Normal
m_HighlightedTrigger: Highlighted
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 1
m_TargetGraphic: {fileID: 1342770482644207694}
m_HandleRect: {fileID: 2251566621526024109}
m_Direction: 0
m_Value: 1
m_Size: 0.99999994
m_NumberOfSteps: 0
m_OnValueChanged:
m_PersistentCalls:
m_Calls: []
--- !u!1 &5969083621566914297
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 374280998538979084}
- component: {fileID: 5436844256530954601}
- component: {fileID: 6879256843609484833}
m_Layer: 0
m_Name: Handle
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &374280998538979084
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5969083621566914297}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 8977826534581480953}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 20, y: 20}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &5436844256530954601
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5969083621566914297}
m_CullTransparentMesh: 1
--- !u!114 &6879256843609484833
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5969083621566914297}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
m_Type: 1
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!1 &6050805973784497029
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 3366448768354673732}
m_Layer: 0
m_Name: Sliding Area
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &3366448768354673732
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6050805973784497029}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 2251566621526024109}
m_Father: {fileID: 2688140319784364735}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: -8.5, y: 0}
m_SizeDelta: {x: -20, y: -20}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!1 &6074956918412360435
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 6248177754200331468}
- component: {fileID: 7678453280902357168}
- component: {fileID: 4027884099002409368}
- component: {fileID: 2554617498295089481}
m_Layer: 0
m_Name: Scroll View
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &6248177754200331468
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6074956918412360435}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 6286131802514671469}
- {fileID: 2688140319784364735}
- {fileID: 4070132176653801724}
m_Father: {fileID: 2417638750186197328}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: 0.0024719}
m_SizeDelta: {x: 737.42, y: 504.26}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &7678453280902357168
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6074956918412360435}
m_CullTransparentMesh: 1
--- !u!114 &4027884099002409368
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6074956918412360435}
m_Enabled: 0
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 0.392}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0}
m_Type: 1
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!114 &2554617498295089481
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6074956918412360435}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1aa08ab6e0800fa44ae55d278d1423e3, type: 3}
m_Name:
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.ScrollRect
m_Content: {fileID: 3059084814696477984}
m_Horizontal: 0
m_Vertical: 1
m_MovementType: 1
m_Elasticity: 0
m_Inertia: 1
m_DecelerationRate: 0.135
m_ScrollSensitivity: 1
m_Viewport: {fileID: 6286131802514671469}
m_HorizontalScrollbar: {fileID: 529710424251508929}
m_VerticalScrollbar: {fileID: 9136497547051495148}
m_HorizontalScrollbarVisibility: 2
m_VerticalScrollbarVisibility: 2
m_HorizontalScrollbarSpacing: -3
m_VerticalScrollbarSpacing: -3
m_OnValueChanged:
m_PersistentCalls:
m_Calls: []
--- !u!1 &6994548556054523628
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 4070132176653801724}
- component: {fileID: 8682590904891029538}
- component: {fileID: 5114829985009070717}
- component: {fileID: 9136497547051495148}
m_Layer: 0
m_Name: Scrollbar Vertical
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &4070132176653801724
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6994548556054523628}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 8977826534581480953}
m_Father: {fileID: 6248177754200331468}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 1, y: 0}
m_AnchorMax: {x: 1, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 20, y: 0}
m_Pivot: {x: 1, y: 1}
--- !u!222 &8682590904891029538
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6994548556054523628}
m_CullTransparentMesh: 1
--- !u!114 &5114829985009070717
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6994548556054523628}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0}
m_Type: 1
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!114 &9136497547051495148
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6994548556054523628}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 2a4db7a114972834c8e4117be1d82ba3, type: 3}
m_Name:
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Scrollbar
m_Navigation:
m_Mode: 3
m_WrapAround: 0
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
m_SelectOnRight: {fileID: 0}
m_Transition: 1
m_Colors:
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
m_ColorMultiplier: 1
m_FadeDuration: 0.1
m_SpriteState:
m_HighlightedSprite: {fileID: 0}
m_PressedSprite: {fileID: 0}
m_SelectedSprite: {fileID: 0}
m_DisabledSprite: {fileID: 0}
m_AnimationTriggers:
m_NormalTrigger: Normal
m_HighlightedTrigger: Highlighted
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 1
m_TargetGraphic: {fileID: 6879256843609484833}
m_HandleRect: {fileID: 374280998538979084}
m_Direction: 2
m_Value: 1
m_Size: 1
m_NumberOfSteps: 0
m_OnValueChanged:
m_PersistentCalls:
m_Calls: []
--- !u!1 &7187724186482890403
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8977826534581480953}
m_Layer: 0
m_Name: Sliding Area
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &8977826534581480953
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7187724186482890403}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 374280998538979084}
m_Father: {fileID: 4070132176653801724}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 8.5}
m_SizeDelta: {x: -20, y: -20}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!1 &7193882241213188023
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2251566621526024109}
- component: {fileID: 1372064744394430487}
- component: {fileID: 1342770482644207694}
m_Layer: 0
m_Name: Handle
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &2251566621526024109
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7193882241213188023}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 3366448768354673732}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 20, y: 20}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &1372064744394430487
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7193882241213188023}
m_CullTransparentMesh: 1
--- !u!114 &1342770482644207694
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7193882241213188023}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
m_Type: 1
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1

210
Samples~/LogEntry.prefab Normal file
View File

@@ -0,0 +1,210 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &6501593483943143564
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 382400732949652569}
- component: {fileID: 4832918257971952213}
- component: {fileID: 1727094465477629914}
m_Layer: 0
m_Name: LogEntry
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &382400732949652569
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6501593483943143564}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 8597194705437786868}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 1093, y: 615}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &4832918257971952213
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6501593483943143564}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5526887cdf77a54439357be8b5754ffc, type: 3}
m_Name:
m_EditorClassIdentifier: Jovian.InGameLogging::Jovian.InGameLogging.UI.LogEntryView
messageText: {fileID: 4259574353180979179}
--- !u!114 &1727094465477629914
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6501593483943143564}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
m_Name:
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.LayoutElement
m_IgnoreLayout: 0
m_MinWidth: -1
m_MinHeight: -1
m_PreferredWidth: -1
m_PreferredHeight: 100
m_FlexibleWidth: 1
m_FlexibleHeight: -1
m_LayoutPriority: 1
--- !u!1 &8033193440249993941
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8597194705437786868}
- component: {fileID: 8331827018725656388}
- component: {fileID: 4259574353180979179}
m_Layer: 0
m_Name: Text (TMP)
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &8597194705437786868
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8033193440249993941}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 382400732949652569}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: -0.0000000044237822}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &8331827018725656388
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8033193440249993941}
m_CullTransparentMesh: 1
--- !u!114 &4259574353180979179
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8033193440249993941}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.TextMeshPro::TMPro.TextMeshProUGUI
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_text: New Text
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
m_fontMaterials: []
m_fontColor32:
serializedVersion: 2
rgba: 4294967295
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
m_enableVertexGradient: 0
m_colorMode: 3
m_fontColorGradient:
topLeft: {r: 1, g: 1, b: 1, a: 1}
topRight: {r: 1, g: 1, b: 1, a: 1}
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
bottomRight: {r: 1, g: 1, b: 1, a: 1}
m_fontColorGradientPreset: {fileID: 0}
m_spriteAsset: {fileID: 0}
m_tintAllSprites: 0
m_StyleSheet: {fileID: 0}
m_TextStyleHashCode: -1183493901
m_overrideHtmlColors: 0
m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 24
m_fontSizeBase: 36
m_fontWeight: 400
m_enableAutoSizing: 1
m_fontSizeMin: 5
m_fontSizeMax: 24
m_fontStyle: 0
m_HorizontalAlignment: 1
m_VerticalAlignment: 256
m_textAlignment: 65535
m_characterSpacing: 0
m_characterHorizontalScale: 1
m_wordSpacing: 0
m_lineSpacing: 0
m_lineSpacingMax: 0
m_paragraphSpacing: 0
m_charWidthMaxAdj: 0
m_TextWrappingMode: 1
m_wordWrappingRatios: 0.4
m_overflowMode: 3
m_linkedTextComponent: {fileID: 0}
parentLinkedComponent: {fileID: 0}
m_enableKerning: 0
m_ActiveFontFeatures: 6e72656b
m_enableExtraPadding: 0
checkPaddingRequired: 0
m_isRichText: 1
m_EmojiFallbackSupport: 1
m_parseCtrlCharacters: 1
m_isOrthographic: 1
m_isCullingEnabled: 0
m_horizontalMapping: 0
m_verticalMapping: 0
m_uvLineOffset: 0
m_geometrySortingOrder: 0
m_IsTextObjectScaleStatic: 0
m_VertexBufferAutoSizeReduction: 0
m_useMaxVisibleDescender: 1
m_pageToDisplay: 1
m_margin: {x: 0, y: 0, z: 0, w: 0}
m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0
m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}

3
Samples~/README.md Normal file
View File

@@ -0,0 +1,3 @@
# Samples
This folder is reserved for sample scenes and scripts demonstrating the In-Game Logging system.

20
package.json Normal file
View File

@@ -0,0 +1,20 @@
{
"name": "com.jovian.ingame-logging",
"version": "0.1.0",
"displayName": "Jovian In-Game Logging",
"description": "An optimized, low-allocation in-game logging system with pooled UI, channel-based filtering, and save system integration.",
"unity": "2022.3",
"dependencies": {
"com.unity.textmeshpro": "3.0.6",
"com.unity.nuget.newtonsoft-json": "3.2.1",
"com.jovian.savesystem": "0.1.0"
},
"keywords": [
"logging",
"ui",
"ingame"
],
"author": {
"name": "Jovian"
}
}

7
package.json.meta Normal file
View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: acdee7574039a3a48980e2cc9c6fe31d
PackageManifestImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: