Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
mamayaya1
GitHub Repository: mamayaya1/game
Path: blob/main/projects/draw-the-hill/scripts/dispatchworker.js
4624 views
1
"use strict";
2
self.inputPort = null;
3
self.jobQueue = [];
4
self.jobWorkers = [];
5
self.sentBlobs = [];
6
self.sentBuffers = [];
7
self.importedScripts = [];
8
self.lastBroadcasts = new Map();
9
class JobWorker {
10
constructor(port, number) {
11
this._port = port;
12
this._number = number;
13
this._isReady = false;
14
this._isBusy = false;
15
this._port.onmessage = (e) => this._OnMessage(e.data);
16
}
17
ImportScripts(scripts) {
18
this._port.postMessage({ type: "_import_scripts", scripts: scripts });
19
}
20
SendBlob(blob, id) {
21
this._port.postMessage({ type: "_send_blob", blob: blob, id: id });
22
}
23
SendBuffer(buffer, id) {
24
this._port.postMessage({ type: "_send_buffer", buffer: buffer, id: id });
25
}
26
SendJob(job) {
27
if (this._isBusy || !this._isReady) throw new Error("cannot take job");
28
this._isBusy = true;
29
this._port.postMessage(job, job["transferables"]);
30
}
31
_InitBroadcast(job) {
32
this._port.postMessage(job, job["transferables"]);
33
}
34
SendReady() {
35
this._port.postMessage({ type: "_ready" });
36
}
37
IsReady() {
38
return this._isReady;
39
}
40
_OnReady() {
41
this._isReady = true;
42
this.MaybeStartNextJob();
43
}
44
IsBusy() {
45
return this._isBusy;
46
}
47
GetNumber() {
48
return this._number;
49
}
50
_OnMessage(msg) {
51
const type = msg["type"];
52
switch (type) {
53
case "ready":
54
this._OnReady();
55
return;
56
case "done":
57
this._OnJobDone();
58
return;
59
default:
60
console.error("unknown message from worker '" + type + "'");
61
return;
62
}
63
}
64
_OnJobDone() {
65
this._isBusy = false;
66
this.MaybeStartNextJob();
67
}
68
MaybeStartNextJob() {
69
if (this._isBusy || !this._isReady) return;
70
const i = this._FindAvailableJob();
71
if (i === -1) return;
72
const job = self.jobQueue[i];
73
const isBroadcast = job["isBroadcast"];
74
if (isBroadcast) {
75
job["doneFlags"][this._number] = true;
76
if (job["doneFlags"].every((x) => x)) self.jobQueue.splice(i, 1);
77
} else self.jobQueue.splice(i, 1);
78
this.SendJob(job);
79
}
80
_FindAvailableJob() {
81
for (let i = 0, len = self.jobQueue.length; i < len; ++i) {
82
const job = self.jobQueue[i];
83
if (!job["isBroadcast"] || (this._number < job["doneFlags"].length && !job["doneFlags"][this._number])) return i;
84
}
85
return -1;
86
}
87
TestMessageChannel() {
88
this._port.postMessage({ type: "_testMessageChannel" });
89
}
90
}
91
let number = 0;
92
function AddJobWorker(port) {
93
const jobWorker = new JobWorker(port, number++);
94
self.jobWorkers.push(jobWorker);
95
for (const [blob, id] of self.sentBlobs) jobWorker.SendBlob(blob, id);
96
for (const [buffer, id] of self.sentBuffers) jobWorker.SendBuffer(buffer, id);
97
for (const scripts of self.importedScripts) jobWorker.ImportScripts(scripts);
98
for (const broadcastJob of self.lastBroadcasts.values()) jobWorker._InitBroadcast(broadcastJob);
99
jobWorker.SendReady();
100
}
101
function CancelJob(jobId) {
102
for (let i = 0, len = self.jobQueue.length; i < len; ++i)
103
if (self.jobQueue[i].jobId === jobId) {
104
self.jobQueue.splice(i, 1);
105
return;
106
}
107
}
108
self.addEventListener("message", (e) => {
109
const msg = e.data;
110
const type = msg["type"];
111
if (type === "_init") {
112
self.inputPort = msg["in-port"];
113
self.inputPort.onmessage = OnInputPortMessage;
114
} else if (type === "_addJobWorker") AddJobWorker(msg["port"]);
115
});
116
function OnInputPortMessage(e) {
117
const msg = e.data;
118
const type = msg["type"];
119
if (type === "_cancel") {
120
CancelJob(msg.jobId);
121
return;
122
} else if (type === "_import_scripts") {
123
const scripts = msg["scripts"];
124
for (const w of self.jobWorkers) w.ImportScripts(scripts);
125
self.importedScripts.push(scripts);
126
return;
127
} else if (type === "_send_blob") {
128
const blob = msg["blob"];
129
const id = msg["id"];
130
for (const w of self.jobWorkers) w.SendBlob(blob, id);
131
self.sentBlobs.push([blob, id]);
132
return;
133
} else if (type === "_send_buffer") {
134
const buffer = msg["buffer"];
135
const id = msg["id"];
136
for (const w of self.jobWorkers) w.SendBuffer(buffer, id);
137
self.sentBuffers.push([buffer, id]);
138
return;
139
} else if (type === "_no_more_workers") {
140
self.sentBlobs.length = 0;
141
self.sentBuffers.length = 0;
142
self.importedScripts.length = 0;
143
self.lastBroadcasts.clear();
144
return;
145
} else if (type === "_testMessageChannel") {
146
self.jobWorkers[0].TestMessageChannel();
147
return;
148
}
149
self.jobQueue.push(msg);
150
if (msg["isBroadcast"]) {
151
msg["doneFlags"] = new Array(self.jobWorkers.length).fill(false);
152
msg["transferables"] = [];
153
self.lastBroadcasts.set(msg["type"], msg);
154
}
155
for (const w of self.jobWorkers) w.MaybeStartNextJob();
156
}
157