modules: Move most code in main package to their own modules
parent
4887d55707
commit
825cf44216
@ -1,89 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/rand"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/bwmarrin/discordgo"
|
|
||||||
|
|
||||||
"PermissionGacha/db"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
viewAuditLogRole = "645856347258093568"
|
|
||||||
manageWebhookRole = "645856081750523914"
|
|
||||||
changeNicknameRole = "645977231281356800"
|
|
||||||
embedLinkRole = "645977361254318080"
|
|
||||||
voiceActivityRole = "645977361254318080"
|
|
||||||
)
|
|
||||||
|
|
||||||
func checkForGachaEligibility(dg *discordgo.Session, discordID, intendedLevel string) {
|
|
||||||
member, err := dg.GuildMember(guildID, discordID)
|
|
||||||
if err != nil {
|
|
||||||
logError(dg, "checkForGachaEligibility", "getGuildMember", discordID)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
found := false
|
|
||||||
for _, v := range member.Roles {
|
|
||||||
if v == intendedLevel {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if found {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if intendedLevel != rolesFromLevel[0] {
|
|
||||||
rollGacha(dg, member)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = dg.GuildMemberRoleAdd(guildID, discordID, intendedLevel)
|
|
||||||
if err != nil {
|
|
||||||
logError(dg, "checkForGachaEligibility", "guildMemberRoleAdd", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func rollGacha(dg *discordgo.Session, member *discordgo.Member) {
|
|
||||||
lookUpAndGive := func(friendlyName, role string) {
|
|
||||||
found := false
|
|
||||||
for _, v := range member.Roles {
|
|
||||||
if v == role {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
channel, err := dg.UserChannelCreate(member.User.ID)
|
|
||||||
if found {
|
|
||||||
db.RewardShard(member.User.ID, 1)
|
|
||||||
if err == nil {
|
|
||||||
dg.ChannelMessageSend(
|
|
||||||
channel.ID,
|
|
||||||
fmt.Sprintf(
|
|
||||||
"**GACHA > ** You got __%s__! However, it was a duplicate so you got a shard instead.", friendlyName,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
dg.GuildMemberRoleAdd(guildID, member.User.ID, role)
|
|
||||||
dg.ChannelMessageSend(
|
|
||||||
channel.ID,
|
|
||||||
fmt.Sprintf("**GACHA > ** You got __%s__!", friendlyName),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gachaRandomness := make([]byte, 1)
|
|
||||||
rand.Read(gachaRandomness)
|
|
||||||
switch gachaRandomness[0] % 5 {
|
|
||||||
case 0:
|
|
||||||
lookUpAndGive("View Audit Log", viewAuditLogRole)
|
|
||||||
case 1:
|
|
||||||
lookUpAndGive("Manage Webhook", manageWebhookRole)
|
|
||||||
case 2:
|
|
||||||
lookUpAndGive("Change Nickname", changeNicknameRole)
|
|
||||||
case 3:
|
|
||||||
lookUpAndGive("Embed Link", embedLinkRole)
|
|
||||||
case 4:
|
|
||||||
lookUpAndGive("Use Voice Activity", voiceActivityRole)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,54 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/bwmarrin/discordgo"
|
|
||||||
)
|
|
||||||
|
|
||||||
const guildID = "645550569573842945"
|
|
||||||
|
|
||||||
var levelMutex sync.Mutex
|
|
||||||
var levelQueue = make(map[string]bool)
|
|
||||||
var assignedLevels = make(map[string]int)
|
|
||||||
var rolesFromLevel []string
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
levels, _ := ioutil.ReadFile("roles.txt")
|
|
||||||
rolesFromLevel = strings.Split(string(levels), "\n")
|
|
||||||
for k, v := range rolesFromLevel {
|
|
||||||
rolesFromLevel[k] = strings.TrimSpace(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func addToLevelQueue(discordID string) {
|
|
||||||
levelMutex.Lock()
|
|
||||||
defer levelMutex.Unlock()
|
|
||||||
levelQueue[discordID] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func listenToLevelUpdate(dg *discordgo.Session) {
|
|
||||||
for {
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
levelMutex.Lock()
|
|
||||||
for k, v := range levelQueue {
|
|
||||||
if !v {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
levelQueue[k] = false
|
|
||||||
level, _, err := getLevelAndXP(k)
|
|
||||||
if err != nil {
|
|
||||||
logError(dg, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if assignedLevels[k] != level {
|
|
||||||
assignedLevels[k] = level
|
|
||||||
go checkForGachaEligibility(dg, k, rolesFromLevel[level-1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
levelMutex.Unlock()
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,3 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
const GuildID = "645550569573842945"
|
@ -0,0 +1,22 @@
|
|||||||
|
package gacha
|
||||||
|
|
||||||
|
import (
|
||||||
|
crand "crypto/rand"
|
||||||
|
"encoding/binary"
|
||||||
|
mrand "math/rand"
|
||||||
|
)
|
||||||
|
|
||||||
|
var rand = mrand.New(cryptoSource{})
|
||||||
|
|
||||||
|
type cryptoSource struct{}
|
||||||
|
|
||||||
|
func (cryptoSource) Int63() int64 {
|
||||||
|
var value uint64
|
||||||
|
err := binary.Read(crand.Reader, binary.BigEndian, &value)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return int64(value ^ uint64(1<<63))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cryptoSource) Seed(seed int64) {}
|
@ -0,0 +1,50 @@
|
|||||||
|
package gacha
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/bwmarrin/discordgo"
|
||||||
|
|
||||||
|
"PermissionGacha/modules/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
type reward struct {
|
||||||
|
FriendlyName string
|
||||||
|
Reward func(s *discordgo.Session, member *discordgo.Member) (bool, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
var gachaRewards = []reward{
|
||||||
|
reward{
|
||||||
|
FriendlyName: "View Audit Log",
|
||||||
|
Reward: generateRoleReward("645856347258093568"),
|
||||||
|
},
|
||||||
|
reward{
|
||||||
|
FriendlyName: "Manage Webhook",
|
||||||
|
Reward: generateRoleReward("645856081750523914"),
|
||||||
|
},
|
||||||
|
reward{
|
||||||
|
FriendlyName: "Change Nickname",
|
||||||
|
Reward: generateRoleReward("645977231281356800"),
|
||||||
|
},
|
||||||
|
reward{
|
||||||
|
FriendlyName: "Use Voice Activity",
|
||||||
|
Reward: generateRoleReward("645880647474479115"),
|
||||||
|
},
|
||||||
|
reward{
|
||||||
|
FriendlyName: "Embed Link",
|
||||||
|
Reward: generateRoleReward("645977361254318080"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateRoleReward(roleID string) func(s *discordgo.Session, member *discordgo.Member) (bool, error) {
|
||||||
|
return func(s *discordgo.Session, member *discordgo.Member) (bool, error) {
|
||||||
|
for _, v := range member.Roles {
|
||||||
|
if v == roleID {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err := s.GuildMemberRoleAdd(config.GuildID, member.User.ID, roleID)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
package gacha
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/bwmarrin/discordgo"
|
||||||
|
|
||||||
|
"PermissionGacha/db"
|
||||||
|
"PermissionGacha/modules/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func RollReward(s *discordgo.Session, rewardeeID string, timesToReward int) error {
|
||||||
|
if timesToReward <= 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
rewardee, err := s.GuildMember(config.GuildID, rewardeeID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rewardCount := make(map[int]map[bool]int)
|
||||||
|
shardCount := 0
|
||||||
|
for i := 0; i < timesToReward; i++ {
|
||||||
|
rewardID := rand.Intn(len(gachaRewards))
|
||||||
|
success, err := gachaRewards[rewardID].Reward(s, rewardee)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, ok := rewardCount[rewardID]; !ok {
|
||||||
|
rewardCount[rewardID] = make(map[bool]int)
|
||||||
|
}
|
||||||
|
if success {
|
||||||
|
rewardee, err = s.GuildMember(config.GuildID, rewardeeID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
shardCount++
|
||||||
|
}
|
||||||
|
rewardCount[rewardID][success]++
|
||||||
|
}
|
||||||
|
err = db.RewardShard(rewardeeID, shardCount)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
channel, err := s.UserChannelCreate(rewardeeID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if timesToReward == 1 {
|
||||||
|
for k, v := range rewardCount {
|
||||||
|
if v[true] > 0 {
|
||||||
|
//They were rewarded that exact thing.
|
||||||
|
s.ChannelMessageSend(
|
||||||
|
channel.ID,
|
||||||
|
fmt.Sprintf(
|
||||||
|
"**GACHA >** <@%s>, you just levelled up! You got __%s__.",
|
||||||
|
rewardeeID, gachaRewards[k].FriendlyName,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
//They were rewarded that thing but got a shard instead.
|
||||||
|
s.ChannelMessageSend(
|
||||||
|
channel.ID,
|
||||||
|
fmt.Sprintf(
|
||||||
|
"**GACHA >** <@%s>, you just levelled up! You originally got __%s__ but you got a shard instead.",
|
||||||
|
rewardeeID, gachaRewards[k].FriendlyName,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
msg := fmt.Sprintf(
|
||||||
|
"**GACHA >** <@%s>, you just levelled up %d times. Here are your rewards:",
|
||||||
|
rewardeeID, timesToReward,
|
||||||
|
)
|
||||||
|
for k, v := range rewardCount {
|
||||||
|
msg += fmt.Sprintf("\n- __%s__", gachaRewards[k].FriendlyName)
|
||||||
|
if v[false] > 0 {
|
||||||
|
msg += fmt.Sprintf(" (%d converted to shards)", v[false])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.ChannelMessageSend(channel.ID, msg)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
package level
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
|
||||||
|
"PermissionGacha/db"
|
||||||
|
)
|
||||||
|
|
||||||
|
var levelUpRequirementCache [30]int
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
for i := 1; i <= 30; i++ {
|
||||||
|
//Constructed on Desmos:
|
||||||
|
//y=2^{\frac{x}{2}}+.1x^{2}+1.2x-1
|
||||||
|
fi := float64(i)
|
||||||
|
levelUpRequirementCache[i-1] = int(10000 * (math.Pow(2, fi/2) + 0.1*fi*fi + 1.2*fi - 1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetLevelAndXP(discordID string) (int, int, error) {
|
||||||
|
rawXP, err := db.GetXP(discordID)
|
||||||
|
if err != nil {
|
||||||
|
return 1, 0, fmt.Errorf("level: GetLevelAndXP: error requesting XP: %w", err)
|
||||||
|
}
|
||||||
|
level, xp := ConvertXPIntoLevel(rawXP)
|
||||||
|
return level, xp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetLevelUpRequirement(level int) int {
|
||||||
|
if level <= 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if level == 1 {
|
||||||
|
return levelUpRequirementCache[0]
|
||||||
|
}
|
||||||
|
if level > len(levelUpRequirementCache) {
|
||||||
|
return levelUpRequirementCache[len(levelUpRequirementCache)-1]
|
||||||
|
}
|
||||||
|
return levelUpRequirementCache[level-1] - levelUpRequirementCache[level-2]
|
||||||
|
}
|
||||||
|
|
||||||
|
func ConvertXPIntoLevel(xp int) (int, int) {
|
||||||
|
if xp < levelUpRequirementCache[0] {
|
||||||
|
return 1, xp
|
||||||
|
}
|
||||||
|
for i := 0; i < 30; i++ {
|
||||||
|
if levelUpRequirementCache[i] > xp {
|
||||||
|
return i + 1, xp - levelUpRequirementCache[i-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 30, xp - levelUpRequirementCache[29]
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
package level
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/bwmarrin/discordgo"
|
||||||
|
|
||||||
|
"PermissionGacha/modules/gacha"
|
||||||
|
"PermissionGacha/modules/log"
|
||||||
|
"PermissionGacha/modules/roles"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
levelMutex sync.Mutex
|
||||||
|
levelQueue = make(map[string]bool)
|
||||||
|
lastKnownLevel = make(map[string]int)
|
||||||
|
)
|
||||||
|
|
||||||
|
func QueueCheck(discordID string) {
|
||||||
|
levelMutex.Lock()
|
||||||
|
defer levelMutex.Unlock()
|
||||||
|
levelQueue[discordID] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func ScheduleUpdates(s *discordgo.Session) {
|
||||||
|
for {
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
levelMutex.Lock()
|
||||||
|
for id, isQueued := range levelQueue {
|
||||||
|
if !isQueued {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
delete(levelQueue, id)
|
||||||
|
level, _, err := GetLevelAndXP(id)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(s, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if lastKnownLevel[id] != level {
|
||||||
|
lastKnownLevel[id] = level
|
||||||
|
go func() {
|
||||||
|
oldLevel, err := roles.GetOldLevel(s, id)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(s, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if level > oldLevel {
|
||||||
|
gacha.RollReward(s, id, level-oldLevel)
|
||||||
|
roles.GiveLevelRoles(s, id, oldLevel, level)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
levelMutex.Unlock()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package log
|
||||||
|
|
||||||
|
import (
|
||||||
|
llog "log"
|
||||||
|
|
||||||
|
"github.com/bwmarrin/discordgo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Error(s *discordgo.Session, a ...interface{}) {
|
||||||
|
s.UpdateStatusComplex(discordgo.UpdateStatusData{
|
||||||
|
Game: &discordgo.Game{
|
||||||
|
Name: "with error",
|
||||||
|
Type: discordgo.GameTypeGame,
|
||||||
|
},
|
||||||
|
Status: string(discordgo.StatusDoNotDisturb),
|
||||||
|
})
|
||||||
|
llog.Println(a...)
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package roles
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/bwmarrin/discordgo"
|
||||||
|
|
||||||
|
"PermissionGacha/modules/config"
|
||||||
|
"PermissionGacha/modules/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GiveLevelRoles(s *discordgo.Session, discordID string, oldLevel, newLevel int) {
|
||||||
|
for i := oldLevel; i <= newLevel; i++ {
|
||||||
|
s.GuildMemberRoleAdd(config.GuildID, discordID, rolesFromLevel[i-1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func RemoveAllLevelRoles(s *discordgo.Session, discordID string) {
|
||||||
|
member, err := s.GuildMember(config.GuildID, discordID)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(s, "RemoveAllLevelRoles", "GuildMember", discordID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, v := range member.Roles {
|
||||||
|
for _, w := range rolesFromLevel {
|
||||||
|
if v == w {
|
||||||
|
s.GuildMemberRoleRemove(config.GuildID, discordID, v)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package roles
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/bwmarrin/discordgo"
|
||||||
|
|
||||||
|
"PermissionGacha/modules/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetOldLevel(s *discordgo.Session, id string) (int, error) {
|
||||||
|
member, err := s.GuildMember(config.GuildID, id)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("roles: EligibleGachaCount: error fetching guild member (%s): %w", id, err)
|
||||||
|
}
|
||||||
|
var foundLevel = 0
|
||||||
|
levelSearchLoop:
|
||||||
|
for i := len(rolesFromLevel); i > 0; i-- {
|
||||||
|
for _, v := range member.Roles {
|
||||||
|
if rolesFromLevel[i-1] == v {
|
||||||
|
foundLevel = i
|
||||||
|
break levelSearchLoop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if foundLevel == 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
return foundLevel, nil
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package roles
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var rolesFromLevel []string
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
listOfRoles, _ := ioutil.ReadFile("roles.txt")
|
||||||
|
rolesFromLevel = strings.Split(string(listOfRoles), "\n")
|
||||||
|
for k, v := range rolesFromLevel {
|
||||||
|
rolesFromLevel[k] = strings.TrimSpace(v)
|
||||||
|
}
|
||||||
|
}
|
@ -1,21 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/bwmarrin/discordgo"
|
|
||||||
)
|
|
||||||
|
|
||||||
func cleanUpRole(s *discordgo.Session, discordID string) {
|
|
||||||
member, err := s.GuildMember(guildID, discordID)
|
|
||||||
if err != nil {
|
|
||||||
logError(s, "cleanUpRole", "guildMember", discordID)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, v := range member.Roles {
|
|
||||||
for _, w := range rolesFromLevel {
|
|
||||||
if v == w {
|
|
||||||
s.GuildMemberRoleRemove(guildID, discordID, v)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue