· 6 years ago · Mar 18, 2020, 08:04 PM
1registerPlugin({
2 name: 'League Of Legends Rankify',
3 version: '1.4.0',
4 backends: ['ts3'],
5 description: 'Adds the corresponding League Of Legends Rank, Level, Role & InGame status for each user',
6 author: 'Erin McGowan <sinusbot_lolrankify@protected.calmarsolutions.ch>',
7 requiredModules: ['http', 'store'],
8 vars: [
9 {
10 name: 'LeagueOfLegendsApiKey',
11 title: 'Official RIOT API Key needed',
12 type: 'string',
13 placeholder: 'Looks like this: RGAPI-3ffb7016-687d-414a-aff4-0d5f18069a78'
14 },
15 {
16 name: 'LeagueRegion',
17 title: 'Select Riot Games Region',
18 type: 'select',
19 options: ['br1', 'eun1', 'euw1', 'jp1', 'kr', 'la1', 'la2', 'na1', 'oc1', 'tr1', 'ru']
20 },
21 {
22 name: 'RankQueueType',
23 title: 'Select the Rank-queue/s you want to show. DEFAULT = highest of both ranks',
24 type: 'select',
25 options: ['highest of both ranks', 'solo/duo rank', 'flex rank']
26 },
27 {
28 name: 'NameForSummonerSearch',
29 title: 'Select if you want to use "TS3 User Nicknames" INSTEAD of the "TS3 User Description" in this script. DEFAULT = description',
30 type: 'checkbox',
31 options: ['useNickname']
32 },
33 {
34 name: 'summonerLevelGroupIDs',
35 title: 'Add Summoner Level groups for lvl "0-30, 30+, 50+, 75+, 100+, 150+, 200+, 250+, 500+" in this order. (USE ENTER KEY)',
36 type: 'strings',
37 },
38 {
39 name: 'summonerLaneGroupIDs',
40 title: 'Add Summoner Lane groups for "TOP_LANE, MID_LANE, BOT_LANE, JUNGLE, SUPPORT" in this order. (USE ENTER KEY)',
41 type: 'strings',
42 },
43 {
44 name: 'gameHistoryCountToConsider',
45 title: 'The ammount of lol games (history) to consider when calculation the role (blank = default 60)',
46 type: 'select',
47 placeholder: '60',
48 options: ['10', '20', '30', '40', '50', '60', '70', '80', '90', '100']
49 },
50 {
51 name: 'inGameGroupId',
52 title: 'Empty/blank = disabled. Add the group ID that gets added if the user is ingame.',
53 type: 'number',
54 },
55 {
56 name: 'inGameFunctionInterval',
57 title: 'How often to check if user is ingame. Default = 60. Use seconds, not milliseconds!',
58 placeholder: '60',
59 type: 'number',
60 },
61 {
62 name: 'PermUserSetDescr',
63 title: 'Allow users to set their own description with !lolsetname <string>',
64 type: 'select',
65 options: ['no', 'yes'],
66 placeholder: 'Default = no'
67 },
68 { //-- Ranks
69 name: 'GroupUndefined',
70 title: 'Input Group if Unranked (Group ID). (NOT REQUIRED!)',
71 type: 'number'
72 },
73 {
74 name: 'GroupIron',
75 title: 'Input Group For Iron (Group ID)',
76 type: 'number'
77 },
78 {
79 name: 'GroupBronze',
80 title: 'Input Group For Bronze (Group ID)',
81 type: 'number'
82 },
83 {
84 name: 'GroupSilver',
85 title: 'Input Group For Silver (Group ID)',
86 type: 'number'
87 },
88 {
89 name: 'GroupGold',
90 title: 'Input Group For Gold (Group ID)',
91 type: 'number'
92 },
93 {
94 name: 'GroupPlatinum',
95 title: 'Input Group For Platinum (Group ID)',
96 type: 'number'
97 },
98 {
99 name: 'GroupDiamond',
100 title: 'Input Group For Diamond (Group ID)',
101 type: 'number'
102 },
103 {
104 name: 'GroupMaster',
105 title: 'Input Group For Master (Group ID)',
106 type: 'number'
107 },
108 {
109 name: 'GroupGrandmaster',
110 title: 'Input Group For Grandmaster (Group ID)',
111 type: 'number'
112 },
113 {
114 name: 'GroupChallenger',
115 title: 'Input Group For Challenger (Group ID)',
116 type: 'number'
117 }, //-- END Ranks
118 {
119 name: 'messageUnranked',
120 title: 'Input your message incase the client is unranked',
121 type: 'string',
122 placeholder: 'Sorry. You are unranked.',
123 },
124 {
125 name: 'messageRankReload',
126 title: 'Input your message for when the client reloads the rank manually',
127 type: 'string',
128 placeholder: 'Your rank was reloaded.',
129 },
130 ],
131}, function(sinusbot, config) {
132 // Variables
133 const engine = require('engine')
134 const backend = require('backend')
135 const event = require('event')
136 const http = require('http')
137 const store = require('store')
138
139 const apiKey = config.LeagueOfLegendsApiKey
140 const protocol = 'https://'
141 const groupUndefined = config.GroupUndefined
142 const leagueRankGroupIDs = [config.GroupIron, config.GroupBronze, config.GroupSilver, config.GroupGold, config.GroupPlatinum, config.GroupDiamond, config.GroupMaster, config.GroupGrandmaster, config.GroupChallenger]
143 const officialRankNamesArray = ['IRON', 'BRONZE', 'SILVER', 'GOLD', 'PLATINUM', 'DIAMOND', 'MASTER', 'GRANDMASTER', 'CHALLENGER']
144 const officialLaneNamesArray = ['TOP', 'MID', 'BOTTOM', 'JUNGLE', 'SUPPORT', 'NONE']
145 const gameHistoryNumbers = ['10', '20', '30', '40', '50', '60', '70', '80', '90', '100']
146 const permUserSetDescr = config.PermUserSetDescr || 'no'
147 const summonerLevelGroupIDsArray = config.summonerLevelGroupIDs
148 const summonerLaneGroupIDsArray = config.summonerLaneGroupIDs
149 const inGameGroupId = config.inGameGroupId
150 const nameForSummonerSearch = config.NameForSummonerSearch
151 //--
152 // Derived Variables
153 function clientBackend() {}
154 let clients // setting them in mainEvent now
155 let clientName
156 let leagueRegionShort = ['br1', 'eun1', 'euw1', 'jp1', 'kr', 'la1', 'la2', 'na1', 'oc1', 'tr1', 'ru']
157 let apiUrlSummonerV4Name
158 let apiUrlLeagueV4Summoner
159 let requestArray = []
160 let gameHistoryCount = gameHistoryNumbers[config.gameHistoryCountToConsider]
161 if (!gameHistoryCount) {
162 gameHistoryCount = 60
163 }
164 let inGameFunctionInterval = config.inGameFunctionInterval
165 if (!inGameFunctionInterval) {
166 inGameFunctionInterval = 60
167 }
168 let rankQueueTypeSelection = config.RankQueueType
169 if (!rankQueueTypeSelection) {
170 rankQueueTypeSelection = 0
171 }
172 let summonerTier
173 //--
174 // Objects
175 //--
176 // Var Messages
177 let message = {
178 rankReload: config.messageRankReload,
179 unranked: config.messageUnranked,
180 newDescription: config.messageNewDescription,
181 }
182 if (!message.rankReload) { message.rankReload = 'Your rank was reloaded.' }
183 if (!message.unranked) { message.unranked = 'Sorry. You are unranked.' }
184 if (!message.newDescription) { message.newDescription = 'Your description is now: ' }
185 //--
186 event.on('clientVisible', function (ev) {
187 backendClientsReload()
188 if (nameForSummonerSearch) {
189 clientName = ev.client.nick()
190 } else {
191 clientName = ev.client.description()
192 }
193 mainEvent(client = ev.client, clientName)
194 })
195
196 event.on('chat', function(ev) {
197 backendClientsReload()
198
199 if (nameForSummonerSearch) {
200 clientName = ev.client.nick()
201 } else {
202 clientName = ev.client.description()
203 }
204
205 if (ev.text === '!lolreload') {
206 console.log('Reloaded Rank of: ' + ev.client.name() )
207 mainEvent(client = ev.client, clientName)
208 ev.client.chat(message.rankReload)
209 }
210 if (ev.text === '!lolreload all') {
211 ev.client.chat('...reloading')
212
213 let chain = Promise.resolve()
214 for (let client of clients) {
215 if (nameForSummonerSearch) {
216 chain = chain.then(resolve => mainEvent(client, client.nick()))
217 } else {
218 chain = chain.then(resolve => mainEvent(client, client.description())).then(delay(300))
219 }
220
221 ev.client.chat('--> Reloaded rank of ' + client.name() + '.')
222 }
223
224 ev.client.chat('ALL ranks reloaded.')
225 }
226 if (ev.text.startsWith('!lolsetname') && permUserSetDescr === '1') { // user can set description by himself
227 let newDescription = ev.text.replace(/!lolsetname /, '')
228 ev.client.setDescription(newDescription)
229 ev.client.chat(message.newDescription + newDescription)
230
231 mainEvent(client = ev.client, clientName)
232 ev.client.chat(message.rankReload)
233 }
234 if (ev.text === '!lolignoreme') {
235 lolIgnore()
236 function lolIgnore () {
237 let clientUID = ev.client.uid()
238 let status = store.get(clientUID + '_ignoreme')
239
240 if (status !== false) {
241 store.set(clientUID + '_ignoreme', false)
242 ev.client.chat('Your InGame status is now INVISIBLE/HIDDEN.')
243 simpleServerGroupRemove(ev.client, inGameGroupId)
244 } else {
245 store.unset(clientUID + '_ignoreme')
246 ev.client.chat('Your InGame status is now VISIBLE.')
247 }
248 }
249 }
250 })
251
252 let delay = (time) => (result) => new Promise(resolve => setTimeout(() => resolve(result), time));
253
254 function backendClientsReload() {
255 clients = backend.getClients() // get list of all current clients
256 }
257
258 function mainEvent(client, userName) {
259 return new Promise(function (resolve) {
260 if (userName.length > 2) {
261
262 apiUrlSummonerV4Name = protocol + leagueRegionShort[config.LeagueRegion] + '.api.riotgames.com/lol/summoner/v4/summoners/by-name/' + userName.replace(/ /g, '%20') + '?api_key=' + apiKey;
263
264 if (client.getServerGroups().length > 0) {
265
266 makeRequest(apiUrlSummonerV4Name)
267 .then(result => makeRequest(protocol + leagueRegionShort[config.LeagueRegion] + '.api.riotgames.com/lol/league/v4/entries/by-summoner/' + result.id + '?api_key=' + apiKey))
268 .catch(error => engine.log('Error: ' + error))
269 .then(result => {
270 return new Promise(function (resolve) {
271 if (result[0] && result[0].tier) {
272 rankQueueTypeSwitch(result)
273 .then(result => {
274 compareLocalGroups(result, client.getServerGroups(), leagueRankGroupIDs, officialRankNamesArray, summonerTier, client)
275 }).then(result => {
276 resolve(result)
277 })
278 } else if (groupUndefined) {
279 addServerGroupRanked(client, groupUndefined)
280 resolve(result)
281 } else {
282 resolve(result)
283 }
284 })
285 })
286 .catch(error => engine.log('Error: ' + error))
287 .then(result => makeRequest(protocol + leagueRegionShort[config.LeagueRegion] + '.api.riotgames.com/lol/match/v4/matchlists/by-account/' + requestArray[0].accountId + '?api_key=' + apiKey + '&endIndex=' + gameHistoryCount))
288 .catch(error => engine.log('Error: ' + error))
289 .then(result => checkLaneStats(result, client))
290 .catch(error => engine.log('Error: ' + error))
291 .then(result => checkSummonerLevel(summonerLevelGroupIDsArray, requestArray[0].summonerLevel, client, result))
292 .catch(error => engine.log('Error: ' + error))
293 .then(result => {
294 requestArray = []
295 resolve(result)
296 })
297 .catch(error => engine.log('Error: ' + error));
298
299 }
300
301 } else {
302 resolve(client.name() + ' has no valid description.')
303 }
304 })
305 }
306
307
308 // -------- CHECK IF CLIENT / SUMMONER IS INGAME
309 function interval() {
310 backendClientsReload()
311 let statusChain = Promise.resolve()
312 for (let client of clients) {
313 statusChain = statusChain.then(result => checkInGameStatus(client))
314 }
315 }
316 if (inGameGroupId && inGameFunctionInterval) { // disable in-game status if no input in backend
317 // runs every 60 sec and runs on init.
318 interval();
319 setInterval(interval, inGameFunctionInterval * 1000)
320 }
321 function summonerNotInGame(client) {
322 return new Promise(function (resolve) {
323 simpleServerGroupRemove(client, inGameGroupId)
324 resolve()
325 })
326 }
327 function summonerInGame(client) {
328 return new Promise(function (resolve) {
329 addServerGroupRanked(client, inGameGroupId)
330 resolve()
331 })
332 }
333
334 function checkResult(client, result) { // used instead of .catch()
335 return new Promise(function (resolve) {
336 if (result !== undefined) {
337 summonerInGame(client, result)
338 } else {
339 summonerNotInGame(client, result)
340 }
341 resolve()
342 })
343 }
344
345 function checkInGameStatus(client) {
346 return new Promise(function (resolve) {
347
348 let userName
349 if (nameForSummonerSearch) {
350 userName = client.nick();
351 } else {
352 userName = client.description();
353 }
354 if (userName.length > 2 && store.get(client.uid() + '_ignoreme') !== false) {
355 apiUrlSummonerV4Name = protocol + leagueRegionShort[config.LeagueRegion] + '.api.riotgames.com/lol/summoner/v4/summoners/by-name/' + userName.replace(/ /g, '%20') + '?api_key=' + apiKey;
356
357 makeRequest(apiUrlSummonerV4Name, '', '', '', true)
358 .then(result => makeRequest(protocol + leagueRegionShort[config.LeagueRegion] + '.api.riotgames.com/lol/spectator/v4/active-games/by-summoner/' + result.id + '?api_key=' + apiKey, '', '', '', true))
359 .catch(result => console.log('Failed. "' + client.name() + '" is not InGame: ' + result))
360 .then(result => checkResult(client, result))
361 .catch(result => console.log('Unexpected Error: ' + result))
362 .then(result => resolve('Success. "' + client.name() + '" is InGame.'))
363 } else {
364 resolve('No Summoner Name found for ' + client.name() + '.')
365 }
366
367 })
368 }
369 // -------- END CHECK IF CLIENT / SUMMONER IS INGAME
370 function rankQueueTypeSwitch(result) {
371 return new Promise(function (resolve) {
372 summonerTier = ''
373 let compareTiers = []
374
375 for (let item of result) {
376 if (rankQueueTypeSelection === '0') { // both
377 compareTiers.push(item.tier)
378 } else if (rankQueueTypeSelection === '1') { // solo
379 if (item.queueType === 'RANKED_SOLO_5x5') {
380 summonerTier = item.tier
381 }
382 } else if (rankQueueTypeSelection === '2') { // flex
383 if (item.queueType === 'RANKED_FLEX_SR') {
384 summonerTier = item.tier
385 }
386 }
387 }
388
389 if (rankQueueTypeSelection === '0' && compareTiers.length > 0) {
390 compareStringToIndex(compareTiers[0], compareTiers[1])
391 } else {
392 resolve(result)
393 }
394
395 function compareStringToIndex(tierOne, tierTwo) {
396 // compare name to index, get the value and use the highest defined value
397 let indexOne = officialRankNamesArray.indexOf(tierOne)
398 let indexTwo = officialRankNamesArray.indexOf(tierTwo)
399
400 if (tierOne && tierTwo) {
401 if (indexOne >= indexTwo) {
402 summonerTier = tierOne
403 } else if (indexTwo > indexOne) {
404 summonerTier = tierTwo
405 }
406 } else if (tierOne) {
407 summonerTier = tierOne
408 } else if (tierTwo) {
409 summonerTier = tierTwo
410 }
411 resolve(result)
412 }
413 })
414 }
415
416 function compareServerGroups(serverGroupList, groupIDsArray, currentGroup, client) {
417 for (let clientGroup of serverGroupList) { // client groups
418 for (let group of groupIDsArray) {
419 if (group === clientGroup.id()) { // array of groups
420 if (group !== currentGroup) // if not equal to group that should be added
421 removeServerGroupRanked(group, client)
422 }
423 }
424 }
425 }
426
427 function checkLaneStats(parsed, client) {
428 return new Promise(function (resolve) {
429 if (summonerLaneGroupIDsArray.length > 4 && parsed && parsed.matches) {
430 let map = new Map()
431 map.set('TOP', 0)
432 map.set('MID', 0)
433 map.set('BOTTOM', 0)
434 map.set('JUNGLE', 0)
435 map.set('NONE', 0)
436
437 let map_role = new Map()
438 map_role.set('SOLO', 0)
439 map_role.set('DUO', 0)
440 map_role.set('NONE', 0)
441 map_role.set('DUO_CARRY', 0)
442 map_role.set('DUO_SUPPORT', 0)
443
444 for (let item of parsed.matches) {
445 let number = map.get(item.lane)
446 map.set(item.lane, number + 1)
447
448 number = map_role.get(item.role)
449 map_role.set(item.role, number + 1)
450 }
451
452 let mostUsedLane = [...map.entries()].reduce((a, e) => e[1] > a[1] ? e : a) // get the map with the highest value
453 let mostUsedLaneName = mostUsedLane[0]
454
455 let mostUsedRole = [...map_role.entries()].reduce((a, e) => e[1] > a[1] ? e : a) // get the map with the highest value
456 let mostUsedRoleName = mostUsedRole[0]
457
458 if (mostUsedLaneName === 'BOTTOM') {
459 if (mostUsedRoleName === 'DUO_SUPPORT') {
460 mostUsedLaneName = 'SUPPORT'
461 }
462 }
463
464 if (mostUsedLaneName === 'NONE') { // role is unclear
465 client.chat('Lane Preference Unclear.')
466 resolve(parsed)
467 return
468 }
469
470 compareLocalGroups(parsed, client.getServerGroups(), summonerLaneGroupIDsArray, officialLaneNamesArray, mostUsedLaneName, client)
471
472 resolve(parsed)
473 } else {
474 resolve(parsed)
475 }
476 })
477 }
478
479 function checkSummonerLevel(groupIDsArray, level, client, request) {
480 return new Promise(function (resolve, reject) {
481 if (summonerLevelGroupIDsArray) {
482
483 if (groupIDsArray !== undefined) {
484 function execute(number) {
485 compareServerGroups(client.getServerGroups(), groupIDsArray, groupIDsArray[number], client)
486 addServerGroupRanked(client, groupIDsArray[number])
487 }
488
489 if (level < 30) { //-25
490 execute(0)
491 } else if (level < 50) { //25
492 execute(1)
493 } else if (level < 75) { //50
494 execute(2)
495 } else if (level < 100) { //75
496 execute(3)
497 } else if (level < 150) { //100
498 execute(4)
499 } else if (level < 200) { //150
500 execute(5)
501 } else if (level < 250) { //200
502 execute(6)
503 } else if (level < 500) { //250
504 execute(7)
505 } else if (level > 500) { //500+
506 execute(8)
507 } else {
508 reject('An Unknown Error Occurred. var level is not a number.')
509 }
510
511 resolve(request) // continue to forward the request
512 } else {
513 reject('Can\'t work with Array. Array empty.')
514 }
515 } else {
516 resolve(request)
517 }
518 })
519 }
520
521 function compareLocalGroups(parsed, currentGroups, groupArrayIDs, groupNamesArray, newGroupName, client) {
522 return new Promise(function (resolve) {
523 let count = 0
524 let countMax = currentGroups.length * groupArrayIDs.length
525 let compareSwitch = false
526
527 for (let currentGroup of currentGroups) {
528 for (let groupID of groupArrayIDs) { // check if one of the Rank Groups match the added groups
529 if (currentGroup.id() == groupID) {
530 count++
531 compareSwitch = true
532 compareGroup(parsed, currentGroup.id(), groupArrayIDs, groupNamesArray, newGroupName, client)
533 resolve(parsed)
534 } else {
535 count++
536 if (count === countMax && compareSwitch === false) {
537 compareGroup(parsed, undefined, groupArrayIDs, groupNamesArray, newGroupName, client)
538 resolve(parsed)
539 }
540 }
541 }
542 }
543
544 simpleServerGroupRemove(client, groupUndefined) // remove rank undefined group if client has it
545
546 if (!newGroupName) {
547 resolve()
548 }
549 })
550 }
551
552 function compareGroup(parsed, currentGroup, theNewGroupIdArray, theNewGroupNameArray, newGroupName, client) { // beware that currentGroup will be removed!
553 return new Promise(function (resolve) {
554 if (parsed) {
555 let newGroup = theNewGroupNameArray.indexOf(newGroupName) // get the index by string
556 newGroup = theNewGroupIdArray[newGroup] // insert index to get correct group
557
558 if (currentGroup == newGroup) {
559 resolve()
560 } else if (currentGroup != newGroup) {
561 if (currentGroup !== undefined) {
562 removeServerGroupRanked(currentGroup, client)
563 }
564 addServerGroupRanked(client, newGroup)
565 resolve()
566 }
567 } else {
568 client.chat(message.unranked)
569 }
570 })
571 }
572
573 function addServerGroupRanked(client, group) {
574 return new Promise(function (resolve) {
575 let count = 0
576 let max = client.getServerGroups().length
577 for (let groupId of client.getServerGroups()) {
578 if (groupId.id() == group) {
579 resolve('Group exists. None added to: ' + client.name())
580 return
581 }
582 count++
583 if (count === max) {
584 client.addToServerGroup(group)
585 resolve('Rank added for ' + client.name())
586 }
587 }
588
589 })
590 }
591
592 function removeServerGroupRanked(group, client) {
593 return new Promise(function (resolve) {
594 client.removeFromServerGroup(group)
595 resolve()
596 })
597 }
598
599 function simpleServerGroupRemove(client, groupToRemove) {
600 return new Promise(function (resolve) {
601 for (let group of client.getServerGroups()) {
602 if (group.id() == groupToRemove) {
603 client.removeFromServerGroup(groupToRemove)
604 resolve()
605 }
606 }
607 })
608 }
609
610 function makeRequest(url, method, datatype, timeout, prevent_push_array) {
611 return new Promise(function (resolve, reject) {
612
613 http.simpleRequest({
614 'method': method || 'GET',
615 'url': url,
616 'dataType': datatype || 'json',
617 'timeout': timeout || 6000,
618 }, function (error, response) {
619
620 if (error) {
621 reject(error)
622 }
623
624 if (response.statusCode == 404) {
625 reject(response.status)
626 }
627
628 if (response.statusCode != 200) {
629 reject(response.status)
630 }
631
632 let parsed = JSON.parse(response.data)
633 if (!prevent_push_array) { // stops the array push if true
634 requestArray.push(parsed)
635 }
636 resolve(parsed);
637
638 });
639
640 })
641 }
642
643});