Day night cycle
This commit is contained in:
@@ -11,7 +11,11 @@ export interface ClientContext {
|
||||
net: ClientNet;
|
||||
player: { readonly name: string; readonly position: Readonly<Position> };
|
||||
// read only, what this client sees
|
||||
world: { get_block(x: number, y: number, z: number): Id | undefined };
|
||||
world: {
|
||||
get_block(x: number, y: number, z: number): Id | undefined;
|
||||
// ticks since 06:00 of day 1, see ServerWorld.time
|
||||
readonly time: number;
|
||||
};
|
||||
log(...args: unknown[]): void;
|
||||
}
|
||||
|
||||
|
||||
@@ -128,6 +128,9 @@ export interface ServerWorld {
|
||||
drop_item(x: number, y: number, z: number, item: ItemStack): void;
|
||||
is_loaded(x: number, z: number): boolean;
|
||||
readonly seed: string;
|
||||
// ticks since 06:00 of day 1. a day is 36000 ticks (06:00 to 18:00), a night 12000
|
||||
readonly time: number;
|
||||
set_time(time: number): void;
|
||||
}
|
||||
|
||||
export interface Player {
|
||||
|
||||
+6
-2
@@ -7,7 +7,7 @@ export const AIR_ID = "bworld:air";
|
||||
|
||||
// bump when a client and server of different versions can't play together.
|
||||
// the server rejects a different version before the client downloads anything
|
||||
export const PROTOCOL_VERSION = 2;
|
||||
export const PROTOCOL_VERSION = 3;
|
||||
|
||||
export interface PlayerInfo {
|
||||
id: string;
|
||||
@@ -101,6 +101,8 @@ export type ServerMessage =
|
||||
changes: BlockChange[];
|
||||
spawn: { x: number; y: number; z: number; yaw: number; pitch: number };
|
||||
selected_slot: number;
|
||||
// world time in ticks, see common/time.ts
|
||||
time: number;
|
||||
}
|
||||
| { type: "player_join"; player: PlayerInfo }
|
||||
| { type: "player_leave"; id: string }
|
||||
@@ -120,7 +122,9 @@ export type ServerMessage =
|
||||
| { type: "cursor"; item: ItemData | null }
|
||||
| { type: "open_screen"; layout: ScreenLayout; properties: Record<string, number> }
|
||||
| { type: "screen_properties"; properties: Record<string, number> }
|
||||
| { type: "close_screen" };
|
||||
| { type: "close_screen" }
|
||||
// the world time, every second and when it's changed. clients count ticks in between
|
||||
| { type: "time"; time: number };
|
||||
|
||||
export const MAX_NAME_LENGTH = 16;
|
||||
export const MAX_CHAT_LENGTH = 256;
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
// the day and night cycle. world time counts ticks since 06:00 of day 1, it never wraps around
|
||||
import { TICKS_PER_SECOND } from "./constants.ts";
|
||||
|
||||
// 30 minutes of day, 06:00 to 18:00
|
||||
export const DAY_TICKS = 30 * 60 * TICKS_PER_SECOND;
|
||||
// 10 minutes of night, 18:00 to 06:00
|
||||
export const NIGHT_TICKS = 10 * 60 * TICKS_PER_SECOND;
|
||||
export const CYCLE_TICKS = DAY_TICKS + NIGHT_TICKS;
|
||||
// dusk right after sunset and dawn right before sunrise, so the whole day is bright
|
||||
export const TWILIGHT_TICKS = 60 * TICKS_PER_SECOND;
|
||||
|
||||
// in game hours are longer during the day than at night, since both halves are 12 hours
|
||||
const DAY_TICKS_PER_HOUR = DAY_TICKS / 12;
|
||||
const NIGHT_TICKS_PER_HOUR = NIGHT_TICKS / 12;
|
||||
// from midnight to 06:00, to count days from midnight
|
||||
const TICKS_BEFORE_SIX = 6 * NIGHT_TICKS_PER_HOUR;
|
||||
|
||||
// named times of day, as ticks into the cycle
|
||||
export const TIMES_OF_DAY: Record<string, number> = {
|
||||
day: 0,
|
||||
noon: 6 * DAY_TICKS_PER_HOUR,
|
||||
sunset: DAY_TICKS,
|
||||
night: DAY_TICKS + TWILIGHT_TICKS,
|
||||
midnight: DAY_TICKS + 6 * NIGHT_TICKS_PER_HOUR,
|
||||
};
|
||||
|
||||
// ticks into the current cycle, 0 is 06:00
|
||||
export function time_of_day(time: number): number {
|
||||
return ((time % CYCLE_TICKS) + CYCLE_TICKS) % CYCLE_TICKS;
|
||||
}
|
||||
|
||||
export function is_day(time: number): boolean {
|
||||
return time_of_day(time) < DAY_TICKS;
|
||||
}
|
||||
|
||||
// the day number, starting at 1 and going up at midnight, and the time on a 24 hour clock
|
||||
export function clock(time: number): { day: number; hour: number; minute: number } {
|
||||
const t = time_of_day(time);
|
||||
const hours = t < DAY_TICKS ? 6 + t / DAY_TICKS_PER_HOUR : 18 + (t - DAY_TICKS) / NIGHT_TICKS_PER_HOUR;
|
||||
const total_minutes = Math.floor(hours * 60) % (24 * 60);
|
||||
return {
|
||||
day: Math.floor((time + TICKS_BEFORE_SIX) / CYCLE_TICKS) + 1,
|
||||
hour: Math.floor(total_minutes / 60),
|
||||
minute: total_minutes % 60,
|
||||
};
|
||||
}
|
||||
|
||||
// like "Day 3, 14:05"
|
||||
export function format_clock(time: number): string {
|
||||
const { day, hour, minute } = clock(time);
|
||||
return `Day ${day}, ${String(hour).padStart(2, "0")}:${String(minute).padStart(2, "0")}`;
|
||||
}
|
||||
|
||||
// how much daylight there is, 1 all day and 0 in the middle of the night, fading through dusk and dawn.
|
||||
// time can be fractional, for drawing between ticks
|
||||
export function daylight(time: number): number {
|
||||
const t = time_of_day(time);
|
||||
if (t < DAY_TICKS) return 1;
|
||||
const into_night = t - DAY_TICKS;
|
||||
const until_day = CYCLE_TICKS - t;
|
||||
const fade = Math.min(1, into_night / TWILIGHT_TICKS, until_day / TWILIGHT_TICKS);
|
||||
return 1 - smoothstep(fade);
|
||||
}
|
||||
|
||||
function smoothstep(x: number) {
|
||||
return x * x * (3 - 2 * x);
|
||||
}
|
||||
Reference in New Issue
Block a user