Code/WeatherKind.cs

Defines a WeatherKind enum (Clear, Cloudy, Rain) and a deterministic WeatherRoll.For(seed, dayIndex) that uses an FNV-1a style 64-bit hash to pick a weather kind with ~60/25/15 distribution. It is pure, deterministic, and intended to match an external game's hashing for compatibility.

using System;

namespace FieldGuide.DayNight;

/// <summary>Weather kinds (visual-only). Rolled per in-game day as a PURE hash of (seed, dayIndex), so a host
/// and every observer agree on the day's weather from the replicated seed + clock alone, with no extra
/// networking. The int order is the wire/override value: an authority pin publishes the forced kind as its
/// int, and any deserializer maps back through this enum.</summary>
public enum WeatherKind
{
	Clear = 0,
	Cloudy = 1,
	Rain = 2,
}

/// <summary>The deterministic per-day weather roll. Pure and self-contained: no DateTime, no System.Random,
/// just an FNV-1a hash of the world seed and the day index bucketed into the three kinds. Same inputs always
/// yield the same kind, so two peers deriving weather from the same seed never disagree and the roll never
/// flaps mid-day.</summary>
public static class WeatherRoll
{
	/// <summary>Roll the weather for a given (world seed, day index). Distribution: ~60% Clear, ~25% Cloudy,
	/// ~15% Rain. Byte-stable and deterministic; the hash (offset basis, prime, salt) is ported unchanged from
	/// the source game, so a save that recorded a WB day rolls the same kind here.</summary>
	public static WeatherKind For( int seed, int dayIndex )
	{
		ulong h = 1469598103934665603UL;   // FNV-1a offset basis
		void Mix( long v )
		{
			for ( int i = 0; i < 8; i++ ) { h ^= (byte)(v >> (i * 8)); h *= 1099511628211UL; }
		}
		Mix( seed );
		Mix( dayIndex );
		Mix( 0x5713_9A2FL );   // fixed salt so dayIndex 0 isn't a bare seed hash (ported verbatim)
		int r = (int)(h % 100);
		if ( r < 60 ) return WeatherKind.Clear;   // ~60% clear, ~25% cloudy, ~15% rain
		if ( r < 85 ) return WeatherKind.Cloudy;
		return WeatherKind.Rain;
	}
}