Skip to content

Commit

Permalink
Merge branch 'rc-1' of https://github.com/SerenityJS/Serenity into rc-1
Browse files Browse the repository at this point in the history
  • Loading branch information
Felipe-Devr committed Nov 6, 2024
2 parents bddc139 + 2d697b9 commit 4311f9a
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 6 deletions.
13 changes: 8 additions & 5 deletions packages/core/src/entity/entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -550,11 +550,14 @@ class Entity {
health.currentValue = health.effectiveMin;
}

// If the entity is not a player, despawn the entity
if (!this.isPlayer()) this.despawn();
// Manually trigger the onDespawn trait event for players
// We does this because the player has the option to disconnect at the respawn screen
else for (const trait of this.traits.values()) trait.onDespawn?.();
// Schedule the entity to despawn
this.dimension.schedule(50).on(() => {
// If the entity is not a player, despawn the entity
if (!this.isPlayer()) this.despawn();
// Manually trigger the onDespawn trait event for players
// We does this because the player has the option to disconnect at the respawn screen
else for (const trait of this.traits.values()) trait.onDespawn?.();
});
}

/**
Expand Down
17 changes: 17 additions & 0 deletions packages/core/src/world/dimension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { CommandExecutionState } from "../commands";
import { World } from "./world";
import { TerrainGenerator } from "./generator";
import { Chunk } from "./chunk";
import { TickSchedule } from "./schedule";

const DefaultDimensionProperties: DimensionProperties = {
identifier: "overworld",
Expand Down Expand Up @@ -617,6 +618,22 @@ class Dimension {
return state.execute() as CommandResponse<T>;
}

/**
* Schedule an execution of a function after a specified amount of ticks.
* @param ticks The amount of ticks to wait before the schedule is complete.
* @returns The created tick schedule.
*/
public schedule(ticks: number): TickSchedule {
// Create a new tick schedule
const schedule = new TickSchedule(ticks, this);

// Add the schedule to the world
this.world.schedules.add(schedule);

// Return the schedule
return schedule;
}

/**
* Broadcast packets to all the players in the dimension.
* @param packets The packets to broadcast.
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/world/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from "./chunk";
export * from "./dimension";
export * from "./provider";
export * from "./generator";
export * from "./schedule";
72 changes: 72 additions & 0 deletions packages/core/src/world/schedule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { Dimension } from "./dimension";

import type { World } from "./world";

class TickSchedule {
/**
* The amount of ticks to wait before the schedule is complete.
*/
public readonly scheduledTick: bigint;

/**
* The tick at which the schedule will be complete.
*/
public readonly completeTick: bigint;

/**
* The callbacks to call when the schedule is complete.
*/
public readonly callbacks = new Set<() => void>();

/**
* Creates a new tick schedule.
* @param scheduledTick The amount of ticks to wait before the schedule is complete.
* @param worldOrDimension The world or dimension to schedule the tick in.
*/
public constructor(
scheduledTick: bigint | number,
worldOrDimension: World | Dimension
) {
// Set the scheduled tick
this.scheduledTick = BigInt(scheduledTick);

// Get the world from the constructor
const world =
worldOrDimension instanceof Dimension
? worldOrDimension.world
: worldOrDimension;

// Get the current tick
const currentTick = world.currentTick;

// Calculate the complete tick
this.completeTick = currentTick + this.scheduledTick;
}

/**
* Executes all the callbacks in the schedule.
*/
public execute(): void {
// Call all the callbacks
for (const callback of this.callbacks) callback();
}

/**
* Adds a callback to the schedule.
* @param callback The callback to add.
*/
public on(callback: () => void): void {
// Add the callback to the schedule
this.callbacks.add(callback);
}

/**
* Cancels the schedule.
*/
public cancel(): void {
// Clear all the callbacks
this.callbacks.clear();
}
}

export { TickSchedule };
47 changes: 46 additions & 1 deletion packages/core/src/world/world.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { EffectPallete } from "../effect";

import { WorldProvider } from "./provider";
import { DefaultDimensionProperties, Dimension } from "./dimension";
import { TickSchedule } from "./schedule";

const DefaultWorldProperties: WorldProperties = {
identifier: "default",
Expand Down Expand Up @@ -76,7 +77,7 @@ class World extends Emitter<WorldEventSignals> {
public readonly entityPalette = new EntityPalette();

/**
* The effect pallete of the world.
* The effect palette of the world.
*/
public readonly effectPalette = new EffectPallete();

Expand All @@ -95,6 +96,11 @@ class World extends Emitter<WorldEventSignals> {
*/
public readonly commands = new Commands();

/**
* The pending schedules of the world.
*/
public readonly schedules = new Set<TickSchedule>();

/**
* The current tick of the world.
*/
Expand Down Expand Up @@ -180,6 +186,29 @@ class World extends Emitter<WorldEventSignals> {
// Broadcast the time packet to all players
this.broadcast(packet);
}

// Check if there are any schedules to execute
if (this.schedules.size > 0) {
// Iterate over the schedules
for (const schedule of this.schedules) {
// Check if the schedule is complete
if (this.currentTick >= schedule.completeTick) {
// Execute the schedule
try {
schedule.execute();
} catch (reason) {
// Log the error if the schedule failed to execute
this.logger.error(
`Failed to execute schedule for dimension at tick ${schedule.completeTick}`,
reason
);
}

// Delete the schedule
this.schedules.delete(schedule);
}
}
}
}

/**
Expand Down Expand Up @@ -298,6 +327,22 @@ class World extends Emitter<WorldEventSignals> {
);
}

/**
* Schedule an execution of a function after a specified amount of ticks.
* @param ticks The amount of ticks to wait before the schedule is complete.
* @returns The created tick schedule.
*/
public schedule(ticks: number): TickSchedule {
// Create a new tick schedule
const schedule = new TickSchedule(ticks, this);

// Add the schedule to the world
this.schedules.add(schedule);

// Return the schedule
return schedule;
}

public broadcast(...packets: Array<DataPacket>): void {
for (const player of this.getPlayers()) player.send(...packets);
}
Expand Down

0 comments on commit 4311f9a

Please sign in to comment.