mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-14 07:24:52 +09:00
Send the research queue to followers after a finished technology is removed
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
bedfe0873b
commit
2035f5bc2c
5 files changed
+66
-12
No files matched your search
@@ -86,16 +86,25 @@ export default async function(context: ControllerPluginContext) {
|
||||
return controller.instances.get(src.id)?.config.get("instance.name") ?? String(src.id);
|
||||
}
|
||||
|
||||
// Removes one entry per level that finished
|
||||
function removeFinished(name: string, levels = 1) {
|
||||
// Removes one entry per level that finished, returns whether any was removed
|
||||
function removeFinished(name: string, levels = 1): boolean {
|
||||
let removed = false;
|
||||
for (let i = 0; i < levels; i++) {
|
||||
let index = queue.indexOf(name);
|
||||
if (index === -1) {
|
||||
return;
|
||||
break;
|
||||
}
|
||||
queue.splice(index, 1);
|
||||
queueDirty = true;
|
||||
removed = true;
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
// Instances only advance the technology on a finish, so they need the queue without it.
|
||||
// No player or instance: the finished research prints its own chat line.
|
||||
function broadcastQueueSilently() {
|
||||
controller.sendTo("allInstances", new QueueEvent(queue, null, null));
|
||||
}
|
||||
|
||||
function setQueue(newQueue: string[], player: string | null, src: lib.Address) {
|
||||
@@ -162,9 +171,12 @@ export default async function(context: ControllerPluginContext) {
|
||||
tech.researched = true;
|
||||
tech.progress = null;
|
||||
progressToBroadcast.delete(name);
|
||||
removeFinished(name);
|
||||
let removed = removeFinished(name);
|
||||
|
||||
controller.sendTo("allInstances", new FinishedEvent(name, tech.level));
|
||||
if (removed) {
|
||||
broadcastQueueSilently();
|
||||
}
|
||||
}
|
||||
technologiesDirty = true;
|
||||
});
|
||||
@@ -172,8 +184,9 @@ export default async function(context: ControllerPluginContext) {
|
||||
controller.handle(FinishedEvent, async (event: FinishedEvent) => {
|
||||
let { name, level } = event;
|
||||
let tech = technologies.get(name);
|
||||
let removed = false;
|
||||
if (!tech || tech.level < level || (tech.level === level && !tech.researched)) {
|
||||
removeFinished(name);
|
||||
removed = removeFinished(name);
|
||||
}
|
||||
if (!tech || tech.level <= level) {
|
||||
controller.sendTo("allInstances", event);
|
||||
@@ -181,6 +194,9 @@ export default async function(context: ControllerPluginContext) {
|
||||
technologies.set(name, { level, progress: null, researched: true });
|
||||
technologiesDirty = true;
|
||||
}
|
||||
if (removed) {
|
||||
broadcastQueueSilently();
|
||||
}
|
||||
});
|
||||
|
||||
controller.handle(SyncTechnologiesRequest, async (request: SyncTechnologiesRequest): Promise<TechnologySync[]> => {
|
||||
@@ -192,6 +208,7 @@ export default async function(context: ControllerPluginContext) {
|
||||
return Number.parseInt(match[1], 10);
|
||||
}
|
||||
|
||||
let removed = false;
|
||||
for (let instanceTech of request.technologies) {
|
||||
let { name, level, progress, researched } = instanceTech;
|
||||
let tech = technologies.get(name);
|
||||
@@ -203,7 +220,8 @@ export default async function(context: ControllerPluginContext) {
|
||||
} else if (researched || baseLevel(name) !== level) {
|
||||
controller.sendTo("allInstances", new FinishedEvent(name, level));
|
||||
// One queue entry per level unlocked
|
||||
removeFinished(name, Math.max(level - Number(!researched) - baseLevel(name) + 1, 1));
|
||||
let levels = Math.max(level - Number(!researched) - baseLevel(name) + 1, 1);
|
||||
removed = removeFinished(name, levels) || removed;
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -216,7 +234,7 @@ export default async function(context: ControllerPluginContext) {
|
||||
let unlocked = level - Number(!researched) - (tech.level - Number(!tech.researched));
|
||||
if (unlocked > 0) {
|
||||
controller.sendTo("allInstances", new FinishedEvent(name, level - Number(!researched)));
|
||||
removeFinished(name, unlocked);
|
||||
removed = removeFinished(name, unlocked) || removed;
|
||||
}
|
||||
tech.level = level;
|
||||
tech.progress = progress;
|
||||
@@ -237,6 +255,9 @@ export default async function(context: ControllerPluginContext) {
|
||||
}
|
||||
}
|
||||
progressRateLimiter.activate();
|
||||
if (removed) {
|
||||
broadcastQueueSilently();
|
||||
}
|
||||
|
||||
let result = [];
|
||||
for (let [name, tech] of technologies) {
|
||||
|
||||
@@ -109,9 +109,10 @@ export default async function(context: InstancePluginContext) {
|
||||
if (!syncStarted || !["starting", "running"].includes(instance.status)) {
|
||||
return;
|
||||
}
|
||||
let data: { queue: string[], instance: string, player?: string } = {
|
||||
queue: event.queue, instance: event.instance,
|
||||
};
|
||||
let data: { queue: string[], instance?: string, player?: string } = { queue: event.queue };
|
||||
if (event.instance !== null) {
|
||||
data.instance = event.instance;
|
||||
}
|
||||
if (event.player !== null) {
|
||||
data.player = event.player;
|
||||
}
|
||||
|
||||
@@ -170,14 +170,14 @@ export class QueueEvent {
|
||||
constructor(
|
||||
public queue: string[],
|
||||
public player: string | null,
|
||||
public instance: string,
|
||||
public instance: string | null,
|
||||
) {
|
||||
}
|
||||
|
||||
static jsonSchema = Type.Object({
|
||||
"queue": Type.Array(Type.String()),
|
||||
"player": Type.Union([Type.String(), Type.Null()]),
|
||||
"instance": Type.String(),
|
||||
"instance": Type.Union([Type.String(), Type.Null()]),
|
||||
});
|
||||
|
||||
static fromJSON(json: Static<typeof QueueEvent.jsonSchema>): QueueEvent {
|
||||
|
||||
@@ -110,6 +110,31 @@ describe("research_sync controller", function() {
|
||||
await finished(new FinishedEvent("m", 3), src);
|
||||
assert.deepEqual(await sync(), ["m", "x"]);
|
||||
});
|
||||
it("should send the queue silently after a completion behind the current research", async function() {
|
||||
await update(["automation", "m", "m"]);
|
||||
sent.length = 0;
|
||||
await mock.getHandler(controller, ContributionEvent)(new ContributionEvent("m", 3, 1), src);
|
||||
assert.equal(queueEvents().length, 1);
|
||||
assert.deepEqual(queueEvents()[0][1], new QueueEvent(["automation", "m"], null, null));
|
||||
});
|
||||
it("should send the queue after an advancing FinishedEvent only", async function() {
|
||||
await update(["m", "x"]);
|
||||
sent.length = 0;
|
||||
const finished = mock.getHandler(controller, FinishedEvent);
|
||||
await finished(new FinishedEvent("m", 3), src);
|
||||
assert.equal(queueEvents().length, 1);
|
||||
assert.deepEqual(queueEvents()[0][1], new QueueEvent(["x"], null, null));
|
||||
sent.length = 0;
|
||||
await finished(new FinishedEvent("m", 3), src);
|
||||
assert.equal(queueEvents().length, 0);
|
||||
});
|
||||
it("should send no queue when the finished technology is not queued", async function() {
|
||||
await update(["x"]);
|
||||
sent.length = 0;
|
||||
await mock.getHandler(controller, FinishedEvent)(new FinishedEvent("m", 3), src);
|
||||
await mock.getHandler(controller, ContributionEvent)(new ContributionEvent("n", 3, 1), src);
|
||||
assert.equal(queueEvents().length, 0);
|
||||
});
|
||||
it("should drop an entry finished through a technology sync", async function() {
|
||||
await update(["m", "x"]);
|
||||
await mock.getHandler(controller, SyncTechnologiesRequest)(
|
||||
@@ -126,8 +151,11 @@ describe("research_sync controller", function() {
|
||||
it("should drop one entry per level unlocked on a known technology", async function() {
|
||||
await techSync("m", 4, true);
|
||||
await update(["m", "m", "m", "x"]);
|
||||
sent.length = 0;
|
||||
await techSync("m", 7, true);
|
||||
assert.deepEqual(await sync(), ["x"]);
|
||||
assert.equal(queueEvents().length, 1);
|
||||
assert.deepEqual(queueEvents()[0][1], new QueueEvent(["x"], null, null));
|
||||
});
|
||||
it("should drop one entry per level unlocked on a new technology", async function() {
|
||||
await update(["m", "m", "x"]);
|
||||
|
||||
@@ -78,6 +78,10 @@ describe("research_sync instance", function() {
|
||||
await handler()(new QueueEvent(["a"], null, "rs-2"));
|
||||
assert.equal(lastCommand(), applyCommand({ queue: ["a"], instance: "rs-2" }));
|
||||
});
|
||||
it("should leave out a null instance", async function() {
|
||||
await handler()(new QueueEvent(["a"], null, null));
|
||||
assert.equal(lastCommand(), applyCommand({ queue: ["a"] }));
|
||||
});
|
||||
it("should ignore the event while stopped", async function() {
|
||||
instance.status = "stopped";
|
||||
await handler()(new QueueEvent(["a"], null, "rs-2"));
|
||||
|
||||
Reference in new issue
Block a user