Line endings: LF everywhere
.gitattributes forces LF (CRLF only for .bat/.cmd), core.autocrlf is off; files that differed only by CRLF are normalized.
This commit is contained in:
1 parent
bd7b472dff
commit
8d3f7445f3
6 files changed
+884
-854
No files matched your search
+146
-146
@@ -1,147 +1,147 @@
|
||||
using Cthangover.Core.Scenes;
|
||||
using Cthangover.Core.Settings;
|
||||
using Cthangover.Core.UI.Tool;
|
||||
using Cthangover.Core.Utils;
|
||||
using Godot;
|
||||
|
||||
using Cthangover.Core.Scenes;
|
||||
using Cthangover.Core.Settings;
|
||||
using Cthangover.Core.UI.Tool;
|
||||
using Cthangover.Core.Utils;
|
||||
using Godot;
|
||||
|
||||
using Cthangover.Mods.Interface.Tool;
|
||||
namespace Cthangover.Mods.Time
|
||||
{
|
||||
/// <summary>
|
||||
/// Draggable lamp UI element for the player's portable light source.
|
||||
/// Input handling exists in both _GuiInput (bubbled) and _Input (global)
|
||||
/// to catch drags that start on the lamp but continue outside its rect.
|
||||
/// When the lamp is hidden, it resets position to offscreen (-1000,-1000)
|
||||
/// to disable the light in the shader. GetLightParams() is a static helper
|
||||
/// so the light controller can query lamp parameters without coupling to
|
||||
/// the behaviour instance. Inherits from TextureRectModIconLoader for
|
||||
/// mod-provided lamp icon textures.
|
||||
/// </summary>
|
||||
public partial class LampBehaviour : TextureRectModIconLoader
|
||||
{
|
||||
private UiLightController controller;
|
||||
private Vector2 dragPosition;
|
||||
private bool isPlaced;
|
||||
|
||||
private bool pressingOnLamp;
|
||||
|
||||
/// <summary>
|
||||
/// Queries lamp parameters (color, radius, influence) from
|
||||
/// <see cref="GameData.Instance.Runtime.LampData"/>. Static so the
|
||||
/// <see cref="UiLightController"/> can query without a direct reference.
|
||||
/// </summary>
|
||||
public static (Color, float, float) GetLightParams()
|
||||
{
|
||||
var lampData = GameData.Instance.Runtime.LampData;
|
||||
var radius = lampData.Radius;
|
||||
var influence = lampData.Influence;
|
||||
return (Colors.Yellow, radius, influence);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Visibility toggle for the lamp. Setting to <c>false</c> resets the
|
||||
/// placed state and sends the light position offscreen to disable
|
||||
/// the lamp light in the shader. Uses <c>new</c> to log transitions.
|
||||
/// </summary>
|
||||
public new bool Visible
|
||||
{
|
||||
get => base.Visible;
|
||||
set
|
||||
{
|
||||
if (base.Visible != value)
|
||||
GameLogger.Log("LIGHT", $"Lamp.Visible: {base.Visible} -> {value}, isPlaced={isPlaced}", LogLevel.Debug);
|
||||
base.Visible = value;
|
||||
if (!value)
|
||||
{
|
||||
pressingOnLamp = false;
|
||||
if (isPlaced)
|
||||
{
|
||||
isPlaced = false;
|
||||
controller?.UpdateLightPos(new Vector2(-1000f, -1000f));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Finds the shared <see cref="UiLightController"/> this lamp pushes positions to.</summary>
|
||||
public override void _Ready()
|
||||
{
|
||||
base._Ready();
|
||||
MouseFilter = MouseFilterEnum.Stop;
|
||||
controller = SceneContextNode.FindNode<UiLightController>("Lights");
|
||||
GameLogger.Log("LIGHT", $"Lamp._Ready: controller={(controller != null ? "OK" : "NULL")}", LogLevel.Debug);
|
||||
}
|
||||
|
||||
/// <summary>Click to place the light at the cursor, drag to move it, and click a placed lamp to pick it back up.</summary>
|
||||
public override void _GuiInput(InputEvent @event)
|
||||
{
|
||||
if (@event is InputEventMouseButton mouseButton)
|
||||
{
|
||||
if (mouseButton.ButtonIndex == MouseButton.Left)
|
||||
{
|
||||
if (mouseButton.Pressed)
|
||||
{
|
||||
pressingOnLamp = true;
|
||||
dragPosition = GetGlobalMousePosition();
|
||||
|
||||
if (isPlaced)
|
||||
{
|
||||
dragPosition = new Vector2(-1000f, -1000f);
|
||||
controller?.UpdateLightPos(dragPosition);
|
||||
isPlaced = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pressingOnLamp && !isPlaced)
|
||||
{
|
||||
isPlaced = true;
|
||||
controller?.UpdateLightPos(dragPosition);
|
||||
}
|
||||
pressingOnLamp = false;
|
||||
}
|
||||
}
|
||||
AcceptEvent();
|
||||
}
|
||||
else if (@event is InputEventMouseMotion mouseMotion)
|
||||
{
|
||||
if (Input.IsMouseButtonPressed(MouseButton.Left))
|
||||
{
|
||||
dragPosition = GetGlobalMousePosition();
|
||||
controller?.UpdateLightPos(dragPosition);
|
||||
isPlaced = false;
|
||||
AcceptEvent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Keeps dragging the placed light while the pointer moves outside the lamp's own control rect.</summary>
|
||||
public override void _Input(InputEvent @event)
|
||||
{
|
||||
if (!Visible)
|
||||
return;
|
||||
|
||||
if (@event is InputEventMouseMotion mouseMotion
|
||||
&& Input.IsMouseButtonPressed(MouseButton.Left)
|
||||
&& pressingOnLamp)
|
||||
{
|
||||
dragPosition = GetGlobalMousePosition();
|
||||
controller?.UpdateLightPos(dragPosition);
|
||||
isPlaced = false;
|
||||
}
|
||||
|
||||
if (@event is InputEventMouseButton mouseButton
|
||||
&& mouseButton.ButtonIndex == MouseButton.Left
|
||||
&& !mouseButton.Pressed
|
||||
&& pressingOnLamp)
|
||||
{
|
||||
if (!isPlaced)
|
||||
{
|
||||
isPlaced = true;
|
||||
controller?.UpdateLightPos(dragPosition);
|
||||
}
|
||||
pressingOnLamp = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace Cthangover.Mods.Time
|
||||
{
|
||||
/// <summary>
|
||||
/// Draggable lamp UI element for the player's portable light source.
|
||||
/// Input handling exists in both _GuiInput (bubbled) and _Input (global)
|
||||
/// to catch drags that start on the lamp but continue outside its rect.
|
||||
/// When the lamp is hidden, it resets position to offscreen (-1000,-1000)
|
||||
/// to disable the light in the shader. GetLightParams() is a static helper
|
||||
/// so the light controller can query lamp parameters without coupling to
|
||||
/// the behaviour instance. Inherits from TextureRectModIconLoader for
|
||||
/// mod-provided lamp icon textures.
|
||||
/// </summary>
|
||||
public partial class LampBehaviour : TextureRectModIconLoader
|
||||
{
|
||||
private UiLightController controller;
|
||||
private Vector2 dragPosition;
|
||||
private bool isPlaced;
|
||||
|
||||
private bool pressingOnLamp;
|
||||
|
||||
/// <summary>
|
||||
/// Queries lamp parameters (color, radius, influence) from
|
||||
/// <see cref="GameData.Instance.Runtime.LampData"/>. Static so the
|
||||
/// <see cref="UiLightController"/> can query without a direct reference.
|
||||
/// </summary>
|
||||
public static (Color, float, float) GetLightParams()
|
||||
{
|
||||
var lampData = GameData.Instance.Runtime.LampData;
|
||||
var radius = lampData.Radius;
|
||||
var influence = lampData.Influence;
|
||||
return (Colors.Yellow, radius, influence);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Visibility toggle for the lamp. Setting to <c>false</c> resets the
|
||||
/// placed state and sends the light position offscreen to disable
|
||||
/// the lamp light in the shader. Uses <c>new</c> to log transitions.
|
||||
/// </summary>
|
||||
public new bool Visible
|
||||
{
|
||||
get => base.Visible;
|
||||
set
|
||||
{
|
||||
if (base.Visible != value)
|
||||
GameLogger.Log("LIGHT", $"Lamp.Visible: {base.Visible} -> {value}, isPlaced={isPlaced}", LogLevel.Debug);
|
||||
base.Visible = value;
|
||||
if (!value)
|
||||
{
|
||||
pressingOnLamp = false;
|
||||
if (isPlaced)
|
||||
{
|
||||
isPlaced = false;
|
||||
controller?.UpdateLightPos(new Vector2(-1000f, -1000f));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Finds the shared <see cref="UiLightController"/> this lamp pushes positions to.</summary>
|
||||
public override void _Ready()
|
||||
{
|
||||
base._Ready();
|
||||
MouseFilter = MouseFilterEnum.Stop;
|
||||
controller = SceneContextNode.FindNode<UiLightController>("Lights");
|
||||
GameLogger.Log("LIGHT", $"Lamp._Ready: controller={(controller != null ? "OK" : "NULL")}", LogLevel.Debug);
|
||||
}
|
||||
|
||||
/// <summary>Click to place the light at the cursor, drag to move it, and click a placed lamp to pick it back up.</summary>
|
||||
public override void _GuiInput(InputEvent @event)
|
||||
{
|
||||
if (@event is InputEventMouseButton mouseButton)
|
||||
{
|
||||
if (mouseButton.ButtonIndex == MouseButton.Left)
|
||||
{
|
||||
if (mouseButton.Pressed)
|
||||
{
|
||||
pressingOnLamp = true;
|
||||
dragPosition = GetGlobalMousePosition();
|
||||
|
||||
if (isPlaced)
|
||||
{
|
||||
dragPosition = new Vector2(-1000f, -1000f);
|
||||
controller?.UpdateLightPos(dragPosition);
|
||||
isPlaced = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pressingOnLamp && !isPlaced)
|
||||
{
|
||||
isPlaced = true;
|
||||
controller?.UpdateLightPos(dragPosition);
|
||||
}
|
||||
pressingOnLamp = false;
|
||||
}
|
||||
}
|
||||
AcceptEvent();
|
||||
}
|
||||
else if (@event is InputEventMouseMotion mouseMotion)
|
||||
{
|
||||
if (Input.IsMouseButtonPressed(MouseButton.Left))
|
||||
{
|
||||
dragPosition = GetGlobalMousePosition();
|
||||
controller?.UpdateLightPos(dragPosition);
|
||||
isPlaced = false;
|
||||
AcceptEvent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Keeps dragging the placed light while the pointer moves outside the lamp's own control rect.</summary>
|
||||
public override void _Input(InputEvent @event)
|
||||
{
|
||||
if (!Visible)
|
||||
return;
|
||||
|
||||
if (@event is InputEventMouseMotion mouseMotion
|
||||
&& Input.IsMouseButtonPressed(MouseButton.Left)
|
||||
&& pressingOnLamp)
|
||||
{
|
||||
dragPosition = GetGlobalMousePosition();
|
||||
controller?.UpdateLightPos(dragPosition);
|
||||
isPlaced = false;
|
||||
}
|
||||
|
||||
if (@event is InputEventMouseButton mouseButton
|
||||
&& mouseButton.ButtonIndex == MouseButton.Left
|
||||
&& !mouseButton.Pressed
|
||||
&& pressingOnLamp)
|
||||
{
|
||||
if (!isPlaced)
|
||||
{
|
||||
isPlaced = true;
|
||||
controller?.UpdateLightPos(dragPosition);
|
||||
}
|
||||
pressingOnLamp = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+79
-79
@@ -1,79 +1,79 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Godot;
|
||||
|
||||
namespace Cthangover.Mods.Time
|
||||
{
|
||||
/// <summary>
|
||||
/// Serializable light definition for JSON scene lighting. Coordinates are
|
||||
/// viewport-relative (0.0–1.0) so scenes adapt to different resolutions.
|
||||
/// ToPixelPos/FromPixelPos convert between normalized space and pixel space
|
||||
/// using a reference viewport size. Color is stored as a hex string for
|
||||
/// human-readable JSON editing.
|
||||
/// </summary>
|
||||
public class LightDef
|
||||
{
|
||||
/// <summary>
|
||||
/// Normalized horizontal position (0.0–1.0) relative to viewport width.
|
||||
/// </summary>
|
||||
[JsonPropertyName("x")]
|
||||
public float X { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Normalized vertical position (0.0–1.0) relative to viewport height.
|
||||
/// </summary>
|
||||
[JsonPropertyName("y")]
|
||||
public float Y { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Light radius in pixel units. Determines the falloff distance in the
|
||||
/// lighting shader.
|
||||
/// </summary>
|
||||
[JsonPropertyName("radius")]
|
||||
public float Radius { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Light intensity (0.0–1.0). At <c>1.0</c>, the light fully brightens
|
||||
/// pixels within its radius. Lower values create subtler effects.
|
||||
/// </summary>
|
||||
[JsonPropertyName("influence")]
|
||||
public float Influence { get; set; } = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// Light color as a hex string (e.g. "#ff8800"). Parsed by
|
||||
/// <see cref="ToColor"/> for shader upload.
|
||||
/// </summary>
|
||||
[JsonPropertyName("color")]
|
||||
public string ColorHex { get; set; } = "#ffff00";
|
||||
|
||||
/// <summary>
|
||||
/// Converts <see cref="ColorHex"/> to a Godot <c>Color</c> struct.
|
||||
/// </summary>
|
||||
public Color ToColor()
|
||||
{
|
||||
return new Color(ColorHex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts normalized coordinates (<see cref="X"/>, <see cref="Y"/>) to
|
||||
/// pixel coordinates based on <paramref name="viewportSize"/>.
|
||||
/// </summary>
|
||||
/// <param name="viewportSize">Current viewport dimensions in pixels.</param>
|
||||
public Vector2 ToPixelPos(Vector2 viewportSize)
|
||||
{
|
||||
return new Vector2(X * viewportSize.X, Y * viewportSize.Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes normalized coordinates from pixel coordinates by dividing by
|
||||
/// <paramref name="referenceSize"/>. Enables saving light positions
|
||||
/// across different resolutions.
|
||||
/// </summary>
|
||||
/// <param name="pixelPos">Light position in pixel space.</param>
|
||||
/// <param name="referenceSize">Viewport dimensions used as reference.</param>
|
||||
public void FromPixelPos(Vector2 pixelPos, Vector2 referenceSize)
|
||||
{
|
||||
X = pixelPos.X / referenceSize.X;
|
||||
Y = pixelPos.Y / referenceSize.Y;
|
||||
}
|
||||
}
|
||||
}
|
||||
using System.Text.Json.Serialization;
|
||||
using Godot;
|
||||
|
||||
namespace Cthangover.Mods.Time
|
||||
{
|
||||
/// <summary>
|
||||
/// Serializable light definition for JSON scene lighting. Coordinates are
|
||||
/// viewport-relative (0.0–1.0) so scenes adapt to different resolutions.
|
||||
/// ToPixelPos/FromPixelPos convert between normalized space and pixel space
|
||||
/// using a reference viewport size. Color is stored as a hex string for
|
||||
/// human-readable JSON editing.
|
||||
/// </summary>
|
||||
public class LightDef
|
||||
{
|
||||
/// <summary>
|
||||
/// Normalized horizontal position (0.0–1.0) relative to viewport width.
|
||||
/// </summary>
|
||||
[JsonPropertyName("x")]
|
||||
public float X { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Normalized vertical position (0.0–1.0) relative to viewport height.
|
||||
/// </summary>
|
||||
[JsonPropertyName("y")]
|
||||
public float Y { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Light radius in pixel units. Determines the falloff distance in the
|
||||
/// lighting shader.
|
||||
/// </summary>
|
||||
[JsonPropertyName("radius")]
|
||||
public float Radius { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Light intensity (0.0–1.0). At <c>1.0</c>, the light fully brightens
|
||||
/// pixels within its radius. Lower values create subtler effects.
|
||||
/// </summary>
|
||||
[JsonPropertyName("influence")]
|
||||
public float Influence { get; set; } = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// Light color as a hex string (e.g. "#ff8800"). Parsed by
|
||||
/// <see cref="ToColor"/> for shader upload.
|
||||
/// </summary>
|
||||
[JsonPropertyName("color")]
|
||||
public string ColorHex { get; set; } = "#ffff00";
|
||||
|
||||
/// <summary>
|
||||
/// Converts <see cref="ColorHex"/> to a Godot <c>Color</c> struct.
|
||||
/// </summary>
|
||||
public Color ToColor()
|
||||
{
|
||||
return new Color(ColorHex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts normalized coordinates (<see cref="X"/>, <see cref="Y"/>) to
|
||||
/// pixel coordinates based on <paramref name="viewportSize"/>.
|
||||
/// </summary>
|
||||
/// <param name="viewportSize">Current viewport dimensions in pixels.</param>
|
||||
public Vector2 ToPixelPos(Vector2 viewportSize)
|
||||
{
|
||||
return new Vector2(X * viewportSize.X, Y * viewportSize.Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes normalized coordinates from pixel coordinates by dividing by
|
||||
/// <paramref name="referenceSize"/>. Enables saving light positions
|
||||
/// across different resolutions.
|
||||
/// </summary>
|
||||
/// <param name="pixelPos">Light position in pixel space.</param>
|
||||
/// <param name="referenceSize">Viewport dimensions used as reference.</param>
|
||||
public void FromPixelPos(Vector2 pixelPos, Vector2 referenceSize)
|
||||
{
|
||||
X = pixelPos.X / referenceSize.X;
|
||||
Y = pixelPos.Y / referenceSize.Y;
|
||||
}
|
||||
}
|
||||
}
|
||||
+519
-519
File diff suppressed because it is too large.
Load diff
+73
-73
@@ -1,73 +1,73 @@
|
||||
using Cthangover.Core.Bootstrap;
|
||||
using Cthangover.Core.Settings;
|
||||
using Cthangover.Core.Events;
|
||||
using Cthangover.Core.Mods;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Godot;
|
||||
|
||||
namespace Cthangover.Mods.Time
|
||||
{
|
||||
/// <summary>
|
||||
/// Bridges the scene-event timer system to the in-game clock.
|
||||
/// Implements <see cref="Cthangover.Core.UI.Event.IOnTimeEvent"/>
|
||||
/// with priority 0 so that the tick is processed before most
|
||||
/// other listeners. The controller must be explicitly registered
|
||||
/// via <see cref="EnsureRegistered"/>, which finds the
|
||||
/// <see cref="Cthangover.Core.UI.Event.SceneEventController"/> in
|
||||
/// the scene tree and subscribes <see cref="OnTimerTick"/> to it.
|
||||
/// Registration is idempotent — subsequent calls are no-ops.
|
||||
/// </summary>
|
||||
public class TimeTickController : IOnTimeEvent
|
||||
{
|
||||
/// <summary>Executes before default-priority listeners so time
|
||||
/// updates are visible to all other tick handlers.</summary>
|
||||
public int Priority => 0;
|
||||
|
||||
private bool _registered;
|
||||
|
||||
/// <summary>
|
||||
/// Locates the <see cref="Cthangover.Core.UI.Event.SceneEventController"/>
|
||||
/// in the scene tree and registers this controller as a timer-tick
|
||||
/// listener. Safe to call multiple times — only the first call
|
||||
/// does work.
|
||||
/// </summary>
|
||||
public void EnsureRegistered(Node node)
|
||||
{
|
||||
if (_registered)
|
||||
return;
|
||||
var eventController = node.GetTree()?.Root?.FindChild("EventController", true, false) as SceneEventController;
|
||||
if (eventController == null)
|
||||
return;
|
||||
eventController.AddTimerTickEventListener(this);
|
||||
_registered = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the event system on each timer pulse. Advances
|
||||
/// the in-game clock by one minute via
|
||||
/// <see cref="TimeData.AddTick"/>.
|
||||
/// </summary>
|
||||
public void OnTimerTick()
|
||||
{
|
||||
// The SceneEventController keeps ticking (1s interval, ProcessMode
|
||||
// Always) while the launcher boot compiles mods in the background —
|
||||
// registration in GameData._Ready succeeds because the engine puts
|
||||
// every autoload into the tree before any _Ready fires. Touching
|
||||
// Runtime here would create it before the starter inventory can be
|
||||
// seeded through loaded mod factories: the seed then runs against an
|
||||
// empty registry, logs "Initialize refused" spam and permanently
|
||||
// skips the starter items. Skip boot-window ticks instead — the same
|
||||
// readiness contract GameData.Runtime enforces.
|
||||
if (!Boot.ModsReady)
|
||||
return;
|
||||
|
||||
GameData.Instance.Runtime.Time.AddTick();
|
||||
ModEventBus.Publish(new TimeTickEvent
|
||||
{
|
||||
TimeTick = GameData.Instance.Runtime.Time.Tick,
|
||||
NormalizedTime = GameData.Instance.Runtime.Time.Normalized,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
using Cthangover.Core.Bootstrap;
|
||||
using Cthangover.Core.Settings;
|
||||
using Cthangover.Core.Events;
|
||||
using Cthangover.Core.Mods;
|
||||
using Cthangover.Core.UI.Event;
|
||||
using Godot;
|
||||
|
||||
namespace Cthangover.Mods.Time
|
||||
{
|
||||
/// <summary>
|
||||
/// Bridges the scene-event timer system to the in-game clock.
|
||||
/// Implements <see cref="Cthangover.Core.UI.Event.IOnTimeEvent"/>
|
||||
/// with priority 0 so that the tick is processed before most
|
||||
/// other listeners. The controller must be explicitly registered
|
||||
/// via <see cref="EnsureRegistered"/>, which finds the
|
||||
/// <see cref="Cthangover.Core.UI.Event.SceneEventController"/> in
|
||||
/// the scene tree and subscribes <see cref="OnTimerTick"/> to it.
|
||||
/// Registration is idempotent — subsequent calls are no-ops.
|
||||
/// </summary>
|
||||
public class TimeTickController : IOnTimeEvent
|
||||
{
|
||||
/// <summary>Executes before default-priority listeners so time
|
||||
/// updates are visible to all other tick handlers.</summary>
|
||||
public int Priority => 0;
|
||||
|
||||
private bool _registered;
|
||||
|
||||
/// <summary>
|
||||
/// Locates the <see cref="Cthangover.Core.UI.Event.SceneEventController"/>
|
||||
/// in the scene tree and registers this controller as a timer-tick
|
||||
/// listener. Safe to call multiple times — only the first call
|
||||
/// does work.
|
||||
/// </summary>
|
||||
public void EnsureRegistered(Node node)
|
||||
{
|
||||
if (_registered)
|
||||
return;
|
||||
var eventController = node.GetTree()?.Root?.FindChild("EventController", true, false) as SceneEventController;
|
||||
if (eventController == null)
|
||||
return;
|
||||
eventController.AddTimerTickEventListener(this);
|
||||
_registered = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the event system on each timer pulse. Advances
|
||||
/// the in-game clock by one minute via
|
||||
/// <see cref="TimeData.AddTick"/>.
|
||||
/// </summary>
|
||||
public void OnTimerTick()
|
||||
{
|
||||
// The SceneEventController keeps ticking (1s interval, ProcessMode
|
||||
// Always) while the launcher boot compiles mods in the background —
|
||||
// registration in GameData._Ready succeeds because the engine puts
|
||||
// every autoload into the tree before any _Ready fires. Touching
|
||||
// Runtime here would create it before the starter inventory can be
|
||||
// seeded through loaded mod factories: the seed then runs against an
|
||||
// empty registry, logs "Initialize refused" spam and permanently
|
||||
// skips the starter items. Skip boot-window ticks instead — the same
|
||||
// readiness contract GameData.Runtime enforces.
|
||||
if (!Boot.ModsReady)
|
||||
return;
|
||||
|
||||
GameData.Instance.Runtime.Time.AddTick();
|
||||
ModEventBus.Publish(new TimeTickEvent
|
||||
{
|
||||
TimeTick = GameData.Instance.Runtime.Time.Tick,
|
||||
NormalizedTime = GameData.Instance.Runtime.Time.Normalized,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user