Passed
Push — master ( 862304...79d443 )
by Viktor
01:43
created

bot/albion.go   F

Size/Duplication

Total Lines 407
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
cc 60
eloc 295
dl 0
loc 407
rs 3.6
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A bot.AlbionSearchPlayers 0 17 4
A bot.AlbionGetPlayerKills 0 17 4
A bot.*Context.AlbionShowKill 0 26 4
B bot.*Context.AlbionShowKills 0 41 7
A bot.AlbionGetKillID 0 17 4
C bot.*AlbionUpdater.Update 0 36 9
B bot.*Context.AlbionAddPlayer 0 30 8
A bot.GetPlayerByID 0 8 3
A bot.AlbionGetUpdater 0 8 2
B bot.SendKill 0 33 7
B bot.SendPlayerKills 0 29 8
1
package bot
2
3
import (
4
	"encoding/json"
5
	"errors"
6
	"fmt"
7
	"github.com/bwmarrin/discordgo"
8
	"net/http"
9
	"strings"
10
	"time"
11
)
12
13
// SearchResult contains search response
0 ignored issues
show
introduced by
comment on exported type AlbionSearchResult should be of the form "AlbionSearchResult ..." (with optional leading article)
Loading history...
14
type AlbionSearchResult struct {
15
	Guilds  []AlbionGuildSearch  `json:"guilds"`
16
	Players []AlbionPlayerSearch `json:"players"`
17
}
18
19
// GuildSearch contains guild data from search response
0 ignored issues
show
introduced by
comment on exported type AlbionGuildSearch should be of the form "AlbionGuildSearch ..." (with optional leading article)
Loading history...
20
type AlbionGuildSearch struct {
21
	ID           string `json:"Id"`
22
	Name         string `json:"Name"`
23
	AllianceID   string `json:"AllianceId"`
24
	AllianceName string `json:"AllianceName"`
25
	KillFame     int    `json:"KillFame"`
26
	DeathFame    int    `json:"DeathFame"`
27
}
28
29
// PlayerSearch contains player data from search response
0 ignored issues
show
introduced by
comment on exported type AlbionPlayerSearch should be of the form "AlbionPlayerSearch ..." (with optional leading article)
Loading history...
30
type AlbionPlayerSearch struct {
31
	ID           string  `json:"Id"`
32
	Name         string  `json:"Name"`
33
	AllianceID   string  `json:"AllianceId"`
34
	AllianceName string  `json:"AllianceName"`
35
	KillFame     int     `json:"KillFame"`
36
	DeathFame    int     `json:"DeathFame"`
37
	Avatar       string  `json:"Avatar"`
38
	AvatarRing   string  `json:"AvatarRing"`
39
	FameRation   float64 `json:"FameRatio"`
40
	TotalKills   int     `json:"totalKills"`
41
	GVGKills     int     `json:"gvgKills"`
42
	GVGWon       int     `json:"gvgWon"`
43
}
44
45
// Player data
0 ignored issues
show
introduced by
comment on exported type AlbionPlayer should be of the form "AlbionPlayer ..." (with optional leading article)
Loading history...
46
type AlbionPlayer struct {
47
	AverageItemPower float64         `json:"AverageItemPower"`
48
	Equipment        AlbionEquipment `json:"Equipment"`
49
	Inventory        []AlbionItem    `json:"Inventory"`
50
	Name             string          `json:"Name"`
51
	Id               string          `json:"Id"`
0 ignored issues
show
introduced by
struct field Id should be ID
Loading history...
52
	GuildName        string          `json:"GuildName"`
53
	GuildId          string          `json:"GuildId"`
0 ignored issues
show
introduced by
struct field GuildId should be GuildID
Loading history...
54
	AllianceName     string          `json:"AllianceName"`
55
	AllianceId       string          `json:"AllianceId"`
0 ignored issues
show
introduced by
struct field AllianceId should be AllianceID
Loading history...
56
	AllianceTag      string          `json:"AllianceTag"`
57
	Avatar           string          `json:"Avatar"`
58
	AvatarRing       string          `json:"AvatarRing"`
59
	DeathFame        int             `json:"DeathFame"`
60
	KillFame         int             `json:"KillFame"`
61
	FameRatio        float64         `json:"FameRatio"`
62
	DamageDone       float64         `json:"DamageDone"`
63
}
64
65
// Equipment contains items in slots
0 ignored issues
show
introduced by
comment on exported type AlbionEquipment should be of the form "AlbionEquipment ..." (with optional leading article)
Loading history...
66
type AlbionEquipment struct {
67
	MainHand AlbionItem `json:"MainHand"`
68
	OffHand  AlbionItem `json:"OffHand"`
69
	Head     AlbionItem `json:"Head"`
70
	Armor    AlbionItem `json:"Armor"`
71
	Shoes    AlbionItem `json:"Shoes"`
72
	Bag      AlbionItem `json:"Bag"`
73
	Cape     AlbionItem `json:"Cape"`
74
	Mount    AlbionItem `json:"Mount"`
75
	Potion   AlbionItem `json:"Potion"`
76
	Food     AlbionItem `json:"Food"`
77
}
78
79
// Item contains item data
0 ignored issues
show
introduced by
comment on exported type AlbionItem should be of the form "AlbionItem ..." (with optional leading article)
Loading history...
80
type AlbionItem struct {
81
	Type    string `json:"Type"`
82
	Count   int    `json:"Count"`
83
	Quality int    `json:"Quality"`
84
}
85
86
// Kill contains kill data
0 ignored issues
show
introduced by
comment on exported type AlbionKill should be of the form "AlbionKill ..." (with optional leading article)
Loading history...
87
type AlbionKill struct {
88
	GroupMemberCount     int            `json:"groupMemberCount"`
89
	NumberOfParticipants int            `json:"numberOfParticipants"`
90
	EventID              int            `json:"EventId"`
91
	TimeStamp            string         `json:"TimeStamp"`
92
	Version              int            `json:"Version"`
93
	Killer               AlbionPlayer   `json:"Killer"`
94
	Victim               AlbionPlayer   `json:"Victim"`
95
	TotalVictimKillFame  int            `json:"TotalVictimKillFame"`
96
	Location             string         `json:"Location"`
97
	Participants         []AlbionPlayer `json:"Participants"`
98
	GroupMembers         []AlbionPlayer `json:"GroupMembers"`
99
	BattleID             int            `json:"BattleId"`
100
	Type                 string         `json:"Type"`
101
}
102
103
type AlbionUpdater struct {
0 ignored issues
show
introduced by
exported type AlbionUpdater should have comment or be unexported
Loading history...
104
	Players map[string]*AlbionPlayerUpdater
105
}
106
107
type AlbionPlayerUpdater struct {
0 ignored issues
show
introduced by
exported type AlbionPlayerUpdater should have comment or be unexported
Loading history...
108
	PlayerID string
109
	UserID   string
110
	LastKill int64
111
	StartAt  int64
112
}
113
114
// SearchPlayers returns player list by name
0 ignored issues
show
introduced by
comment on exported function AlbionSearchPlayers should be of the form "AlbionSearchPlayers ..."
Loading history...
115
func AlbionSearchPlayers(name string) (result *AlbionSearchResult, err error) {
116
	var sResult AlbionSearchResult
117
	resp, err := http.Get(fmt.Sprintf("https://gameinfo.albiononline.com/api/gameinfo/search?q=%v", name))
118
	if err != nil {
119
		return nil, err
120
	}
121
122
	if resp.StatusCode != 200 {
123
		return nil, errors.New("status " + resp.Status)
124
	}
125
126
	err = json.NewDecoder(resp.Body).Decode(&sResult)
127
	if err != nil {
128
		return nil, err
129
	}
130
131
	return &sResult, nil
132
}
133
134
// GetPlayerKills returns array of kills by player id
0 ignored issues
show
introduced by
comment on exported function AlbionGetPlayerKills should be of the form "AlbionGetPlayerKills ..."
Loading history...
135
func AlbionGetPlayerKills(id string) (result []AlbionKill, err error) {
136
	var kills []AlbionKill
137
	resp, err := http.Get(fmt.Sprintf("https://gameinfo.albiononline.com/api/gameinfo/players/%v/topkills?range=month&offset=0&limit=20", id))
138
	if err != nil {
139
		return nil, err
140
	}
141
142
	if resp.StatusCode != 200 {
143
		return nil, errors.New("status " + resp.Status)
144
	}
145
146
	err = json.NewDecoder(resp.Body).Decode(&kills)
147
	if err != nil {
148
		return nil, err
149
	}
150
151
	return kills, nil
152
}
153
154
func AlbionGetKillID(id string) (kill *AlbionKill, err error) {
0 ignored issues
show
introduced by
exported function AlbionGetKillID should have comment or be unexported
Loading history...
155
	var result AlbionKill
156
	resp, err := http.Get(fmt.Sprintf("https://gameinfo.albiononline.com/api/gameinfo/events/%v", id))
157
	if err != nil {
158
		return nil, err
159
	}
160
161
	if resp.StatusCode != 200 {
162
		return nil, errors.New("status " + resp.Status)
163
	}
164
165
	err = json.NewDecoder(resp.Body).Decode(&result)
166
	if err != nil {
167
		return nil, err
168
	}
169
170
	return &result, nil
171
}
172
173
// ShowKills sends embed message in discord
0 ignored issues
show
introduced by
comment on exported method Context.AlbionShowKills should be of the form "AlbionShowKills ..."
Loading history...
174
func (ctx *Context) AlbionShowKills() {
175
	search, err := AlbionSearchPlayers(ctx.Args[1])
176
	if err != nil {
177
		fmt.Println("Error:" + err.Error())
178
		return
179
	}
180
	fmt.Println("Founded players")
181
	if len(search.Players) > 0 {
182
		fmt.Println("Players more then 0")
183
		kills, err := AlbionGetPlayerKills(search.Players[0].ID)
184
		fmt.Println("Searching kills of " + search.Players[0].Name + search.Players[0].ID)
185
		if err != nil {
186
			fmt.Println("Error: " + err.Error())
187
			return
188
		}
189
		fmt.Println("Founded kills of " + search.Players[0].Name)
190
		if len(kills) > 0 {
191
			fmt.Println("Kills more then 0")
192
			embed := NewEmbed("Albion Killboard")
193
			embed.Desc(fmt.Sprintf("[%v](https://albiononline.com/ru/killboard/player/%v)", search.Players[0].Name, search.Players[0].ID)) // "https://assets.albiononline.com/assets/images/icons/favicon.ico")
194
			embed.Color(ctx.GuildConf().EmbedColor)
195
			for _, k := range kills {
196
				fmt.Println("Killed " + k.Victim.Name)
197
				var timeString string
198
				t, err := time.Parse("2006-01-02T15:04:05.000000000Z", k.TimeStamp)
199
				if err == nil {
200
					timeString = fmt.Sprintf("%v.%v.%v %v:%v", t.Day(), t.Month().String(), t.Year(), t.Hour(), t.Minute())
201
				} else {
202
					fmt.Println("Parse time: ", err.Error())
203
				}
204
				embed.Field(
205
					k.Victim.Name,
206
					fmt.Sprintf("%v [[%v](https://albiononline.com/ru/killboard/kill/%v)]",
207
						fmt.Sprintf(ctx.Loc("albion_kill_short"),
0 ignored issues
show
introduced by
can't check non-constant format in call to Sprintf
Loading history...
208
							k.Victim.DeathFame,
209
							k.Victim.AverageItemPower,
210
							timeString),
211
						k.EventID,
212
						k.EventID), false)
213
			}
214
			embed.Send(ctx)
215
		}
216
217
	}
218
}
219
220
func (ctx *Context) AlbionShowKill() {
0 ignored issues
show
introduced by
exported method Context.AlbionShowKill should have comment or be unexported
Loading history...
221
	kill, err := AlbionGetKillID(ctx.Args[1])
222
	if err != nil {
223
		fmt.Println("Error:" + err.Error())
224
		return
225
	}
226
227
	embed := NewEmbed(fmt.Sprintf("Show on killboard #%v", kill.EventID))
228
	embed.Desc(fmt.Sprintf("%v :crossed_swords: %v", kill.Killer.Name, kill.Victim.Name))
229
	embed.Color(ctx.GuildConf().EmbedColor)
230
	embed.URL(fmt.Sprintf("https://albiononline.com/ru/killboard/kill/%v", kill.EventID))
231
	embed.AttachThumbURL("https://assets.albiononline.com/assets/images/header/logo.png")
232
	embed.Author("Albion Killboard", "https://albiononline.com/ru/killboard", "")
233
	embed.TimeStamp(kill.TimeStamp)
234
	embed.Field(ctx.Loc("albion_guild"), kill.Victim.GuildName, true)
235
	embed.Field(ctx.Loc("albion_fame"), fmt.Sprintf("%v", kill.Victim.DeathFame), true)
236
	embed.Field(ctx.Loc("albion_item_power"), fmt.Sprintf("%.3f", kill.Victim.AverageItemPower), true)
237
	embed.Field(ctx.Loc("albion_killer_item_power"), fmt.Sprintf("%.3f", kill.Killer.AverageItemPower), true)
238
	if len(kill.Participants) > 0 {
239
		var names []string
240
		for _, p := range kill.Participants {
241
			names = append(names, fmt.Sprintf("%v (%.0f)", p.Name, p.DamageDone))
242
		}
243
		embed.Field(ctx.Loc("albion_participants"), strings.Join(names, ", "), true)
244
	}
245
	embed.Send(ctx)
246
}
247
248
func SendKill(session *discordgo.Session, conf *Config, kill *AlbionKill, userID string) {
0 ignored issues
show
introduced by
exported function SendKill should have comment or be unexported
Loading history...
249
	embed := NewEmbed(fmt.Sprintf("Show on killboard #%v", kill.EventID))
250
	embed.Desc(fmt.Sprintf("%v :crossed_swords: %v", kill.Killer.Name, kill.Victim.Name))
251
	embed.Color(4460547)
252
	embed.URL(fmt.Sprintf("https://albiononline.com/ru/killboard/kill/%v", kill.EventID))
253
	embed.AttachThumbURL("https://assets.albiononline.com/assets/images/header/logo.png")
254
	embed.Author("Albion Killboard", "https://albiononline.com/ru/killboard", "")
255
	embed.TimeStamp(kill.TimeStamp)
256
	if kill.Victim.GuildName != "" {
257
		embed.Field(conf.GetLocale("albion_guild"), kill.Victim.GuildName, true)
258
	}
259
	embed.Field(conf.GetLocale("albion_fame"), fmt.Sprintf("%v", kill.Victim.DeathFame), true)
260
	embed.Field(conf.GetLocale("albion_item_power"), fmt.Sprintf("%.2f", kill.Victim.AverageItemPower), true)
261
	embed.Field(conf.GetLocale("albion_killer_item_power"), fmt.Sprintf("%.2f", kill.Killer.AverageItemPower), true)
262
	if len(kill.Participants) > 0 {
263
		var names []string
264
		for _, p := range kill.Participants {
265
			names = append(names, fmt.Sprintf("%v (%.0f)", p.Name, p.DamageDone))
266
		}
267
		participants := strings.Join(names, ", ")
268
		if len(participants) < 1000 {
269
			embed.Field(conf.GetLocale("albion_participants"), participants, true)
270
		}
271
	}
272
	ch, err := session.UserChannelCreate(userID)
273
	if err != nil {
274
		fmt.Println("Error whilst creating private channel, ", err)
275
		return
276
	}
277
	_, err = session.ChannelMessageSendEmbed(ch.ID, embed.GetEmbed())
278
	if err != nil {
279
		fmt.Println("Error whilst sending embed message, ", err)
280
		return
281
	}
282
}
283
284
func GetPlayerByID(name string) string {
0 ignored issues
show
introduced by
exported function GetPlayerByID should have comment or be unexported
Loading history...
285
	search, err := AlbionSearchPlayers(name)
286
	if err == nil {
287
		if len(search.Players) > 0 {
288
			return search.Players[0].ID
289
		}
290
	}
291
	return ""
292
}
293
294
func AlbionGetUpdater(db *DBWorker) *AlbionUpdater {
0 ignored issues
show
introduced by
exported function AlbionGetUpdater should have comment or be unexported
Loading history...
295
	var updater = &AlbionUpdater{Players: make(map[string]*AlbionPlayerUpdater)}
296
	var players []AlbionPlayerUpdater
297
	players = db.GetAlbionPlayers()
298
	for _, p := range players {
299
		updater.Players[p.UserID] = &p
300
	}
301
	return updater
302
}
303
304
func SendPlayerKills(session *discordgo.Session, worker *DBWorker, conf *Config, updater *AlbionUpdater, userID string) {
0 ignored issues
show
introduced by
exported function SendPlayerKills should have comment or be unexported
Loading history...
305
	startTime := time.Unix(updater.Players[userID].StartAt, 0)
306
	lastTime := time.Unix(updater.Players[userID].LastKill, 0)
307
	if startTime.Add(time.Hour * 24).Unix() < time.Now().Unix() {
308
		worker.RemoveAlbionPlayer(updater.Players[userID].UserID)
309
		delete(updater.Players, updater.Players[userID].UserID)
310
		return
311
	} else {
0 ignored issues
show
introduced by
if block ends with a return statement, so drop this else and outdent its block
Loading history...
312
		kills, err := AlbionGetPlayerKills(updater.Players[userID].PlayerID)
313
		if err != nil {
314
			return
315
		}
316
		var newKillTime int64
317
		for i, k := range kills {
318
			killTime, err := time.Parse("2006-01-02T15:04:05.000000000Z", k.TimeStamp)
319
			if err != nil {
320
				fmt.Println("Kill time parse error: ", err.Error())
321
				continue
322
			}
323
			if killTime.Unix() > lastTime.Unix() {
324
				if killTime.Unix() > newKillTime {
325
					newKillTime = killTime.Unix()
326
				}
327
				SendKill(session, conf, &kills[i], userID)
328
			}
329
		}
330
		if newKillTime > lastTime.Unix() {
331
			worker.UpdateAlbionPlayerLast(userID, newKillTime)
332
			updater.Players[userID].LastKill = newKillTime
333
		}
334
	}
335
}
336
337
func (u *AlbionUpdater) Update(session *discordgo.Session, worker *DBWorker, conf *Config) {
0 ignored issues
show
introduced by
exported method AlbionUpdater.Update should have comment or be unexported
Loading history...
338
	for _, p := range u.Players {
339
		//go SendPlayerKills(session, worker, conf, u, p.UserID)
340
		startTime := time.Unix(u.Players[p.UserID].StartAt, 0)
341
		lastTime := time.Unix(u.Players[p.UserID].LastKill, 0)
342
		if startTime.Add(time.Hour * 24).Unix() < time.Now().Unix() {
343
			worker.RemoveAlbionPlayer(p.UserID)
344
			delete(u.Players, p.UserID)
345
			return
346
		} else {
0 ignored issues
show
introduced by
if block ends with a return statement, so drop this else and outdent its block
Loading history...
347
			kills, err := AlbionGetPlayerKills(p.PlayerID)
348
			if err != nil {
349
				return
350
			}
351
			var newKillTime int64
352
			for i, k := range kills {
353
				killTime, err := time.Parse("2006-01-02T15:04:05.000000000Z", k.TimeStamp)
354
				if err != nil {
355
					fmt.Println("Kill time parse error: ", err.Error())
356
					continue
357
				}
358
				fmt.Printf("Kill time: %v | Last time: %v\n", killTime.Unix(), lastTime.Unix())
359
				if killTime.Unix() > lastTime.Unix() {
360
					fmt.Printf("...Kill time: %v | > | Last kill: %v\n", killTime.Unix(), lastTime.Unix())
361
					if killTime.Unix() > newKillTime {
362
						fmt.Printf("......Kill time: %v | > | Last kill: %v\n", killTime.Unix(), newKillTime)
363
						newKillTime = killTime.Unix()
364
						fmt.Printf(".........New kill time: %v\n", newKillTime)
365
					}
366
					go SendKill(session, conf, &kills[i], p.UserID)
367
				}
368
			}
369
			fmt.Printf("Last: %v | New: %v\n", lastTime.Unix(), newKillTime)
370
			if newKillTime > lastTime.Unix() {
371
				worker.UpdateAlbionPlayerLast(p.UserID, newKillTime)
372
				u.Players[p.UserID].LastKill = newKillTime
373
			}
374
		}
375
	}
376
}
377
378
func (ctx *Context) AlbionAddPlayer() error {
0 ignored issues
show
introduced by
exported method Context.AlbionAddPlayer should have comment or be unexported
Loading history...
379
	if len(ctx.Args) > 1 {
380
		search, err := AlbionSearchPlayers(ctx.Args[1])
381
		if err != nil {
382
			fmt.Println("Error searching Albion player: ", err.Error())
383
			return errors.New("error searching Albion player")
384
		}
385
		if _, ok := ctx.Albion.Players[ctx.User.ID]; !ok {
386
			kills, err := AlbionGetPlayerKills(search.Players[0].ID)
387
			if err != nil {
388
				fmt.Println("Error getting Albion kills: ", err.Error())
389
				return errors.New("error getting Albion kills")
390
			}
391
			var lastKill int64
392
			for _, k := range kills {
393
				killTime, err := time.Parse("2006-01-02T15:04:05.000000000Z", k.TimeStamp)
394
				if err != nil {
395
					continue
396
				}
397
				if killTime.Unix() > lastKill {
398
					lastKill = killTime.Unix()
399
				}
400
			}
401
			player := &AlbionPlayerUpdater{search.Players[0].ID, ctx.User.ID, lastKill, time.Now().Unix()}
402
			ctx.Albion.Players[ctx.User.ID] = player
403
			ctx.DB.AddAlbionPlayer(player)
404
			return nil
405
		}
406
	}
407
	return errors.New("error")
408
}
409