mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-21 23:22:34 +01:00
feat(channelserver): add daily noon resets for gacha stepup and guild RP
Gacha stepup progress now resets when queried after the most recent noon boundary, using a new created_at column on gacha_stepup. Guild member rp_today rolls into rp_yesterday lazily when members are enumerated after noon, using a new rp_reset_at column on guilds. Both follow the established lazy-reset pattern from the cafe handler.
This commit is contained in:
6
schemas/patch-schema/30-daily-resets.sql
Normal file
6
schemas/patch-schema/30-daily-resets.sql
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
BEGIN;
|
||||||
|
ALTER TABLE IF EXISTS public.gacha_stepup
|
||||||
|
ADD COLUMN IF NOT EXISTS created_at TIMESTAMP WITH TIME ZONE DEFAULT now();
|
||||||
|
ALTER TABLE IF EXISTS public.guilds
|
||||||
|
ADD COLUMN IF NOT EXISTS rp_reset_at TIMESTAMP WITH TIME ZONE;
|
||||||
|
END;
|
||||||
@@ -56,6 +56,7 @@ type Guild struct {
|
|||||||
Souls uint32 `db:"souls"`
|
Souls uint32 `db:"souls"`
|
||||||
AllianceID uint32 `db:"alliance_id"`
|
AllianceID uint32 `db:"alliance_id"`
|
||||||
Icon *GuildIcon `db:"icon"`
|
Icon *GuildIcon `db:"icon"`
|
||||||
|
RPResetAt time.Time `db:"rp_reset_at"`
|
||||||
|
|
||||||
GuildLeader
|
GuildLeader
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
package channelserver
|
package channelserver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
"erupe-ce/network/mhfpacket"
|
"erupe-ce/network/mhfpacket"
|
||||||
"math/rand"
|
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
@@ -306,8 +310,25 @@ func handleMsgMhfPlayStepupGacha(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
|
|
||||||
func handleMsgMhfGetStepupStatus(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfGetStepupStatus(s *Session, p mhfpacket.MHFPacket) {
|
||||||
pkt := p.(*mhfpacket.MsgMhfGetStepupStatus)
|
pkt := p.(*mhfpacket.MsgMhfGetStepupStatus)
|
||||||
// TODO: Reset daily (noon)
|
|
||||||
step, _ := s.server.gachaRepo.GetStepupStep(pkt.GachaID, s.charID)
|
// Compute the most recent noon boundary
|
||||||
|
midday := TimeMidnight().Add(12 * time.Hour)
|
||||||
|
if TimeAdjusted().Before(midday) {
|
||||||
|
midday = midday.Add(-24 * time.Hour)
|
||||||
|
}
|
||||||
|
|
||||||
|
step, createdAt, err := s.server.gachaRepo.GetStepupWithTime(pkt.GachaID, s.charID)
|
||||||
|
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||||
|
s.logger.Error("Failed to get gacha stepup state", zap.Error(err))
|
||||||
|
}
|
||||||
|
// Reset stale stepup progress (created before the most recent noon)
|
||||||
|
if err == nil && createdAt.Before(midday) {
|
||||||
|
if err := s.server.gachaRepo.DeleteStepup(pkt.GachaID, s.charID); err != nil {
|
||||||
|
s.logger.Error("Failed to reset stale gacha stepup", zap.Error(err))
|
||||||
|
}
|
||||||
|
step = 0
|
||||||
|
}
|
||||||
|
|
||||||
hasEntry, _ := s.server.gachaRepo.HasEntryType(pkt.GachaID, step)
|
hasEntry, _ := s.server.gachaRepo.HasEntryType(pkt.GachaID, step)
|
||||||
if !hasEntry {
|
if !hasEntry {
|
||||||
if err := s.server.gachaRepo.DeleteStepup(pkt.GachaID, s.charID); err != nil {
|
if err := s.server.gachaRepo.DeleteStepup(pkt.GachaID, s.charID); err != nil {
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
package channelserver
|
package channelserver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sort"
|
||||||
|
"time"
|
||||||
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
"erupe-ce/common/mhfitem"
|
"erupe-ce/common/mhfitem"
|
||||||
_config "erupe-ce/config"
|
_config "erupe-ce/config"
|
||||||
"sort"
|
|
||||||
|
|
||||||
ps "erupe-ce/common/pascalstring"
|
ps "erupe-ce/common/pascalstring"
|
||||||
"erupe-ce/network/mhfpacket"
|
"erupe-ce/network/mhfpacket"
|
||||||
@@ -105,6 +107,17 @@ func handleMsgMhfEnumerateGuildMember(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lazy daily RP rollover: move rp_today → rp_yesterday at noon
|
||||||
|
midday := TimeMidnight().Add(12 * time.Hour)
|
||||||
|
if TimeAdjusted().Before(midday) {
|
||||||
|
midday = midday.Add(-24 * time.Hour)
|
||||||
|
}
|
||||||
|
if guild.RPResetAt.Before(midday) {
|
||||||
|
if err := s.server.guildRepo.RolloverDailyRP(guild.ID, midday); err != nil {
|
||||||
|
s.logger.Error("Failed to rollover guild daily RP", zap.Error(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
guildMembers, err := s.server.guildRepo.GetMembers(guild.ID, false)
|
guildMembers, err := s.server.guildRepo.GetMembers(guild.ID, false)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
package channelserver
|
package channelserver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -96,6 +100,21 @@ func (r *GachaRepository) GetStepupStep(gachaID uint32, charID uint32) (uint8, e
|
|||||||
return step, err
|
return step, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetStepupWithTime returns the current step and creation time for a stepup entry.
|
||||||
|
// Returns sql.ErrNoRows if no entry exists.
|
||||||
|
func (r *GachaRepository) GetStepupWithTime(gachaID uint32, charID uint32) (uint8, time.Time, error) {
|
||||||
|
var step uint8
|
||||||
|
var createdAt time.Time
|
||||||
|
err := r.db.QueryRow(
|
||||||
|
`SELECT step, COALESCE(created_at, '2000-01-01'::timestamptz) FROM gacha_stepup WHERE gacha_id = $1 AND character_id = $2`,
|
||||||
|
gachaID, charID,
|
||||||
|
).Scan(&step, &createdAt)
|
||||||
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return 0, time.Time{}, err
|
||||||
|
}
|
||||||
|
return step, createdAt, err
|
||||||
|
}
|
||||||
|
|
||||||
// HasEntryType returns whether a gacha has any entries of the given type.
|
// HasEntryType returns whether a gacha has any entries of the given type.
|
||||||
func (r *GachaRepository) HasEntryType(gachaID uint32, entryType uint8) (bool, error) {
|
func (r *GachaRepository) HasEntryType(gachaID uint32, entryType uint8) (bool, error) {
|
||||||
var count int
|
var count int
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ SELECT
|
|||||||
ga.sub2_id = g.id
|
ga.sub2_id = g.id
|
||||||
), 0) AS alliance_id,
|
), 0) AS alliance_id,
|
||||||
icon,
|
icon,
|
||||||
|
COALESCE(rp_reset_at, '2000-01-01'::timestamptz) AS rp_reset_at,
|
||||||
(SELECT count(1) FROM guild_characters gc WHERE gc.guild_id = g.id) AS member_count
|
(SELECT count(1) FROM guild_characters gc WHERE gc.guild_id = g.id) AS member_count
|
||||||
FROM guilds g
|
FROM guilds g
|
||||||
JOIN guild_characters gc ON gc.character_id = leader_id
|
JOIN guild_characters gc ON gc.character_id = leader_id
|
||||||
@@ -939,6 +940,30 @@ func (r *GuildRepository) ListInvitedCharacters(guildID uint32) ([]*ScoutedChara
|
|||||||
return chars, nil
|
return chars, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RolloverDailyRP moves rp_today into rp_yesterday for all members of a guild,
|
||||||
|
// then updates the guild's rp_reset_at timestamp.
|
||||||
|
func (r *GuildRepository) RolloverDailyRP(guildID uint32, noon time.Time) error {
|
||||||
|
tx, err := r.db.Begin()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := tx.Exec(
|
||||||
|
`UPDATE guild_characters SET rp_yesterday = rp_today, rp_today = 0 WHERE guild_id = $1`,
|
||||||
|
guildID,
|
||||||
|
); err != nil {
|
||||||
|
_ = tx.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := tx.Exec(
|
||||||
|
`UPDATE guilds SET rp_reset_at = $1 WHERE id = $2`,
|
||||||
|
noon, guildID,
|
||||||
|
); err != nil {
|
||||||
|
_ = tx.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return tx.Commit()
|
||||||
|
}
|
||||||
|
|
||||||
// AddWeeklyBonusUsers atomically adds numUsers to the guild's weekly bonus exceptional user count.
|
// AddWeeklyBonusUsers atomically adds numUsers to the guild's weekly bonus exceptional user count.
|
||||||
func (r *GuildRepository) AddWeeklyBonusUsers(guildID uint32, numUsers uint8) error {
|
func (r *GuildRepository) AddWeeklyBonusUsers(guildID uint32, numUsers uint8) error {
|
||||||
_, err := r.db.Exec(
|
_, err := r.db.Exec(
|
||||||
|
|||||||
Reference in New Issue
Block a user