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