See how far Plany has got learning to read your game's log output. Plany works out when players join and leave from a game server's own log lines, so there is no SDK to integrate — and a game it has never seen shows no players until the patterns for those lines have been learned and proven, which takes hours. GetEventLearning shows that progress: the patterns found so far, and how much of the game's output they cover.
Says how far the platform has got understanding a game's log output.
The customer's view of the whole subsystem. A game Plany has never seen shows no players until a pattern for its join and leave lines has been learned and then trusted, which takes hours by design. Without this the wait looks exactly like a broken server, or one nobody is playing on.
Authorized on the game: anybody who may read the game may read this. For a game Plany publishes, the lines behind it come from every account running it, so the unmatched lines and the samples are withheld and only the counts and the patterns are returned.
namestringRequiredaccounts/{account}/games/{game}/eventLearning, or games/{game}/eventLearning for a game Plany publishes.
grpcurl -H "authorization: Bearer $PLANY_API_KEY" \ -d '{ "name": "accounts//games/my-game/eventLearning" }' \ api.plany.cloud:443 plany.gamelog.v1.EventService/GetEventLearning{ "name": "accounts//games/my-game/eventLearning", "game": "", "location": "", "state": "STATE_AWAITING_LOGS", "state_message": "", "learning_enabled": false, "templates": [ { "template": "projects//locations//templates/my-template", "game": "", "inherited": false, "kind": "KIND_PLAYER_CONNECTED", "state": "STATE_PROPOSED", "origin": "ORIGIN_BUILTIN", "pattern": "", "match_count": "0", "coherent_count": "0", "required_coherent_count": "0", "incoherence_ratio": 0, "max_incoherence_ratio": 0, "earliest_promote_time": "2026-10-04T12:00:00Z", "create_time": "2026-10-04T12:00:00Z", "promote_time": "2026-10-04T12:00:00Z", "progress_message": "", "samples": [ "" ] } ], "unmatched": [ { "skeleton": "", "example": "", "occurrences": "0", "first_seen_time": "2026-10-04T12:00:00Z", "last_seen_time": "2026-10-04T12:00:00Z", "last_asked_time": "2026-10-04T12:00:00Z" } ], "unmatched_shape_count": "0", "unmatched_withheld": false, "next_learn_time": "2026-10-04T12:00:00Z", "min_occurrences": "0"}TemplateProgress is one pattern and how close it is to being trusted.
templatestringOutput onlyprojects/{project}/locations/{location}/templates/{template}
gamestringOutput onlyThe game it is stored against. An ancestor of the game asked about when
inherited is set: a pattern on games/minecraft-java serves every
modpack under it.
inheritedboolOutput onlyKIND_PLAYER_CONNECTEDKIND_PLAYER_DISCONNECTEDKIND_SERVER_READYKIND_SERVER_STOPPINGKIND_CHATKIND_ERRORSTATE_PROPOSEDSTATE_ACTIVESTATE_REJECTEDORIGIN_BUILTINORIGIN_LEARNEDORIGIN_MANUALpatternstringOutput onlyThe RE2 pattern.
match_countint64Output onlycoherent_countint64Output onlyMatches that made sense: a leave after a join for the same player, a join for somebody not already there.
required_coherent_countint64Output onlyWhat promotion needs. Set while the template is PROPOSED.
incoherence_ratiodoubleOutput onlymax_incoherence_ratiodoubleOutput onlyThe earliest it can be promoted, however well it behaves. The window in which a person can notice a bad pattern before it reaches a bill.
progress_messagestringOutput onlyWhy it is where it is. For a PROPOSED template, what promotion is still waiting on, worked out from the same policy the promotion loop runs.
samplesrepeated stringOutput onlyThe lines it was derived from. Only for a pattern stored against the caller's own game: anything else may have been learned from another account's servers.
{ "template": "projects//locations//templates/my-template", "game": "", "inherited": false, "kind": "KIND_PLAYER_CONNECTED", "state": "STATE_PROPOSED", "origin": "ORIGIN_BUILTIN", "pattern": "", "match_count": "0", "coherent_count": "0", "required_coherent_count": "0", "incoherence_ratio": 0, "max_incoherence_ratio": 0, "earliest_promote_time": "2026-10-04T12:00:00Z", "create_time": "2026-10-04T12:00:00Z", "promote_time": "2026-10-04T12:00:00Z", "progress_message": "", "samples": [ "" ]}UnmatchedShape is one kind of line nothing recognises.
skeletonstringOutput onlyThe line with its variable parts replaced by placeholders.
examplestringOutput onlyOne real line of this shape.
occurrencesint64Output onlyWhen it was last put in front of a model. Unset if never.
{ "skeleton": "", "example": "", "occurrences": "0", "first_seen_time": "2026-10-04T12:00:00Z", "last_seen_time": "2026-10-04T12:00:00Z", "last_asked_time": "2026-10-04T12:00:00Z"}EventLearning is where the platform has got with one game's log output, in the region that answered.
Regional, because templates are: one learned in eu-west-2 does not appear in us-east-1, so a game can be understood in one region and still be learning in another.
namestringIdentifieraccounts/{account}/games/{game}/eventLearning, or games/{game}/eventLearning.
gamestringOutput onlyThe game this describes.
locationstringOutput onlyThe region that answered.
STATE_AWAITING_LOGSSTATE_LEARNINGSTATE_NO_PATTERN_FOUNDSTATE_VERIFYINGSTATE_ACTIVESTATE_LEARNING_DISABLEDstate_messagestringOutput onlyOne sentence for a person, saying what is happening and what happens next.
learning_enabledboolOutput onlyWhether this region can learn a new pattern at all.
Every pattern this game resolves to, inherited ones included, in the order they are tried: trusted first.
templatestringOutput onlyprojects/{project}/locations/{location}/templates/{template}
gamestringOutput onlyThe game it is stored against. An ancestor of the game asked about when
inherited is set: a pattern on games/minecraft-java serves every
modpack under it.
inheritedboolOutput onlyKIND_PLAYER_CONNECTEDKIND_PLAYER_DISCONNECTEDKIND_SERVER_READYKIND_SERVER_STOPPINGKIND_CHATKIND_ERRORSTATE_PROPOSEDSTATE_ACTIVESTATE_REJECTEDORIGIN_BUILTINORIGIN_LEARNEDORIGIN_MANUALpatternstringOutput onlyThe RE2 pattern.
match_countint64Output onlycoherent_countint64Output onlyMatches that made sense: a leave after a join for the same player, a join for somebody not already there.
required_coherent_countint64Output onlyWhat promotion needs. Set while the template is PROPOSED.
incoherence_ratiodoubleOutput onlymax_incoherence_ratiodoubleOutput onlyThe earliest it can be promoted, however well it behaves. The window in which a person can notice a bad pattern before it reaches a bill.
progress_messagestringOutput onlyWhy it is where it is. For a PROPOSED template, what promotion is still waiting on, worked out from the same policy the promotion loop runs.
samplesrepeated stringOutput onlyThe lines it was derived from. Only for a pattern stored against the caller's own game: anything else may have been learned from another account's servers.
Line shapes this game printed that nothing recognises, busiest first.
Empty when unmatched_withheld is set.
skeletonstringOutput onlyThe line with its variable parts replaced by placeholders.
examplestringOutput onlyOne real line of this shape.
occurrencesint64Output onlyWhen it was last put in front of a model. Unset if never.
unmatched_shape_countint64Output onlyHow many distinct unrecognised shapes there are, which may be more than
unmatched lists.
unmatched_withheldboolOutput onlySet for a game Plany publishes. Its lines come from every account running it, so they are not shown to any one of them.
When the queued lines will next be put to a model. Unset when nothing is waiting to be asked about, or learning is disabled.
min_occurrencesint64Output onlyHow many times a shape must be seen before it is worth asking about.
The stage a game is at, in the order a new game passes through them.
Derived on every read from the templates and the unmatched lines, never stored, so it cannot disagree with them.
| Value | Description |
|---|---|
| STATE_UNSPECIFIED | |
| STATE_AWAITING_LOGS | No server of this game has logged anything Plany could not already read, and nothing matches a join or a leave yet. Start a server and let somebody join it. |
| STATE_LEARNING | Lines nothing recognises are queued, and a model will be asked to propose patterns for them. |
| STATE_NO_PATTERN_FOUND | A model was asked and proposed nothing it could stand behind. Asked again at `next_learn_time`, or sooner if the game starts printing lines of a shape it has not seen. |
| STATE_VERIFYING | Patterns for joining and leaving exist and are being checked against real sessions before their events are trusted. Players are detected, provisionally. |
| STATE_ACTIVE | Joining and leaving are both recognised by trusted patterns. Done. |
| STATE_LEARNING_DISABLED | This region has no model configured, so a game whose lines nothing recognises stays that way until a person writes a pattern for it. |
| Value | Description |
|---|---|
| KIND_UNSPECIFIED | |
| KIND_PLAYER_CONNECTED | A player joined. What starts a billable session. |
| KIND_PLAYER_DISCONNECTED | A player left. What ends one. |
| KIND_SERVER_READY | The server announced it is accepting connections. Distinct from the instance being RUNNING, which only says a process started — a Minecraft server takes a further minute loading its world, and a player who connects in between gets a refused connection. |
| KIND_SERVER_STOPPING | The server is shutting down of its own accord: an in-game command, a scheduled restart, a crash handler. |
| KIND_CHAT | A player sent a chat message. Never carries the message body — see `attributes`. |
| KIND_ERROR | The server logged something it called an error. Useful for support long before it is useful for billing. |
| Value | Description |
|---|---|
| ORIGIN_UNSPECIFIED | |
| ORIGIN_BUILTIN | Shipped with Plany, in `internal/patterns`. Starts ACTIVE: these come with tests over real log samples, which is a stronger guarantee than shadowing gives. |
| ORIGIN_LEARNED | Proposed by a model from unmatched lines. |
| ORIGIN_MANUAL | Written by hand rather than learned. |
| Value | Description |
|---|---|
| STATE_UNSPECIFIED | |
| STATE_PROPOSED | Proposed and validated, but not yet trusted. Events it produces are published as PROVISIONAL. Everything new lands here. A regular expression that matches slightly too much would invent player connections, and an invented connection is a wrong invoice — so a template earns its way out of this state by behaving, not by being plausible. |
| STATE_ACTIVE | Trusted. Events it produces are CONFIRMED. |
| STATE_REJECTED | Withdrawn. Kept rather than deleted, so the same shape is not proposed again next week and so there is a record of what was tried. |