Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add feature discord command "/cosmetic-loadout" #7

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 26 additions & 7 deletions server/evr_profile.go
Original file line number Diff line number Diff line change
@@ -33,13 +33,14 @@ type GameProfile interface {
}

type GameProfileData struct {
Login evr.LoginProfile `json:"login"`
Client evr.ClientProfile `json:"client"`
Server evr.ServerProfile `json:"server"`
Rating types.Rating `json:"rating"`
EarlyQuits EarlyQuitStatistics `json:"early_quit"`
Version string // The version of the profile from the DB
Stale bool // Whether the profile is stale and needs to be updated
Login evr.LoginProfile `json:"login"`
Client evr.ClientProfile `json:"client"`
Server evr.ServerProfile `json:"server"`
Rating types.Rating `json:"rating"`
EarlyQuits EarlyQuitStatistics `json:"early_quit"`
CosmeticPresets map[string]evr.CosmeticLoadout `json:"cosmetic_presets"`
Version string // The version of the profile from the DB
Stale bool // Whether the profile is stale and needs to be updated
}

type AccountProfile struct {
@@ -725,3 +726,21 @@ func SetCosmeticDefaults(s *evr.ServerProfile, enableAll bool) error {
}
return nil
}

func (p *GameProfileData) saveCosmeticPreset(profileName string) {
if p.CosmeticPresets == nil {
p.CosmeticPresets = make(map[string]evr.CosmeticLoadout)
}
p.CosmeticPresets[profileName] = p.Server.EquippedCosmetics.Instances.Unified.Slots
p.SetStale()
}

func (p *GameProfileData) loadCosmeticPreset(profileName string) {
p.Server.EquippedCosmetics.Instances.Unified.Slots = p.CosmeticPresets[profileName]
p.SetStale()
}

func (p *GameProfileData) deleteCosmeticPreset(profileName string) {
delete(p.CosmeticPresets, profileName)
p.SetStale()
}
143 changes: 141 additions & 2 deletions server/evr_runtime_discord_slashcommands.go
Original file line number Diff line number Diff line change
@@ -159,8 +159,9 @@ var (
"7c": "VRML Season 7 Champion",
}

partyGroupIDPattern = regexp.MustCompile("^[a-z0-9]+$")
vrmlIDPattern = regexp.MustCompile("^[-a-zA-Z0-9]{24}$")
partyGroupIDPattern = regexp.MustCompile("^[a-z0-9]+$")
vrmlIDPattern = regexp.MustCompile("^[-a-zA-Z0-9]{24}$")
cosmeticPresetPattern = regexp.MustCompile("^[a-zA-Z0-9-_]+$")

mainSlashCommands = []*discordgo.ApplicationCommand{

@@ -725,6 +726,51 @@ var (
},
},
*/

{
Name: "cosmetic-loadout",
Description: "Manage user-defined cosmetic loadouts.",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionSubCommand,
Name: "manage",
Description: "Manage user-defined cosmetic loadouts.",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionString,
Name: "action",
Description: "Action to perform on the specified loadout.",
Required: true,
Choices: []*discordgo.ApplicationCommandOptionChoice{
{
Name: "Save Loadout",
Value: "save",
},
{
Name: "Apply Loadout",
Value: "load",
},
{
Name: "Delete Loadout",
Value: "delete",
},
},
},
{
Type: discordgo.ApplicationCommandOptionString,
Name: "name",
Description: "Name of the loadout.",
Required: true,
},
},
},
{
Type: discordgo.ApplicationCommandOptionSubCommand,
Name: "list",
Description: "List all of user's cosmetic loadouts.",
},
},
},
}
)

@@ -2301,6 +2347,99 @@ func (d *DiscordAppBot) RegisterSlashCommands() error {
}
return discordgo.ErrNilState
},
"cosmetic-loadout": func(logger runtime.Logger, s *discordgo.Session, i *discordgo.InteractionCreate, user *discordgo.User, member *discordgo.Member, userID string, groupID string) error {
if user == nil {
return nil
}

options := i.ApplicationCommandData().Options

if len(options) == 0 {
return nil
}

profile, err := d.profileRegistry.Load(ctx, uuid.FromStringOrNil(userID))
if err != nil {
return err
}

switch options[0].Name {
case "manage":
profileName := options[0].Options[1].StringValue()
if len(profileName) < 3 || len(profileName) > 32 {
simpleInteractionResponse(s, i, "Invalid profile name. It must be between three (3) and thirty two (32) characters long.")
return nil
}
if !cosmeticPresetPattern.MatchString(profileName) {
simpleInteractionResponse(s, i, "Invalid profile name. It must contain only characters a-z, A-Z, 0-9, underscores, and hyphens.")
return nil
}

switch options[0].Options[0].StringValue() {
case "save":
// limit set arbitrarily
if len(profile.CosmeticPresets) >= 5 {
simpleInteractionResponse(s, i, "Cannot save more than 5 loadouts.")
return nil
}

profile.saveCosmeticPreset(profileName)

if err := d.profileRegistry.SaveAndCache(ctx, uuid.FromStringOrNil(userID), profile); err != nil {
return err
}

simpleInteractionResponse(s, i, fmt.Sprintf("Saved current loadout to profile `%s`", profileName))
return nil

case "load":
if _, ok := profile.CosmeticPresets[profileName]; !ok {
simpleInteractionResponse(s, i, fmt.Sprintf("Profile `%s` does not exist.", profileName))
return nil
}

profile.loadCosmeticPreset(profileName)

if err := d.profileRegistry.SaveAndCache(ctx, uuid.FromStringOrNil(userID), profile); err != nil {
return err
}

simpleInteractionResponse(s, i, fmt.Sprintf("Applied loadout from profile `%s`. Please relog for changes to take effect.", profileName))
return nil

case "delete":
if _, ok := profile.CosmeticPresets[profileName]; !ok {
simpleInteractionResponse(s, i, fmt.Sprintf("Profile `%s` does not exist.", profileName))
return nil
}

profile.deleteCosmeticPreset(profileName)

if err := d.profileRegistry.SaveAndCache(ctx, uuid.FromStringOrNil(userID), profile); err != nil {
return err
}

simpleInteractionResponse(s, i, fmt.Sprintf("Deleted loadout profile `%s`", profileName))
return nil
}

case "list":
if len(profile.CosmeticPresets) == 0 {
simpleInteractionResponse(s, i, "No saved profiles.")
return nil
}

responseString := "Available profiles: "

for k := range profile.CosmeticPresets {
responseString += fmt.Sprintf("`%s`, ", k)
}
responseString = responseString[:len(responseString)-2]
simpleInteractionResponse(s, i, responseString)
return nil
}
return discordgo.ErrNilState
},
}

dg.AddHandler(func(s *discordgo.Session, i *discordgo.InteractionCreate) {