// package warbot -- бот для игры в wartank package warbot import ( "context" "fmt" "log" "strings" "wartank/pkg/components/safebool" "wartank/pkg/types" "wartank/server/serv_bots/warbot/angar" "wartank/server/serv_bots/warbot/tank" "wartank/server/serv_bots/warbot/warbot_config" "wartank/server/serv_bots/warbot/warbot_net" ) // WarBot -- бот для игры в вартанк type WarBot struct { server types.IServer store types.IStore tank *tank.Tank errFinal error // Финальная ошибка работы, если была angar types.IAngar botNet types.IBotNet isRun *safebool.SafeBool isAutoRun *safebool.SafeBool config *warbot_config.WarBotConfig // Конфиг бота для хранения в базе ctx context.Context // Контекст бота fnCancel func() // Функция отменя контекста бота } // LoadWarBot -- загружает бота из базы func LoadWarBot(server types.IServer, login string) (*WarBot, error) { { // Предусловия if server == nil { return nil, fmt.Errorf("LoadWarBot(): IApp is nil") } if login == "" { return nil, fmt.Errorf("LoadWarBot(): name is empty") } } log.Printf("LoadWarBot(): name=%q\n", login) store := server.Store() strData, err := store.Get("/bots/" + login) if err != nil { if !strings.Contains(err.Error(), "not found") { return nil, fmt.Errorf("LoadWarBot(): in load bot %q from store, err=\n\t%w", login, err) } return nil, fmt.Errorf("LoadWarBot(): bot %q not found in store", login) } config := &warbot_config.WarBotConfig{} if err = config.Unmarshall(strData); err != nil { return nil, fmt.Errorf("LoadWarBot(): in unmarshall WarBotConfig(%q) from store, err=\n\t%w", login, err) } sf, err := makeCoreWarBot(server, config) if err != nil { return nil, fmt.Errorf("NewWarBot(): in make core for bot %q, err=\n\t%w", login, err) } return sf, nil } // NewWarBot -- возвращает новый WarBot func NewWarBot(server types.IServer, login, pass string) (*WarBot, error) { { // Предусловия if server == nil { return nil, fmt.Errorf("NewWarBot(): IApp is nil") } if login == "" { return nil, fmt.Errorf("NewWarBot(): login is empty") } if pass == "" { return nil, fmt.Errorf("NewWarBot(): pass is empty") } } log.Printf("NewWarBot(): name=%q\n", login) config := &warbot_config.WarBotConfig{ IsAutoRun_: false, Login_: login, Password_: pass, } sf, err := makeCoreWarBot(server, config) if err != nil { return nil, fmt.Errorf("NewWarBot(): in make core bot %q, err=\n\t%w", login, err) } if err := sf.save(); err != nil { return nil, fmt.Errorf("NewWarBot(): in self save to store, err=\n\t%w", err) } return sf, nil } // Создаёт ядро бота func makeCoreWarBot(server types.IServer, config *warbot_config.WarBotConfig) (*WarBot, error) { { // Предусловия if server == nil { return nil, fmt.Errorf("NewWarBot(): IServer==nil") } if config == nil { return nil, fmt.Errorf("NewWarBot(): WarBotConfig==nil") } } ctx, fnCancel := context.WithCancel(server.CtxApp()) sf := &WarBot{ server: server, store: server.Store(), tank: tank.NewTank(), isRun: safebool.NewSafeBool(), isAutoRun: safebool.NewSafeBool(), config: config, ctx: ctx, fnCancel: fnCancel, } var err error { // WarBotNet sf.botNet, err = warbot_net.NewWarBotNet(sf) if err != nil { return nil, fmt.Errorf("NewWarBot(): in make IBotNet, err=\n\t%w", err) } } sf.angar, err = angar.NewAngar(sf) if err != nil { return nil, fmt.Errorf("NewWarBot(): bot(%q) in make IAngar, err=\n\t%w", sf.Name(), err) } if sf.config.IsAutoRun_ { sf.isAutoRun.Set() sf.Run() } return sf, nil } // Server -- возвращает ссылку на объект сервера func (sf *WarBot) Server() types.IServer { return sf.server } // IsRun -- возвращает признак, что бот подключен func (sf *WarBot) IsRun() bool { return sf.isRun.Get() } // Name -- возвращает имя бота func (sf *WarBot) Name() string { return sf.config.Login_ } // Pass -- возвращает пароль бота func (sf *WarBot) Pass() string { return sf.config.Password_ } // Run -- запускает бот в работу func (sf *WarBot) Run() (err error) { if sf.isRun.Get() { return nil } if err := sf.angar.Run(); err != nil { return fmt.Errorf("WarBot.Run(): bot(%q) in run angar, err=\n\t%w", sf.Name(), err) } sf.isRun.Set() return nil } // Error -- возвращает финальную ошибку работы, если была func (sf *WarBot) Error() error { return sf.errFinal } // Angar -- возвращает ангар игры func (sf *WarBot) Angar() types.IAngar { return sf.angar } // Tank -- возвращает объект танка func (sf *WarBot) Tank() types.ITank { return sf.tank } // BotNet -- возвращает ссылку на свой сетевой клиент func (sf *WarBot) BotNet() types.IBotNet { return sf.botNet } // IsAutoGame -- возвращает признак автоматичского запуска бота func (sf *WarBot) IsAutoGame() bool { return sf.isAutoRun.Get() } // SetAutoGame -- устанавливает признак автоматического запуска бота func (sf *WarBot) SetAutoGame() { log.Printf("WarBot.SetAutoGame()") sf.isAutoRun.Set() sf.config.IsAutoRun_ = true sf.saveConfig() } // ResetAutoGame -- сбрасывает признак автоматического запуска бота func (sf *WarBot) ResetAutoGame() { log.Printf("WarBot.ResetAutoGame()") sf.isAutoRun.Set() sf.config.IsAutoRun_ = false sf.saveConfig() } // Сохраняет конфиг бота func (sf *WarBot) saveConfig() { log.Printf("WarBot.saveConfig()") strConf := sf.config.Marshall() err := sf.store.Put("/bots/"+sf.Name(), strConf) if err != nil { log.Printf("WarBot.saveConfig(): err=\n\t%v\n", err) } } // Ctx -- возвращает контекст бота func (sf *WarBot) Ctx() context.Context { return sf.ctx } // CancelBot -- отменяет контекст бота func (sf *WarBot) CancelBot() { sf.fnCancel() } // Сохраняет себя в базу func (sf *WarBot) save() error { err := sf.store.Put("/bots/"+sf.Name(), sf.config.Marshall()) if err != nil { return fmt.Errorf("WarBot.save(): in self save to store bot(%q), err=\n\t%w", sf.Name(), err) } return nil }