Day night cycle
This commit is contained in:
@@ -26,6 +26,7 @@ import {
|
||||
} from "$/common/protocol.ts";
|
||||
import type { AtlasListing, ModListing, RecipeBook } from "$/common/mod_loader.ts";
|
||||
import type { WorldgenSetup } from "$/common/generation.ts";
|
||||
import { CYCLE_TICKS, format_clock, time_of_day, TIMES_OF_DAY } from "$/common/time.ts";
|
||||
import { ModRuntime, run_guarded } from "./mod_runtime.ts";
|
||||
import type { GameLoop } from "./game_loop.ts";
|
||||
import { consume_recipe_items, update_crafting_result } from "./crafting.ts";
|
||||
@@ -62,6 +63,8 @@ export interface GameHost {
|
||||
export interface SavedWorld {
|
||||
version: 3;
|
||||
seed: string;
|
||||
// world time in ticks, 0 in saves from before the day and night cycle
|
||||
time?: number;
|
||||
changes: BlockChange[];
|
||||
tiles: SavedTile[];
|
||||
// every ctx.containers container, by id
|
||||
@@ -124,6 +127,7 @@ export class GameServer {
|
||||
this.world = new ServerWorld(saved?.seed ?? default_seed, mods.worldgen);
|
||||
this.mods.storage = saved?.mod_storage ?? {};
|
||||
this.world.load_changes(saved?.changes ?? []);
|
||||
this.world.time = saved?.time ?? 0;
|
||||
for (const [id, items] of Object.entries(saved?.containers ?? {})) {
|
||||
const container = new Container(items.length);
|
||||
container.load(items);
|
||||
@@ -188,7 +192,11 @@ export class GameServer {
|
||||
|
||||
tick() {
|
||||
this.#tick += 1;
|
||||
this.world.time += 1;
|
||||
const second = this.#tick % TICKS_PER_SECOND === 0;
|
||||
if (second) {
|
||||
this.#broadcast({ type: "time", time: this.world.time });
|
||||
}
|
||||
|
||||
for (const tile of [...this.world.tiles.values()]) {
|
||||
if (tile.mod_data === undefined) {
|
||||
@@ -236,6 +244,7 @@ export class GameServer {
|
||||
const saved: SavedWorld = {
|
||||
version: 3,
|
||||
seed: this.world.seed,
|
||||
time: this.world.time,
|
||||
changes: this.world.all_changes(),
|
||||
tiles: [...this.world.tiles.values()].map((tile) => ({
|
||||
id: tile.id,
|
||||
@@ -342,6 +351,12 @@ export class GameServer {
|
||||
this.#broadcast({ type: "player_move", id: player.id, x, y, z, yaw: player.yaw, pitch: player.pitch }, player);
|
||||
}
|
||||
|
||||
set_time(time: number) {
|
||||
this.world.time = time;
|
||||
this.world.dirty = true;
|
||||
this.#broadcast({ type: "time", time });
|
||||
}
|
||||
|
||||
// changes a block's state bits without anything else happening, see ServerWorld.get_block_value
|
||||
set_block_state(x: number, y: number, z: number, state: number) {
|
||||
const id = this.world.get_block_id(x, y, z);
|
||||
@@ -511,6 +526,7 @@ export class GameServer {
|
||||
entities: [...this.#entities.values()].map((entity) => entity.info()),
|
||||
spawn: { x: player.x, y: player.y, z: player.z, yaw: player.yaw, pitch: player.pitch },
|
||||
selected_slot: player.selected_slot,
|
||||
time: this.world.time,
|
||||
});
|
||||
this.#players.set(conn, player);
|
||||
this.#sync(player);
|
||||
@@ -820,6 +836,10 @@ export class GameServer {
|
||||
this.give(player, item_id, amount);
|
||||
return;
|
||||
}
|
||||
if (command === "time") {
|
||||
this.#time_command(player, args);
|
||||
return;
|
||||
}
|
||||
if (command === "tps") {
|
||||
if (!this.loop) {
|
||||
this.#send(player, { type: "chat", text: "The game loop isn't running" });
|
||||
@@ -841,6 +861,30 @@ export class GameServer {
|
||||
this.#send(player, { type: "chat", text: `Unknown command /${command}` });
|
||||
}
|
||||
|
||||
// /time shows the time, /time set <ticks or day, noon, sunset, night, midnight> changes it, /time add <ticks>
|
||||
#time_command(player: ServerPlayer, [action, value]: string[]) {
|
||||
const usage = "Usage: /time [set <ticks|day|noon|sunset|night|midnight> | add <ticks>]";
|
||||
if (action === undefined) {
|
||||
this.#send(player, { type: "chat", text: `${format_clock(this.world.time)} (tick ${this.world.time})` });
|
||||
return;
|
||||
}
|
||||
const ticks = Number(value);
|
||||
if (action === "set" && value !== undefined && value in TIMES_OF_DAY) {
|
||||
// the next time it's that time of day, so days keep counting up
|
||||
const now = this.world.time;
|
||||
const target = now - time_of_day(now) + TIMES_OF_DAY[value];
|
||||
this.set_time(target >= now ? target : target + CYCLE_TICKS);
|
||||
} else if (action === "set" && Number.isInteger(ticks) && ticks >= 0) {
|
||||
this.set_time(ticks);
|
||||
} else if (action === "add" && Number.isInteger(ticks) && this.world.time + ticks >= 0) {
|
||||
this.set_time(this.world.time + ticks);
|
||||
} else {
|
||||
this.#send(player, { type: "chat", text: usage });
|
||||
return;
|
||||
}
|
||||
this.#broadcast({ type: "chat", text: `${player.name} set the time to ${format_clock(this.world.time)}` });
|
||||
}
|
||||
|
||||
#close_screen(player: ServerPlayer) {
|
||||
const screen = player.screen;
|
||||
player.screen = undefined;
|
||||
|
||||
@@ -310,7 +310,9 @@ export class ModRuntime {
|
||||
if (!/^[a-z0-9_]+$/.test(name)) {
|
||||
throw new ModLoadError(mod, `command name "${name}" must be a-z, 0-9 and _`);
|
||||
}
|
||||
if (["give", "tps"].includes(name)) throw new ModLoadError(mod, `/${name} belongs to the engine`);
|
||||
if (["give", "tps", "time"].includes(name)) {
|
||||
throw new ModLoadError(mod, `/${name} belongs to the engine`);
|
||||
}
|
||||
const existing = this.commands.get(name);
|
||||
if (existing) {
|
||||
throw new ModLoadError(mod, `/${name} is also registered by ${existing.mod}`);
|
||||
@@ -363,6 +365,15 @@ export class ModRuntime {
|
||||
get seed() {
|
||||
return game().world.seed;
|
||||
},
|
||||
get time() {
|
||||
return game().world.time;
|
||||
},
|
||||
set_time: (time) => {
|
||||
if (!Number.isInteger(time) || time < 0) {
|
||||
throw new Error(`time must be a whole number of ticks, not ${time}`);
|
||||
}
|
||||
game().set_time(time);
|
||||
},
|
||||
},
|
||||
players: {
|
||||
all: () => game().players().map((p) => this.player(p)),
|
||||
|
||||
@@ -41,6 +41,9 @@ export class ServerWorld {
|
||||
#changes = new Map<number, Map<string, BlockChange>>();
|
||||
tiles = new Map<string, Tile>();
|
||||
|
||||
// ticks since 06:00 of day 1, see common/time.ts
|
||||
time = 0;
|
||||
|
||||
// set when anything that gets saved changes
|
||||
dirty = false;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user