Passed
Push — master ( d308f4...774918 )
by Viktor
01:32
created

bot.AlbionMakeUpdater   A

Complexity

Conditions 1

Size

Total Lines 2
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nop 0
dl 0
loc 2
rs 10
c 0
b 0
f 0
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
func AlbionMakeUpdater() *AlbionUpdater {
0 ignored issues
show
introduced by
exported function AlbionMakeUpdater should have comment or be unexported
Loading history...
115
	return &AlbionUpdater{make(map[string]*AlbionPlayerUpdater)}
116
}
117
118
// 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...
119
func AlbionSearchPlayers(name string) (result *AlbionSearchResult, err error) {
120
	var sResult AlbionSearchResult
121
	resp, err := http.Get(fmt.Sprintf("https://gameinfo.albiononline.com/api/gameinfo/search?q=%v", name))
122
	if err != nil {
123
		return nil, err
124
	}
125
126
	if resp.StatusCode != 200 {
127
		return nil, errors.New("status " + resp.Status)
128
	}
129
130
	err = json.NewDecoder(resp.Body).Decode(&sResult)
131
	if err != nil {
132
		return nil, err
133
	}
134
135
	return &sResult, nil
136
}
137
138
// 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...
139
func AlbionGetPlayerKills(id string) (result []AlbionKill, err error) {
140
	var kills []AlbionKill
141
	resp, err := http.Get(fmt.Sprintf("https://gameinfo.albiononline.com/api/gameinfo/players/%v/topkills?range=lastWeek&offset=0&limit=20", id))
142
	if err != nil {
143
		return nil, err
144
	}
145
146
	if resp.StatusCode != 200 {
147
		return nil, errors.New("status " + resp.Status)
148
	}
149
150
	err = json.NewDecoder(resp.Body).Decode(&kills)
151
	if err != nil {
152
		return nil, err
153
	}
154
155
	return kills, nil
156
}
157
158
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...
159
	var result AlbionKill
160
	resp, err := http.Get(fmt.Sprintf("https://gameinfo.albiononline.com/api/gameinfo/events/%v", id))
161
	if err != nil {
162
		return nil, err
163
	}
164
165
	if resp.StatusCode != 200 {
166
		return nil, errors.New("status " + resp.Status)
167
	}
168
169
	err = json.NewDecoder(resp.Body).Decode(&result)
170
	if err != nil {
171
		return nil, err
172
	}
173
174
	return &result, nil
175
}
176
177
// 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...
178
func (ctx *Context) AlbionShowKills() {
179
	search, err := AlbionSearchPlayers(ctx.Args[1])
180
	if err != nil {
181
		fmt.Println("Error:" + err.Error())
182
		return
183
	}
184
	fmt.Println("Founded players")
185
	if len(search.Players) > 0 {
186
		fmt.Println("Players more then 0")
187
		kills, err := AlbionGetPlayerKills(search.Players[0].ID)
188
		fmt.Println("Searching kills of " + search.Players[0].Name + search.Players[0].ID)
189
		if err != nil {
190
			fmt.Println("Error: " + err.Error())
191
			return
192
		}
193
		fmt.Println("Founded kills of " + search.Players[0].Name)
194
		if len(kills) > 0 {
195
			fmt.Println("Kills more then 0")
196
			embed := NewEmbed("Albion Killboard")
197
			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")
198
			embed.Color(ctx.GuildConf().EmbedColor)
199
			for _, k := range kills {
200
				fmt.Println("Killed " + k.Victim.Name)
201
				var timeString string
202
				t, err := time.Parse("2006-01-02T15:04:05.000000000Z", k.TimeStamp)
203
				if err == nil {
204
					timeString = fmt.Sprintf("%v.%v.%v %v:%v", t.Day(), t.Month().String(), t.Year(), t.Hour(), t.Minute())
205
				} else {
206
					fmt.Println("Parse time: ", err.Error())
207
				}
208
				embed.Field(
209
					k.Victim.Name,
210
					fmt.Sprintf("%v [[%v](https://albiononline.com/ru/killboard/kill/%v)]",
211
						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...
212
							k.Victim.DeathFame,
213
							k.Victim.AverageItemPower,
214
							timeString),
215
						k.EventID,
216
						k.EventID), false)
217
			}
218
			embed.Send(ctx)
219
		}
220
221
	}
222
}
223
224
func (ctx *Context) AlbionShowKill() {
0 ignored issues
show
introduced by
exported method Context.AlbionShowKill should have comment or be unexported
Loading history...
225
	kill, err := AlbionGetKillID(ctx.Args[1])
226
	if err != nil {
227
		fmt.Println("Error:" + err.Error())
228
		return
229
	}
230
231
	embed := NewEmbed(fmt.Sprintf("Show on killboard #%v", kill.EventID))
232
	embed.Desc(fmt.Sprintf("%v :crossed_swords: %v", kill.Killer.Name, kill.Victim.Name))
233
	embed.Color(ctx.GuildConf().EmbedColor)
234
	embed.URL(fmt.Sprintf("https://albiononline.com/ru/killboard/kill/%v", kill.EventID))
235
	embed.AttachThumbURL("https://assets.albiononline.com/assets/images/header/logo.png")
236
	embed.Author("Albion Killboard", "https://albiononline.com/ru/killboard", "")
237
	embed.TimeStamp(kill.TimeStamp)
238
	embed.Field(ctx.Loc("albion_guild"), kill.Victim.GuildName, true)
239
	embed.Field(ctx.Loc("albion_fame"), fmt.Sprintf("%v", kill.Victim.DeathFame), true)
240
	embed.Field(ctx.Loc("albion_item_power"), fmt.Sprintf("%.3f", kill.Victim.AverageItemPower), true)
241
	embed.Field(ctx.Loc("albion_killer_item_power"), fmt.Sprintf("%.3f", kill.Killer.AverageItemPower), true)
242
	if len(kill.Participants) > 0 {
243
		var names []string
244
		for _, p := range kill.Participants {
245
			names = append(names, fmt.Sprintf("%v (%.0f)", p.Name, p.DamageDone))
246
		}
247
		embed.Field(ctx.Loc("albion_participants"), strings.Join(names, ", "), true)
248
	}
249
	embed.Send(ctx)
250
}
251
252
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...
253
	embed := NewEmbed(fmt.Sprintf("Show on killboard #%v", kill.EventID))
254
	embed.Desc(fmt.Sprintf("%v :crossed_swords: %v", kill.Killer.Name, kill.Victim.Name))
255
	embed.Color(4460547)
256
	embed.URL(fmt.Sprintf("https://albiononline.com/ru/killboard/kill/%v", kill.EventID))
257
	embed.AttachThumbURL("https://assets.albiononline.com/assets/images/header/logo.png")
258
	embed.Author("Albion Killboard", "https://albiononline.com/ru/killboard", "")
259
	embed.TimeStamp(kill.TimeStamp)
260
	embed.Field(conf.GetLocale("albion_guild"), kill.Victim.GuildName, true)
261
	embed.Field(conf.GetLocale("albion_fame"), fmt.Sprintf("%v", kill.Victim.DeathFame), true)
262
	embed.Field(conf.GetLocale("albion_item_power"), fmt.Sprintf("%.3f", kill.Victim.AverageItemPower), true)
263
	embed.Field(conf.GetLocale("albion_killer_item_power"), fmt.Sprintf("%.3f", kill.Killer.AverageItemPower), true)
264
	if len(kill.Participants) > 0 {
265
		var names []string
266
		for _, p := range kill.Participants {
267
			names = append(names, fmt.Sprintf("%v (%.0f)", p.Name, p.DamageDone))
268
		}
269
		embed.Field(conf.GetLocale("albion_participants"), strings.Join(names, ", "), true)
270
	}
271
	ch, err := session.UserChannelCreate(userID)
272
	if err != nil {
273
		fmt.Println("Error whilst creating private channel, ", err)
274
		return
275
	}
