Skip to content

Commit

Permalink
feat(): Add a delay for exit game and do not exit from the menu core …
Browse files Browse the repository at this point in the history
…- untested yet - (#43)

* code

* now compiles

* TAPTUI: Add menu times for new settings

* changed strategy

* more changes

* forgot to push

---------

Co-authored-by: sigboe <[email protected]>
  • Loading branch information
asturur and sigboe authored Apr 11, 2024
1 parent d8240c0 commit 7a93aee
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 16 deletions.
15 changes: 15 additions & 0 deletions docs/mister.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,21 @@ With this configuration, removing a token will not exit the game when using the

The core name is the same as the name that shows on the left sidebar of the OSD when in a core.

### Exit Game Delay

| Key | Default Value |
|-----------------------|---------------|
| `exit_game_delay` | 0 |

A number, in seconds, that TapTo will wait between the removal of the card and reloading the menu core. Requires `exit_game` set to yes. This parameter is useful if you want to swap games without reloading the menu core.
If a new card is tapped before the menu core is loaded, the command on the card will be executed immediately and the menu core loading will be cancelled.

```ini
[tapto]
exit_game=yes
exit_game_delay=6
```

## Mappings Database

TapTo supports an `nfc.csv` file in the top of the SD card. This file can be used to override the text read from a tag and map it to a different text value. This is useful for mapping Amiibos which are read-only, testing text values before actually writing them, and is necessary for using the `command` custom command by default.
Expand Down
7 changes: 7 additions & 0 deletions pkg/config/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ type TapToConfig struct {
ProbeDevice bool `ini:"probe_device,omitempty"`
ExitGame bool `ini:"exit_game,omitempty"`
ExitGameBlocklist []string `ini:"exit_game_blocklist,omitempty"`
ExitGameDelay int8 `ini:"exit_game_delay"`
Debug bool `ini:"debug,omitempty"`
}

Expand Down Expand Up @@ -122,6 +123,12 @@ func (c *UserConfig) GetExitGameBlocklist() []string {
return c.TapTo.ExitGameBlocklist
}

func (c *UserConfig) GetExitGameDelay() int8 {
c.mu.RLock()
defer c.mu.RUnlock()
return c.TapTo.ExitGameDelay
}

func (c *UserConfig) SetExitGameBlocklist(exitGameBlocklist []string) {
c.mu.Lock()
defer c.mu.Unlock()
Expand Down
52 changes: 46 additions & 6 deletions pkg/daemon/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/clausecker/nfc/v2"
"github.com/rs/zerolog/log"
mrextConfig "github.com/wizzomafizzo/mrext/pkg/config"
"github.com/wizzomafizzo/mrext/pkg/input"
"github.com/wizzomafizzo/tapto/pkg/config"
"github.com/wizzomafizzo/tapto/pkg/daemon/state"
Expand Down Expand Up @@ -163,15 +164,27 @@ func OpenDeviceWithRetries(cfg *config.UserConfig, st *state.State, quiet bool)
}

func shouldExit(
removed bool,
candidateForRemove bool,
cfg *config.UserConfig,
st *state.State,
) bool {
if !removed || st.GetLastScanned().FromApi || st.IsLauncherDisabled() {
// do not exit from menu, there is nowhere to go anyway
if mister.GetActiveCoreName() == mrextConfig.MenuCore {
return false
}

if cfg.GetExitGame() && !inExitGameBlocklist(cfg) {
// candidateForRemove is true from the moment in which we remove a card
if !candidateForRemove || st.GetLastScanned().FromApi || st.IsLauncherDisabled() {
return false
}

var hasTimePassed bool = false
var removalTime = st.GetCardRemovalTime()
if !removalTime.IsZero() {
hasTimePassed = int8(time.Since(removalTime).Seconds()) >= cfg.GetExitGameDelay()
}

if hasTimePassed && cfg.GetExitGame() && !inExitGameBlocklist(cfg) {
return true
} else {
return false
Expand All @@ -189,8 +202,9 @@ func readerPollLoop(

ttp := TimesToPoll
pbp := PeriodBetweenPolls

var lastError time.Time
var candidateForRemove bool
var currentlyLoadedCard state.Token
playFail := func() {
if time.Since(lastError) > 1*time.Second {
mister.PlayFail(cfg)
Expand Down Expand Up @@ -237,6 +251,8 @@ func readerPollLoop(
log.Info().Msgf("opened connection: %s %s", pnd, pnd.Connection())
}

// activeCard is the card that sat on the scanner at the previous poll loop.
// is not the card representing the current loaded core
activeCard := st.GetActiveCard()
writeRequest := st.GetWriteRequest()

Expand Down Expand Up @@ -301,6 +317,18 @@ func readerPollLoop(

newScanned, removed, err := pollDevice(cfg, &pnd, activeCard, ttp, pbp)

// if we removed but we weren't removing already, start the remove countdown
if removed && candidateForRemove == false {
st.SetCardRemovalTime(time.Now())
candidateForRemove = true
// if we were removing but we put back the card we had before
// then we are ok blocking the exit process
} else if candidateForRemove && (newScanned.UID == currentlyLoadedCard.UID) {
log.Info().Msgf("Card was removed but inserted back")
st.SetCardRemovalTime(time.Time{})
candidateForRemove = false
}

if errors.Is(err, nfc.Error(nfc.EIO)) {
st.SetReaderDisconnected()
log.Error().Msgf("error during poll: %s", err)
Expand All @@ -317,21 +345,33 @@ func readerPollLoop(

st.SetActiveCard(newScanned)

if shouldExit(removed, cfg, st) {
if shouldExit(candidateForRemove, cfg, st) {
candidateForRemove = false
st.SetCardRemovalTime(time.Time{})
mister.ExitGame()
currentlyLoadedCard = state.Token{}
continue
}

if newScanned.UID == "" || activeCard.UID == newScanned.UID {
// if there is no card (newScanned.UID == "")
// if the card is the same as the one we have scanned before ( activeCard.UID == newScanned.UID)
// if the card has no text a real card but empty (newScanned.Text == "")
// if the card is the same that has been loaded last time (newScanned.UID == currentlyLoadedCard.UID)
if newScanned.UID == "" || activeCard.UID == newScanned.UID || newScanned.Text == "" || newScanned.UID == currentlyLoadedCard.UID {
continue
}

// should we play success if launcher is disabled?
mister.PlaySuccess(cfg)

if st.IsLauncherDisabled() {
continue
}

// we are about to change card, so we also stop the exit process
st.SetCardRemovalTime(time.Time{})
candidateForRemove = false
currentlyLoadedCard = newScanned
tq.Enqueue(newScanned)
}

Expand Down
13 changes: 13 additions & 0 deletions pkg/daemon/state/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type State struct {
dbLoadTime time.Time
uidMap map[string]string
textMap map[string]string
cardRemovalTime time.Time
}

func (s *State) SetUpdateHook(hook *func(st *State)) {
Expand Down Expand Up @@ -65,6 +66,12 @@ func (s *State) SetActiveCard(card Token) {
}
}

func (s *State) SetCardRemovalTime(removalTime time.Time) {
s.mu.Lock()
defer s.mu.Unlock()
s.cardRemovalTime = removalTime
}

func (s *State) GetActiveCard() Token {
s.mu.RLock()
defer s.mu.RUnlock()
Expand All @@ -77,6 +84,12 @@ func (s *State) GetLastScanned() Token {
return s.lastScanned
}

func (s *State) GetCardRemovalTime() time.Time {
s.mu.RLock()
defer s.mu.RUnlock()
return s.cardRemovalTime
}

func (s *State) StopService() {
s.mu.Lock()
s.stopService = true
Expand Down
26 changes: 16 additions & 10 deletions scripts/taptui/taptui.sh
Original file line number Diff line number Diff line change
Expand Up @@ -783,22 +783,28 @@ _EOF_
_Settings() {
local menuOptions selected
menuOptions=(
"Service" "Start/stop the TapTo service"
"Commands" "Toggles the ability to run Linux commands from NFC tags"
"Sounds" "Toggles sounds played when a tag is scanned"
"Connection" "Hardware configuration for certain NFC readers"
"Probe" "Auto detection of a serial based reader device"
"Service" "Start/stop the TapTo service"
"Commands" "Toggles the ability to run Linux commands from NFC tags"
"Sounds" "Toggles sounds played when a tag is scanned"
"Connection" "Hardware configuration for certain NFC readers"
"Probe" "Auto detection of a serial based reader device"
"Exit Game" "Exit Game When Token Is Removed"
"Exit Blocklist" "Exit Game Core Blocklist"
"Exit Delay" "Exit Game Delay"
)

while true; do
selected="$(_menu --cancel-label "Back" -- "${menuOptions[@]}")"
exitcode="${?}"; [[ "${exitcode}" -ge 1 ]] && return "${exitcode}"
case "${selected}" in
Service) _serviceSetting ;;
Commands) _commandSetting ;;
Sounds) _soundSetting ;;
Connection) _connectionSetting ;;
Probe) _probeSetting ;;
"Service") _serviceSetting ;;
"Commands") _commandSetting ;;
"Sounds") _soundSetting ;;
"Connection") _connectionSetting ;;
"Probe") _probeSetting ;;
"Exit Game") _exitGameSetting ;;
"Exit Blocklist") _exitGameBlocklistSetting ;;
"Exit Delay") _exitGameDelaySetting ;;
esac
done
}
Expand Down

0 comments on commit 7a93aee

Please sign in to comment.