package gameserver import ( "fmt" "gac-hkrpg-go/internal/common" ) func (s *Session) applyCurrencyWarsCommands() error { if _, active := CURRENT_BATTLE.Load(s.Token); active { return nil } commands, err := common.ReadCurrencyWarsCommands() if err != nil { return err } if len(commands) == 0 { return nil } cfg, err := common.LoadRuntimeConfig() if err != nil { return err } // A pending grant can be blocked by a stuck page. Give the explicit quit // request priority so it can recover that run without applying the grant. for _, command := range commands { if command.UID == cfg.PlayerUID && command.Field == common.CurrencyWarsCommandEnd { return s.applyCurrencyWarsEnd(command) } } for _, command := range commands { if command.UID != cfg.PlayerUID { continue } if !s.currencyWarsOpen { continue } catalog, data, err := cwPreparingData(s) if err != nil { return nil } if command.RunID != data.DHFOFLFCLAH.UniqueId { if err = common.AcknowledgeCurrencyWarsCommand(command.ID); err != nil { return err } PacketLog("CW_GM discarded command for a finished run") continue } player, _, _ := cwComponents(data.DHFOFLFCLAH) if player == nil { return fmt.Errorf("CW player missing") } runtime, _ := cwBonfireRuntime(catalog, data.DHFOFLFCLAH) notify, applyErr := cwApplyCommand(catalog, data.DHFOFLFCLAH, command, runtime) if applyErr != nil { PacketLog(fmt.Sprintf("CW_GM rejected request=%s: %v", command.ID, applyErr)) if err = common.AcknowledgeCurrencyWarsCommand(command.ID); err != nil { return err } continue } if err = s.saveCurrencyWarsDataWithRuntime(data, catalog, runtime, command.ID); err != nil { return err } if err = s.Send(notify); err != nil { return err } PacketLog(fmt.Sprintf("CW_GM applied request=%s field=%s value=%d revision=%d", command.ID, command.Field, command.Value, s.currencyWarsRevision)) } return nil } // End is allowed even with a pending choice so it can recover a stuck CW UI. // Do not end a battle or replace a newer session's saved data. Queue removal, // archive and quit settlement share the same persistent CAS transaction. func (s *Session) applyCurrencyWarsEnd(command common.CurrencyWarsCommand) error { catalog, err := common.LoadCurrencyWarsCatalog() if err != nil { return err } data, revision, err := readCurrencyWarsData(catalog) if err != nil { return err } if data == nil || data.DHFOFLFCLAH == nil || data.DHFOFLFCLAH.UniqueId != command.RunID { if err := common.AcknowledgeCurrencyWarsCommand(command.ID); err != nil { return err } PacketLog(fmt.Sprintf("CW_GM discarded end request=%s: run already ended or changed", command.ID)) return nil } if revision != s.currencyWarsRevision { // If this session has not opened CW, it holds no CW UI state. Adopt the // freshly read revision; the CAS still rejects any concurrent changes. if s.currencyWarsOpen { return common.ErrCurrencyWarsSaveConflict } s.currencyWarsRevision = revision } keep, settle, err := currencyWarsQuitSettlement(catalog, data, data.DHFOFLFCLAH) if err != nil { return err } data.DHFOFLFCLAH = nil if err := s.saveCurrencyWarsTerminal(data, catalog, settle.BFLLJJBHLDF, command.ID); err != nil { return err } wasOpen := s.currencyWarsOpen s.currencyWarsOpen = false if wasOpen { if err := cwSend(s, keep); err != nil { return err } if err := cwSend(s, settle); err != nil { return err } } PacketLog(fmt.Sprintf("CW_GM applied end request=%s run=%d revision=%d result=quit", command.ID, command.RunID, s.currencyWarsRevision)) return nil }