Skip to content

Commit 8d29d47

Browse files
feat: Operators
Experiment to try to find a good guiding approach with KE. Also contains various other fixes for the current development stream.
1 parent 216f5d7 commit 8d29d47

32 files changed

+789
-74
lines changed

packages/kitten-analysts/examples/a708b0ad-5f94-4466-8a2e-1d381117d0e0.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

packages/kitten-analysts/examples/ka-internal-savestate.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

packages/kitten-analysts/game.Containerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ FROM docker.io/library/node:22.8.0-bookworm@sha256:8ec02324cb37718197de92e516777
33
LABEL "org.opencontainers.image.description"="Kittens Game with Kitten Science DNA"
44

55
ARG REPO=https://github.com/kitten-science/kittensgame.git
6-
ARG BRANCH=feat/kgnet-iteration
6+
ARG BRANCH=feat/caching
77

88
EXPOSE 8080
99

packages/kitten-analysts/source/KittenAnalysts.ts

Lines changed: 163 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ declare global {
1616
export type KittenAnalystsMessageId =
1717
| "connected"
1818
| "getBuildings"
19+
| "getCalendar"
20+
| "getRaces"
1921
| "getResourcePool"
2022
| "getStatistics"
2123
| "getTechnologies"
@@ -24,17 +26,40 @@ export type KittenAnalystsMessageId =
2426
| "reportSavegame";
2527

2628
export type PayloadBuildings = Array<{
29+
group: string;
2730
label: string;
2831
name: string;
2932
on: number;
3033
tab: TabId;
3134
value: number;
3235
}>;
36+
export type PayloadCalendar = Array<{
37+
cryptoPrice: number;
38+
cycle: number;
39+
cycleYear: number;
40+
day: number;
41+
eventChance: number;
42+
festivalDays: number;
43+
futureSeasonTemporalParadox: number;
44+
season: number;
45+
seasonsPerYear: number;
46+
year: number;
47+
yearsPerCycle: number;
48+
}>;
49+
export type PayloadRaces = Array<{
50+
embassyLevel: number;
51+
energy: number;
52+
name: string;
53+
standing: number;
54+
title: string;
55+
unlocked: boolean;
56+
}>;
3357
export type PayloadResources = Array<{
3458
craftable: boolean;
3559
label: string;
3660
maxValue: number;
3761
name: string;
62+
rate: number;
3863
value: number;
3964
}>;
4065
export type PayloadStatistics = Array<{
@@ -55,19 +80,23 @@ export interface KittenAnalystsMessage<
5580
TMessage extends KittenAnalystsMessageId,
5681
TData = TMessage extends "getBuildings"
5782
? PayloadBuildings
58-
: TMessage extends "getResourcePool"
59-
? PayloadResources
60-
: TMessage extends "getStatistics"
61-
? PayloadStatistics
62-
: TMessage extends "getTechnologies"
63-
? PayloadTechnologies
64-
: TMessage extends "reportFrame"
65-
? unknown
66-
: TMessage extends "reportSavegame"
67-
? unknown
68-
: TMessage extends "injectSavegame"
69-
? KGNetSavePersisted
70-
: never,
83+
: TMessage extends "getCalendar"
84+
? PayloadCalendar
85+
: TMessage extends "getRaces"
86+
? PayloadRaces
87+
: TMessage extends "getResourcePool"
88+
? PayloadResources
89+
: TMessage extends "getStatistics"
90+
? PayloadStatistics
91+
: TMessage extends "getTechnologies"
92+
? PayloadTechnologies
93+
: TMessage extends "reportFrame"
94+
? unknown
95+
: TMessage extends "reportSavegame"
96+
? unknown
97+
: TMessage extends "injectSavegame"
98+
? KGNetSavePersisted
99+
: never,
71100
> {
72101
/**
73102
* The payload of the message.
@@ -225,80 +254,180 @@ export class KittenAnalysts {
225254
const bonfire: PayloadBuildings = game.bld.meta[0].meta.flatMap(building => {
226255
if (building.stages) {
227256
return building.stages.map((stage, index) => ({
257+
group: "upgrade",
258+
label: stage.label,
228259
name: building.name,
229-
value: index === building.stage ? building.val : 0,
230260
on: index === building.stage ? building.on : 0,
231-
label: stage.label,
232261
tab: "Bonfire",
262+
value: index === building.stage ? building.val : 0,
233263
}));
234264
}
235265
return {
266+
group: "base",
267+
label: building.label ?? building.name,
236268
name: building.name,
237-
value: building.val,
238269
on: building.on,
239-
label: building.label ?? building.name,
240270
tab: "Bonfire",
271+
value: building.val,
241272
};
242273
});
274+
275+
const religionGroups = ["ziggurats", "orderOfTheSun", "cryptotheology", "pacts"];
276+
const religion: PayloadBuildings = game.religion.meta.flatMap((meta, index) =>
277+
meta.meta.map(building => ({
278+
group: religionGroups[index],
279+
label: building.label,
280+
name: building.name,
281+
on: 0,
282+
tab: "Religion",
283+
value: building.val,
284+
})),
285+
);
286+
287+
const spaceGroups = [
288+
"groundControl",
289+
"cath",
290+
"moon",
291+
"dune",
292+
"piscine",
293+
"helios",
294+
"terminus",
295+
"kairo",
296+
"yarn",
297+
"umbra",
298+
"charon",
299+
"centaurusSystem",
300+
"furthestRing",
301+
];
243302
const space: PayloadBuildings = game.space.meta.flatMap((meta, index) =>
244303
// index 0 is moon missions
245304
index === 0
246305
? []
247306
: meta.meta.map(building => ({
307+
group: spaceGroups[index],
308+
label: building.label,
248309
name: building.name,
249-
value: building.val,
250310
on: building.on,
251-
label: building.label,
252311
tab: "Space",
312+
value: building.val,
253313
})),
254314
);
255-
const religion: PayloadBuildings = game.religion.meta.flatMap(meta =>
256-
meta.meta.map(building => ({
257-
name: building.name,
258-
value: building.val,
259-
on: 0,
260-
label: building.label,
261-
tab: "Religion",
315+
316+
const timeGroups = ["chronoForge", "voidSpace"];
317+
const time: PayloadBuildings = game.time.meta.flatMap((meta, index) =>
318+
meta.meta.map(item => ({
319+
group: timeGroups[index],
320+
label: item.label,
321+
name: item.name,
322+
on: "on" in item ? (item.on ?? 0) : 0,
323+
tab: "Time",
324+
value: item.val,
262325
})),
263326
);
264327

265328
return {
266329
client_type: this.location.includes("headless.html") ? "headless" : "browser",
267-
data: [...bonfire, ...space, ...religion],
330+
data: [...bonfire, ...religion, ...space, ...time],
268331
guid: game.telemetry.guid,
269332
location: this.location,
270333
responseId: message.responseId,
271334
type: message.type,
272335
};
273336
}
274-
case "getResourcePool": {
275-
const resources: PayloadResources = game.resPool.resources.map(resource => ({
276-
name: resource.name,
277-
value: resource.value,
278-
maxValue: resource.maxValue,
279-
label: resource.title,
280-
craftable: resource.craftable ?? false,
337+
338+
case "getCalendar": {
339+
const data: PayloadCalendar = [
340+
{
341+
cryptoPrice: game.calendar.cryptoPrice,
342+
cycle: game.calendar.cycle,
343+
cycleYear: game.calendar.cycleYear,
344+
day: game.calendar.day,
345+
eventChance: game.calendar.eventChance,
346+
festivalDays: game.calendar.festivalDays,
347+
futureSeasonTemporalParadox: game.calendar.futureSeasonTemporalParadox,
348+
season: game.calendar.season,
349+
seasonsPerYear: game.calendar.seasonsPerYear,
350+
year: game.calendar.year,
351+
yearsPerCycle: game.calendar.yearsPerCycle,
352+
},
353+
];
354+
return {
355+
client_type: this.location.includes("headless.html") ? "headless" : "browser",
356+
data,
357+
guid: game.telemetry.guid,
358+
location: this.location,
359+
responseId: message.responseId,
360+
type: message.type,
361+
};
362+
}
363+
364+
case "getRaces": {
365+
const data: PayloadRaces = game.diplomacy.races.map(race => ({
366+
embassyLevel: race.embassyLevel,
367+
energy: race.energy,
368+
name: race.name,
369+
standing: race.standing,
370+
title: race.title,
371+
unlocked: race.unlocked,
281372
}));
373+
374+
return {
375+
client_type: this.location.includes("headless.html") ? "headless" : "browser",
376+
data,
377+
guid: game.telemetry.guid,
378+
location: this.location,
379+
responseId: message.responseId,
380+
type: message.type,
381+
};
382+
}
383+
case "getResourcePool": {
384+
const isTimeParadox = this.game.calendar.day < 0;
385+
386+
const resources: PayloadResources = this.game.resPool.resources.map(resource => {
387+
let rate =
388+
(isTimeParadox ? 0 : this.game.getResourcePerTick(resource.name, true)) *
389+
this.game.getTicksPerSecondUI();
390+
if (resource.calculatePerDay === true) {
391+
rate =
392+
this.game.getResourcePerDay(resource.name) *
393+
(resource.name === "necrocorn" ? 1 + this.game.timeAccelerationRatio() : 1);
394+
} else if (resource.calculatePerYear) {
395+
rate = this.game.getResourceOnYearProduction(resource.name);
396+
}
397+
398+
return {
399+
name: resource.name,
400+
value: resource.value,
401+
maxValue: resource.maxValue,
402+
label: resource.title,
403+
craftable: resource.craftable ?? false,
404+
rate: rate,
405+
};
406+
});
407+
282408
const pseudoResources: PayloadResources = [
283409
{
284410
craftable: false,
285411
label: "Worship",
286412
maxValue: Infinity,
287413
name: "worship",
414+
rate: 0,
288415
value: game.religion.faith,
289416
},
290417
{
291418
craftable: false,
292419
label: "Epiphany",
293420
maxValue: Infinity,
294421
name: "epiphany",
422+
rate: 0,
295423
value: game.religion.faithRatio,
296424
},
297425
{
298426
craftable: false,
299427
label: "Necrocorn deficit",
300428
maxValue: Infinity,
301429
name: "necrocornDeficit",
430+
rate: 0,
302431
value: game.religion.pactsManager.necrocornDeficit,
303432
},
304433
];

packages/kitten-analysts/source/entrypoint-backend.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import {
1818
KittenAnalystsMessage,
1919
KittenAnalystsMessageId,
2020
PayloadBuildings,
21+
PayloadCalendar,
22+
PayloadRaces,
2123
PayloadResources,
2224
PayloadStatistics,
2325
PayloadTechnologies,
@@ -28,13 +30,19 @@ import { kg_buildings_constructed } from "./metrics/kg_buildings_constructed.js"
2830
import { kg_challenges_completed_total } from "./metrics/kg_challenges_completed_total.js";
2931
import { kg_clicks_total } from "./metrics/kg_clicks_total.js";
3032
import { kg_crafts_total } from "./metrics/kg_crafts_total.js";
33+
import { kg_crypto_price } from "./metrics/kg_crypto_price.js";
34+
import { kg_embassy_level } from "./metrics/kg_embassy_level.js";
3135
import { kg_events_observed } from "./metrics/kg_events_observed.js";
36+
import { kg_festival_days } from "./metrics/kg_festival_days.js";
3237
import { kg_kittens_average } from "./metrics/kg_kittens_average.js";
3338
import { kg_kittens_dead } from "./metrics/kg_kittens_dead.js";
3439
import { kg_kittens_total } from "./metrics/kg_kittens_total.js";
3540
import { kg_paragon_total } from "./metrics/kg_paragon_total.js";
41+
import { kg_race_energy } from "./metrics/kg_race_energy.js";
42+
import { kg_race_standing } from "./metrics/kg_race_standing.js";
3643
import { kg_resets_total } from "./metrics/kg_resets_total.js";
3744
import { kg_resource_max_value } from "./metrics/kg_resource_max_value.js";
45+
import { kg_resource_rate } from "./metrics/kg_resource_rate.js";
3846
import { kg_resource_value } from "./metrics/kg_resource_value.js";
3947
import { kg_tech_researched } from "./metrics/kg_tech_researched.js";
4048
import { kg_tech_unlocked } from "./metrics/kg_tech_unlocked.js";
@@ -77,7 +85,12 @@ const cache = new Map<
7785
Promise<
7886
Array<KittenAnalystsMessage<
7987
KittenAnalystsMessageId,
80-
PayloadBuildings | PayloadResources | PayloadStatistics | PayloadTechnologies
88+
| PayloadBuildings
89+
| PayloadCalendar
90+
| PayloadRaces
91+
| PayloadResources
92+
| PayloadStatistics
93+
| PayloadTechnologies
8194
> | null>
8295
>
8396
>();
@@ -92,6 +105,14 @@ register.registerMetric(kg_building_on(cache, remote));
92105

93106
register.registerMetric(kg_resource_value(cache, remote));
94107
register.registerMetric(kg_resource_max_value(cache, remote));
108+
register.registerMetric(kg_resource_rate(cache, remote));
109+
110+
register.registerMetric(kg_embassy_level(cache, remote));
111+
register.registerMetric(kg_race_energy(cache, remote));
112+
register.registerMetric(kg_race_standing(cache, remote));
113+
114+
register.registerMetric(kg_crypto_price(cache, remote));
115+
register.registerMetric(kg_festival_days(cache, remote));
95116

96117
// Metrics from in-game Stats
97118

@@ -216,7 +237,7 @@ routerNetwork.post("/kgnet/save/upload", context => {
216237
remote
217238
.toHeadless({
218239
type: "injectSavegame",
219-
data: savegame,
240+
data: savegameEphemeral,
220241
})
221242
.catch(redirectErrorsToConsole(console));
222243

0 commit comments

Comments
 (0)