Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sisilicon
GitHub Repository: sisilicon/worldedit-be
Path: blob/master/src/gametest/record.ts
1782 views
1
import { Vector3, Vector2, system, CommandPermissionLevel, CustomCommandParamType, Player, CustomCommandStatus } from "@minecraft/server";
2
import { Server, sleep, Databases } from "@notbeer-api";
3
4
interface RecordedOperation {
5
command: string;
6
args: string[];
7
position: Vector3;
8
rotation: Vector2;
9
}
10
11
const recording = new Map<string, RecordedOperation[]>();
12
13
system.beforeEvents.startup.subscribe((ev) => {
14
ev.customCommandRegistry.registerEnum("wedit:recordAction", ["start", "save", "stop", "replay", "list"]);
15
ev.customCommandRegistry.registerCommand(
16
{
17
name: "wedit:record",
18
description: "Record a bunch of worldedit commands to repeat later",
19
permissionLevel: CommandPermissionLevel.Admin,
20
mandatoryParameters: [{ name: "wedit:recordAction", type: CustomCommandParamType.Enum }],
21
optionalParameters: [{ name: "filename", type: CustomCommandParamType.String }],
22
},
23
(origin, action: string, filename: string) => {
24
const player = origin.sourceEntity as Player;
25
if (action === "start") startRecording(player);
26
else if (action === "save") saveRecording(player, filename);
27
else if (action === "stop") stopRecording(player);
28
else if (action === "replay") replayRecording(player, filename);
29
else if (action === "list") listRecordings(player);
30
return { status: CustomCommandStatus.Success };
31
}
32
);
33
});
34
35
Server.command.on("runCommand", (player, command, args) => {
36
if (!recording.has(player.id)) return;
37
38
recording.get(player.id).push({
39
command,
40
args,
41
position: player.location,
42
rotation: player.getRotation(),
43
});
44
});
45
46
function startRecording(player: Player) {
47
if (recording.has(player.id)) throw "You are already recording!";
48
recording.set(player.id, []);
49
player.sendMessage("Started recording!");
50
}
51
52
function stopRecording(player: Player) {
53
if (!recording.has(player.id)) throw "You are not recording!";
54
recording.delete(player.id);
55
player.sendMessage("Stopped recording!");
56
}
57
58
function saveRecording(player: Player, filename: string) {
59
if (!recording.has(player.id)) throw "You are not recording!";
60
if (!filename) throw "You must provide a filename to save to!";
61
62
const operations = recording.get(player.id);
63
recording.delete(player.id);
64
65
const records = getRecordDatabase(player);
66
records.data[filename] = operations;
67
records.save();
68
69
player.sendMessage(`Saved ${operations.length} operations to '${filename}'`);
70
}
71
72
async function replayRecording(player: Player, filename: string) {
73
await sleep(1); // Wait a tick to get out of before event context
74
if (!filename) throw "You must provide a filename to load from!";
75
76
const records = getRecordDatabase(player);
77
if (!(filename in records.data)) throw `No recording found with the name '${filename}'`;
78
79
const operations = records.data[filename];
80
player.sendMessage(`Replaying ${operations.length} operations from '${filename}'`);
81
82
for (const op of operations) {
83
player.teleport(op.position, { rotation: op.rotation });
84
const thread = Server.command.callCommand(player, op.command, op.args);
85
while (thread.isActive()) await sleep(1);
86
}
87
}
88
89
function listRecordings(player: Player) {
90
player.sendMessage(
91
`Saved recordings: ${Object.keys(getRecordDatabase(player).data)
92
.map((f) => `\n- ${f}`)
93
.join("")}`
94
);
95
}
96
97
function getRecordDatabase(player: Player) {
98
return Databases.load<{ [filename: string]: RecordedOperation[] }>("recordings", player);
99
}
100
101