Skip to content

Commit

Permalink
Use common avatar cache. Add shared callback struct.
Browse files Browse the repository at this point in the history
  • Loading branch information
leighmacdonald committed Feb 28, 2023
1 parent 948adf7 commit 892c543
Show file tree
Hide file tree
Showing 11 changed files with 180 additions and 173 deletions.
9 changes: 1 addition & 8 deletions application.go
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,7 @@ func (bd *BD) gameStateTracker(ctx context.Context) {
log.Printf("Failed to download avatar [%s]: %v\n", p.AvatarHash, errDownload)
continue
}
p.SetAvatar(p.AvatarHash, avatar)
bd.gui.SetAvatar(sid64, avatar)
queueUpdate = true
case update := <-bd.gameStateUpdate:
var sourcePlayer *model.Player
Expand Down Expand Up @@ -758,13 +758,6 @@ func (bd *BD) onUpdateMark(status updateMarkEvent) error {
// TODO Use channels for communicating instead
func (bd *BD) AttachGui(gui ui.UserInterface) {
gui.SetBuildInfo(version, commit, date, builtBy)
gui.SetOnLaunchTF2(func() {
go bd.launchGameAndWait()
})
gui.SetOnKick(func(ctx context.Context, userId int64, reason model.KickReason) error {
return bd.callVote(ctx, userId, reason)
})

gui.UpdateAttributes(bd.rules.UniqueTags())
bd.gui = gui
}
Expand Down
2 changes: 2 additions & 0 deletions model/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ const (
EvtLobby
)

type SteamIDFunc func(sid64 steamid.SID64)

type MarkFunc func(sid64 steamid.SID64, attrs []string) error

type KickReason string
Expand Down
15 changes: 0 additions & 15 deletions model/player.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ package model

import (
"fmt"
"fyne.io/fyne/v2"
"github.com/leighmacdonald/bd/pkg/rules"
"github.com/leighmacdonald/steamid/v2/steamid"
"log"
"time"
)

Expand Down Expand Up @@ -53,7 +51,6 @@ type Player struct {
AccountCreatedOn time.Time

Visibility ProfileVisibility
Avatar fyne.Resource // TODO store somewhere else so we dont couple ui item to the model
AvatarHash string

// PlayerBanState
Expand Down Expand Up @@ -150,17 +147,6 @@ func AvatarUrl(hash string) string {
return fmt.Sprintf("%s/%s/%s_full.jpg", baseAvatarUrl, firstN(avatarHash, 2), avatarHash)
}

func (ps *Player) SetAvatar(hash string, buf []byte) {
res := fyne.NewStaticResource(fmt.Sprintf("%s.jpg", hash), buf)
if res == nil {
log.Printf("Failed to load avatar\n")
return
} else {
ps.Avatar = res
ps.AvatarHash = rules.HashBytes(buf)
}
}

type PlayerCollection []*Player

func (players PlayerCollection) AsAny() []any {
Expand All @@ -178,7 +164,6 @@ func NewPlayer(sid64 steamid.SID64, name string) *Player {
RealName: "",
NamePrevious: "",
AccountCreatedOn: time.Time{},
Avatar: nil,
AvatarHash: "",
CommunityBanned: false,
Visibility: ProfileVisibilityPublic,
Expand Down
5 changes: 4 additions & 1 deletion pkg/rules/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func (e *Engine) Mark(opts MarkOpts) error {
Time: int(time.Now().Unix()),
PlayerName: opts.Name,
},
SteamID: opts.SteamID,
SteamID: opts.SteamID.String(),
Proof: opts.Proof,
})
e.Unlock()
Expand Down Expand Up @@ -167,6 +167,7 @@ func (e *Engine) ImportRules(list *RuleSchema) error {
// ImportPlayers loads the provided player list for matching
func (e *Engine) ImportPlayers(list *PlayerListSchema) error {
var playerAttrs []string
var count int
for _, player := range list.Players {
var steamID steamid.SID64
// Some entries can be raw number types in addition to strings...
Expand All @@ -187,6 +188,7 @@ func (e *Engine) ImportPlayers(list *PlayerListSchema) error {
}
e.registerSteamIDMatcher(newSteamIDMatcher(list.FileInfo.Title, steamID))
playerAttrs = append(playerAttrs, player.Attributes...)
count++
}
e.Lock()
for _, newTag := range playerAttrs {
Expand All @@ -203,6 +205,7 @@ func (e *Engine) ImportPlayers(list *PlayerListSchema) error {
}
e.playerLists = append(e.playerLists, list)
e.Unlock()
log.Printf("[%s] Loaded %d players\n", list.FileInfo.Title, count)
return nil
}

Expand Down
31 changes: 31 additions & 0 deletions ui/avatar.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package ui

import (
"fyne.io/fyne/v2"
"github.com/leighmacdonald/steamid/v2/steamid"
"sync"
)

type avatarCache struct {
*sync.RWMutex
userAvatar map[steamid.SID64]fyne.Resource
}

func (cache *avatarCache) SetAvatar(sid64 steamid.SID64, data []byte) {
if !sid64.Valid() || data == nil {
return
}
cache.Lock()
cache.userAvatar[sid64] = fyne.NewStaticResource(sid64.String(), data)
cache.Unlock()
}

func (cache *avatarCache) GetAvatar(sid64 steamid.SID64) fyne.Resource {
cache.RLock()
defer cache.RUnlock()
av, found := cache.userAvatar[sid64]
if found {
return av
}
return resourceDefaultavatarJpg
}
62 changes: 34 additions & 28 deletions ui/chat_game.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,43 +11,50 @@ import (
"fyne.io/fyne/v2/widget"
"github.com/leighmacdonald/bd/model"
"github.com/leighmacdonald/bd/translations"
"github.com/leighmacdonald/steamid/v2/steamid"
"github.com/pkg/errors"
"log"
"sync"
"time"
)

type gameChatWindow struct {
window fyne.Window
ctx context.Context
app fyne.App
window fyne.Window
list *widget.List
boundList binding.UntypedList
objectMu sync.RWMutex
boundListMu sync.RWMutex
objectMu *sync.RWMutex
boundListMu *sync.RWMutex
messageCount binding.Int
autoScrollEnabled binding.Bool
avatarCache *avatarCache
cb callBacks
}

func newGameChatWindow(ctx context.Context, app fyne.App, kickFunc model.KickFunc, attrs binding.StringList, markFunc model.MarkFunc,
settings *model.Settings, createUserChat func(sid64 steamid.SID64), createNameHistory func(sid64 steamid.SID64)) *gameChatWindow {
chatWindow := app.NewWindow(translations.One(translations.WindowChatHistoryGame))
chatWindow.Canvas().AddShortcut(
func newGameChatWindow(ctx context.Context, app fyne.App, cb callBacks, attrs binding.StringList, settings *model.Settings, cache *avatarCache) *gameChatWindow {
window := app.NewWindow(translations.One(translations.WindowChatHistoryGame))
window.Canvas().AddShortcut(
&desktop.CustomShortcut{KeyName: fyne.KeyW, Modifier: fyne.KeyModifierControl},
func(shortcut fyne.Shortcut) {
chatWindow.Hide()
window.Hide()
})

window := gameChatWindow{
window.SetCloseIntercept(func() {
window.Hide()
})
gcw := gameChatWindow{
window: window,
ctx: ctx,
app: app,
window: chatWindow,
boundList: binding.BindUntypedList(&[]interface{}{}),
autoScrollEnabled: binding.NewBool(),
messageCount: binding.NewInt(),
boundListMu: &sync.RWMutex{},
objectMu: &sync.RWMutex{},
avatarCache: cache,
cb: cb,
}
if errSet := window.autoScrollEnabled.Set(true); errSet != nil {

if errSet := gcw.autoScrollEnabled.Set(true); errSet != nil {
log.Printf("Failed to set default autoscroll: %v\n", errSet)
}

Expand All @@ -67,7 +74,7 @@ func newGameChatWindow(ctx context.Context, app fyne.App, kickFunc model.KickFun
return
}
um := obj.(model.UserMessage)
window.objectMu.Lock()
gcw.objectMu.Lock()
rootContainer := o.(*fyne.Container)
timeAndProfileContainer := rootContainer.Objects[1].(*fyne.Container)
timeStamp := timeAndProfileContainer.Objects[0].(*widget.Label)
Expand All @@ -76,9 +83,9 @@ func newGameChatWindow(ctx context.Context, app fyne.App, kickFunc model.KickFun

timeStamp.SetText(um.Created.Format(time.Kitchen))
profileButton.SetText(um.Player)
profileButton.menu = generateUserMenu(window.ctx, app, window.window, um.PlayerSID, um.UserId,
kickFunc, attrs, markFunc, settings.Links, createUserChat, createNameHistory)
profileButton.menu.Refresh()
profileButton.SetIcon(gcw.avatarCache.GetAvatar(um.PlayerSID))
profileButton.menu = generateUserMenu(gcw.ctx, app, gcw.window, um.PlayerSID, um.UserId, cb, attrs, settings.Links)
//profileButton.menu.Refresh()
profileButton.Refresh()
nameStyle := widget.RichTextStyleInline
if um.Team == model.Red {
Expand All @@ -92,32 +99,31 @@ func newGameChatWindow(ctx context.Context, app fyne.App, kickFunc model.KickFun
}
messageRichText.Refresh()

window.objectMu.Unlock()
gcw.objectMu.Unlock()
}
window.list = widget.NewListWithData(window.boundList, createFunc, updateFunc)
window.window.SetContent(container.NewBorder(
gcw.list = widget.NewListWithData(gcw.boundList, createFunc, updateFunc)
gcw.window.SetContent(container.NewBorder(
container.NewBorder(
nil,
nil,
container.NewHBox(
widget.NewCheckWithData(translations.One(translations.LabelAutoScroll), window.autoScrollEnabled),
widget.NewButtonWithIcon(translations.One(translations.LabelBottom), theme.MoveDownIcon(), window.list.ScrollToBottom),
widget.NewCheckWithData(translations.One(translations.LabelAutoScroll), gcw.autoScrollEnabled),
widget.NewButtonWithIcon(translations.One(translations.LabelBottom), theme.MoveDownIcon(), gcw.list.ScrollToBottom),
widget.NewButtonWithIcon(translations.One(translations.LabelClear), theme.ContentClearIcon(), func() {
if errReload := window.boundList.Set(nil); errReload != nil {
if errReload := gcw.boundList.Set(nil); errReload != nil {
log.Printf("Failed to clear chat: %v\n", errReload)
}
}),
),
widget.NewLabelWithData(binding.IntToStringWithFormat(window.messageCount, fmt.Sprintf("%s%%d", translations.One(translations.LabelMessageCount)))),
widget.NewLabelWithData(binding.IntToStringWithFormat(gcw.messageCount, fmt.Sprintf("%s%%d", translations.One(translations.LabelMessageCount)))),
widget.NewLabel(""),
),
nil,
nil,
nil,
container.NewVScroll(window.list)))
chatWindow.Resize(fyne.NewSize(1000, 500))
window.window.Content().Refresh()
return &window
container.NewVScroll(gcw.list)))
gcw.window.Resize(fyne.NewSize(1000, 500))
return &gcw
}

func (gcw *gameChatWindow) append(msg any) error {
Expand Down
7 changes: 4 additions & 3 deletions ui/chat_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ func newUserChatWindow(ctx context.Context, app fyne.App, queryFunc model.QueryU
1, map[string]interface{}{
"SteamId": sid64,
}))

appWindow.SetCloseIntercept(func() {
appWindow.Hide()
})
window := userChatWindow{
Window: appWindow,
app: app,
Expand Down Expand Up @@ -105,7 +107,7 @@ func newUserChatWindow(ctx context.Context, app fyne.App, queryFunc model.QueryU
Team: 0,
Player: "Bot Detector",
PlayerSID: 0,
UserId: 69,
UserId: -1,
Message: "No messages",
Created: time.Now(),
Dead: false,
Expand All @@ -116,6 +118,5 @@ func newUserChatWindow(ctx context.Context, app fyne.App, queryFunc model.QueryU
log.Printf("Failed to set messages: %v\n", errSet)
}
window.Resize(fyne.NewSize(600, 600))
window.Show()
return &window
}
13 changes: 6 additions & 7 deletions ui/menu.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,17 +176,16 @@ func generateKickMenu(ctx context.Context, userId int64, kickFunc model.KickFunc
)
}

func generateUserMenu(ctx context.Context, app fyne.App, window fyne.Window, steamId steamid.SID64, userId int64, kickFunc model.KickFunc,
knownAttributes binding.StringList, markFunc model.MarkFunc, links []model.LinkConfig,
createUserChat func(sid64 steamid.SID64), createNameHistory func(sid64 steamid.SID64)) *fyne.Menu {
func generateUserMenu(ctx context.Context, app fyne.App, window fyne.Window, steamId steamid.SID64, userId int64, cb callBacks,
knownAttributes binding.StringList, links []model.LinkConfig) *fyne.Menu {
menu := fyne.NewMenu("User Actions",
&fyne.MenuItem{
Icon: theme.CheckButtonCheckedIcon(),
ChildMenu: generateKickMenu(ctx, userId, kickFunc),
ChildMenu: generateKickMenu(ctx, userId, cb.kickFunc),
Label: translations.One(translations.MenuCallVote)},
&fyne.MenuItem{
Icon: theme.ZoomFitIcon(),
ChildMenu: generateAttributeMenu(window, steamId, knownAttributes, markFunc),
ChildMenu: generateAttributeMenu(window, steamId, knownAttributes, cb.markFn),
Label: translations.One(translations.MenuMarkAs)},
&fyne.MenuItem{
Icon: theme.SearchIcon(),
Expand All @@ -199,13 +198,13 @@ func generateUserMenu(ctx context.Context, app fyne.App, window fyne.Window, ste
&fyne.MenuItem{
Icon: theme.ListIcon(),
Action: func() {
createUserChat(steamId)
cb.createUserChat(steamId)
},
Label: translations.One(translations.MenuChatHistory)},
&fyne.MenuItem{
Icon: theme.VisibilityIcon(),
Action: func() {
createNameHistory(steamId)
cb.createNameHistory(steamId)
},
Label: translations.One(translations.MenuNameHistory)},
)
Expand Down
Loading

0 comments on commit 892c543

Please sign in to comment.