Day night cycle
This commit is contained in:
@@ -53,6 +53,7 @@ export class Client {
|
||||
this.#on_disconnect = on_disconnect;
|
||||
|
||||
this.level = new ClientLevel(connection.seed);
|
||||
this.level.time = connection.time;
|
||||
for (const [x, y, z, id, state] of connection.initial_changes) {
|
||||
this.level.record_change(x, y, z, id, state);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import type { Client } from "$/client/client.ts";
|
||||
import { DebugUI } from "$/client/debug_ui.ts";
|
||||
import { format_clock } from "$/common/time.ts";
|
||||
|
||||
// f3: every entity's fields, editable
|
||||
export class DebugOverlay {
|
||||
render(client: Client) {
|
||||
DebugUI.begin("Entities", 10, 10, 300);
|
||||
DebugUI.text(`${format_clock(client.level.time)} (tick ${client.level.time})`);
|
||||
DebugUI.separator();
|
||||
|
||||
for (const entity of client.level.entities.values()) {
|
||||
if (DebugUI.collapsing_header(`${entity.constructor.name} - ${entity.id}`)) {
|
||||
|
||||
@@ -87,6 +87,8 @@ export class ClientLevel {
|
||||
second_timer = 0;
|
||||
tick_timer = 0;
|
||||
seed: string;
|
||||
// world time in ticks, counted here between the server's updates. see common/time.ts
|
||||
time = 0;
|
||||
|
||||
// blocks players changed from the generated terrain, per chunk, so they survive reloading chunks
|
||||
changes = new Map<string, Map<string, BlockChange>>();
|
||||
@@ -129,6 +131,7 @@ export class ClientLevel {
|
||||
}
|
||||
|
||||
tick() {
|
||||
this.time += 1;
|
||||
for (const entity of this.entities.values()) {
|
||||
entity.save_previous_position();
|
||||
entity.tick();
|
||||
|
||||
@@ -100,6 +100,9 @@ function client_context(listing: ModListing): ClientContext {
|
||||
if (nid === AIR) return AIR_ID;
|
||||
return EverythingRegistry.get_by_id<BlockRegistry>("blocks", nid)?.id;
|
||||
},
|
||||
get time() {
|
||||
return need_client().level.time;
|
||||
},
|
||||
},
|
||||
log: (...args) => console.log(`[${mod}]`, ...args),
|
||||
};
|
||||
|
||||
@@ -11,6 +11,7 @@ export class Connection {
|
||||
initial_changes: BlockChange[];
|
||||
spawn: { x: number; y: number; z: number; yaw: number; pitch: number };
|
||||
selected_slot: number;
|
||||
time: number;
|
||||
// who was already there when we joined, they become entities in the level
|
||||
initial_players: PlayerInfo[];
|
||||
initial_entities: EntityInfo[];
|
||||
@@ -24,6 +25,7 @@ export class Connection {
|
||||
this.initial_changes = join.changes;
|
||||
this.spawn = join.spawn;
|
||||
this.selected_slot = join.selected_slot;
|
||||
this.time = join.time;
|
||||
this.initial_players = join.players;
|
||||
this.initial_entities = join.entities;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,9 @@ export class ClientPacketListener {
|
||||
case "player_join":
|
||||
level.add_entity(new RemotePlayer(level, message.player));
|
||||
break;
|
||||
case "time":
|
||||
level.time = message.time;
|
||||
break;
|
||||
case "player_leave":
|
||||
level.remove_entity(message.id);
|
||||
break;
|
||||
|
||||
@@ -1,19 +1,41 @@
|
||||
import type { Client } from "$/client/client.ts";
|
||||
import { begin_mode_3d, end_mode_3d } from "$/client/renderer/mod.ts";
|
||||
import { begin_mode_3d, clear_background, end_mode_3d, update_lightmap } from "$/client/renderer/mod.ts";
|
||||
import { daylight } from "$/common/time.ts";
|
||||
import { Hud } from "$/client/gui/hud.ts";
|
||||
import { DebugOverlay } from "$/client/gui/debug_overlay.ts";
|
||||
import { LevelRenderer } from "./level_renderer.ts";
|
||||
|
||||
// the sky at noon and in the middle of the night
|
||||
const DAY_SKY = [0.69, 0.8, 1];
|
||||
const NIGHT_SKY = [0.02, 0.03, 0.08];
|
||||
// minecraft's darkest sky: moonlight still lights things a little
|
||||
const NIGHT_SKY_LIGHT = 0.2;
|
||||
|
||||
// draws a frame, like minecraft's GameRenderer: the level from the camera, then the hud and screens on top
|
||||
export class GameRenderer {
|
||||
level_renderer = new LevelRenderer();
|
||||
hud = new Hud();
|
||||
debug_overlay = new DebugOverlay();
|
||||
// what the lightmap was last made for, so it's only rebuilt when the light changes
|
||||
#lightmap_daylight = -1;
|
||||
|
||||
// sky color and sky light for the time of day
|
||||
#setup_sky(client: Client, partial_tick: number) {
|
||||
const light = daylight(client.level.time + partial_tick);
|
||||
const [r, g, b] = DAY_SKY.map((day, i) => NIGHT_SKY[i] + (day - NIGHT_SKY[i]) * light);
|
||||
clear_background(r, g, b, 1);
|
||||
|
||||
if (Math.abs(light - this.#lightmap_daylight) > 0.001) {
|
||||
this.#lightmap_daylight = light;
|
||||
update_lightmap(NIGHT_SKY_LIGHT + (1 - NIGHT_SKY_LIGHT) * light);
|
||||
}
|
||||
}
|
||||
|
||||
// partial_tick is how far this frame is between the last tick and the next, entities are drawn in between
|
||||
render(client: Client, partial_tick: number) {
|
||||
const camera = client.camera;
|
||||
camera.setup(client.player, partial_tick);
|
||||
this.#setup_sky(client, partial_tick);
|
||||
|
||||
begin_mode_3d(camera);
|
||||
this.level_renderer.render_opaque(client.level, camera);
|
||||
|
||||
Reference in New Issue
Block a user