mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-15 16:42:41 +00:00
H3 retired the manual !forage/!mine/!scavenge/!fish/!essence/!commune
verbs from the command dispatcher in e05da91; the underlying handlers
were left parked behind an operator-gated 2-week soak. The expedition
sim has since exercised the auto-harvest path 15k+ times per sweep
across every class, level, and zone — vastly more coverage than the
soak would have collected in production. Pull the dead handlers now.
Removed:
- handleHarvestCmd (dnd_expedition_harvest.go, ~175 lines)
- handleStandaloneHarvest (dnd_zone_harvest.go, ~80 lines)
- dnd_zone_harvest_test.go (three tests against the deleted handler;
the autopilot's standalone-storage path is what runs in prod and is
covered by the cmd/expedition-sim sweep + adv2 scenario test)
The deprecation DM in adventure.go ("Harvest is automatic now — just
walk.") stays for now — muscle memory takes longer than two weeks to
fade and the redirect costs 7 lines.
adv2 scenario test rewired to drive autoHarvestRoom directly.
97 lines
3.2 KiB
Go
97 lines
3.2 KiB
Go
package plugin
|
|
|
|
import (
|
|
"database/sql"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"log/slog"
|
|
"strconv"
|
|
|
|
"gogobee/internal/db"
|
|
|
|
"maunium.net/go/mautrix/id"
|
|
)
|
|
|
|
// Standalone-zone-run harvest. The expedition path uses
|
|
// expedition.region_state to keep per-(region,room) HarvestNode state;
|
|
// !zone enter runs aren't tied to any expedition, so we mirror the
|
|
// per-room storage onto dnd_zone_run.harvest_nodes_json instead.
|
|
//
|
|
// Region-scoped expedition features (kill-gated nodes, conditional
|
|
// events, cursed trinket drops, threat ticks) don't fire here — those
|
|
// belong to the expedition system. Standalone harvest is the casual
|
|
// flow: roll d20 vs DC, get yield, decrement node, save.
|
|
|
|
// loadStandaloneHarvestNodes reads the run's harvest map and returns
|
|
// the nodes for the given graph node. Lazy-seeds from the zone registry
|
|
// on first access. Caller persists via saveStandaloneHarvestNodes.
|
|
//
|
|
// G6 migration: rows written before the re-key used the room-index
|
|
// integer as the storage key. When the node-id key is absent and the
|
|
// id maps back to a legacy room index, we read from the old key so
|
|
// in-flight runs don't lose harvest state. The next save writes under
|
|
// the new key (and drops the old one).
|
|
func loadStandaloneHarvestNodes(runID string, zoneID ZoneID, nodeID string) ([]HarvestNode, error) {
|
|
table, err := loadStandaloneHarvestTable(runID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
roomKey := nodeHarvestKey(nodeID)
|
|
if existing, ok := table[roomKey]; ok {
|
|
return existing, nil
|
|
}
|
|
if idx, ok := legacyRoomIdxFromNodeID(nodeID, zoneID); ok {
|
|
if existing, ok := table[strconv.Itoa(idx)]; ok {
|
|
return existing, nil
|
|
}
|
|
}
|
|
return seedRoomNodes(zoneID), nil
|
|
}
|
|
|
|
// saveStandaloneHarvestNodes writes nodes back into the run's harvest map.
|
|
func saveStandaloneHarvestNodes(runID string, zoneID ZoneID, nodeID string, nodes []HarvestNode) error {
|
|
table, err := loadStandaloneHarvestTable(runID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
table[nodeHarvestKey(nodeID)] = nodes
|
|
if idx, ok := legacyRoomIdxFromNodeID(nodeID, zoneID); ok {
|
|
delete(table, strconv.Itoa(idx))
|
|
}
|
|
raw, err := json.Marshal(table)
|
|
if err != nil {
|
|
return fmt.Errorf("marshal harvest table: %w", err)
|
|
}
|
|
_, err = db.Get().Exec(
|
|
`UPDATE dnd_zone_run SET harvest_nodes_json = ?, last_action_at = CURRENT_TIMESTAMP WHERE run_id = ?`,
|
|
string(raw), runID)
|
|
return err
|
|
}
|
|
|
|
func loadStandaloneHarvestTable(runID string) (map[string][]HarvestNode, error) {
|
|
row := db.Get().QueryRow(
|
|
`SELECT harvest_nodes_json FROM dnd_zone_run WHERE run_id = ?`, runID)
|
|
var raw string
|
|
if err := row.Scan(&raw); err != nil {
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
return map[string][]HarvestNode{}, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
if raw == "" || raw == "{}" {
|
|
return map[string][]HarvestNode{}, nil
|
|
}
|
|
table := map[string][]HarvestNode{}
|
|
if err := json.Unmarshal([]byte(raw), &table); err != nil {
|
|
// Corrupt blob — fall through with empty so harvest re-seeds.
|
|
slog.Warn("standalone harvest: corrupt nodes json", "run", runID, "err", err)
|
|
return map[string][]HarvestNode{}, nil
|
|
}
|
|
return table, nil
|
|
}
|
|
|
|
// Compile-time check that loadAdvCharacter is reachable; silences "unused
|
|
// import" complaints if loadAdvCharacter changes signature in the future.
|
|
var _ id.UserID
|