276
	_, err = session.ChannelMessageSendEmbed(ch.ID, embed.GetEmbed())
277
	if err != nil {
278
		fmt.Println("Error whilst sending embed message, ", err)
279
		return
280
	}
281
}
282
283
func GetPlayerID(name string) string {
0 ignored issues
show
introduced by
exported function GetPlayerID should have comment or be unexported
Loading history...
284
	search, err := AlbionSearchPlayers(name)
285
	if err == nil {
286
		if len(search.Players) > 0 {
287
			return search.Players[0].ID
288
		}
289
	}
290
	return ""
291
}
292
293
func AlbionGetUpdater(db *DBWorker) *AlbionUpdater {
0 ignored issues
show
introduced by
exported function AlbionGetUpdater should have comment or be unexported
Loading history...
294
	var updater = &AlbionUpdater{Players: make(map[string]*AlbionPlayerUpdater)}
295
	var players []AlbionPlayerUpdater
296
	players = db.GetAlbionPlayers()
297
	for _, p := range players {
298
		updater.Players[p.UserID] = &p
299
	}
300
	return updater
301
}
302
303
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...
304
	startTime := time.Unix(updater.Players[userID].StartAt, 0)
305
	lastTime := time.Unix(updater.Players[userID].LastKill, 0)
306
	if startTime.Add(time.Hour * 24).Unix() > time.Now().Unix() {
307
		worker.RemoveAlbionPlayer(updater.Players[userID].UserID)
308
		delete(updater.Players, updater.Players[userID].UserID)
309
		return
310
	} else {
0 ignored issues
show
introduced by
if block ends with a return statement, so drop this else and outdent its block
Loading history...
311
		kills, err := AlbionGetPlayerKills(updater.Players[userID].PlayerID)
312
		if err != nil {
313
			return
314
		}
315
		var newKillTime int64
316
		for i, k := range kills {
317
			killTime, err := time.Parse("", k.TimeStamp)
318
			if err != nil {
319
				return
320
			}
321
			if killTime.Unix() > lastTime.Unix() {
322
				if killTime.Unix() > newKillTime {
323
					newKillTime = killTime.Unix()
324
				}
325
				SendKill(session, conf, &kills[i], userID)
326
			}
327
		}
328
		if newKillTime > lastTime.Unix() {
329
			worker.UpdateAlbionPlayerLast(userID, newKillTime)
330
			updater.Players[userID].LastKill = newKillTime
331
		}
332
	}
333
}
334
335
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...
336
	for _, p := range u.Players {
337
		go SendPlayerKills(session, worker, conf, u, p.UserID)
338
	}
339
}
340
341
func (u *AlbionUpdater) Add(ctx *Context) error {
0 ignored issues
show
introduced by
exported method AlbionUpdater.Add should have comment or be unexported
Loading history...
342
	if len(ctx.Args) > 1 {
343
		search, err := AlbionSearchPlayers(ctx.Args[1])
344
		if err != nil {
345
			fmt.Println("Error searching Albion player: ", err.Error())
346
			return errors.New("error searching Albion player")
347
		}
348
		if _, ok := ctx.Albion.Players[ctx.User.ID]; !ok {
349
			kills, err := AlbionGetPlayerKills(search.Players[0].ID)
350
			if err != nil {
351
				fmt.Println("Error getting Albion kills: ", err.Error())
352
				return errors.New("error getting Albion kills")
353
			}
354
			var lastKill int64
355
			for _, k := range kills {
356
				killTime, err := time.Parse("2006-01-02T15:04:05.000000000Z", k.TimeStamp)
357
				if err != nil {
358
					continue
359
				}
360
				if killTime.Unix() > lastKill {
361
					lastKill = killTime.Unix()
362
				}
363
			}
364
			ctx.Albion.Players[ctx.User.ID] = &AlbionPlayerUpdater{search.Players[0].ID, ctx.User.ID, lastKill, time.Now().Unix()}
365
			return nil
366
		}
367
	}
368
	return errors.New("error")
369
}
370