mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-22 23:54:33 +01:00
The tower repo had business logic beyond simple CRUD: AddGem used a fetch-transform-save pattern, progress capping was inline in the handler, and RP donation orchestrated multiple repo calls with conditional page advancement. Move these into a new TowerService following the established service layer pattern.
336 lines
16 KiB
Go
336 lines
16 KiB
Go
package channelserver
|
|
|
|
import (
|
|
"time"
|
|
)
|
|
|
|
// Repository interfaces decouple handlers from concrete PostgreSQL implementations,
|
|
// enabling mock/stub injection for unit tests and alternative storage backends.
|
|
|
|
// CharacterRepo defines the contract for character data access.
|
|
type CharacterRepo interface {
|
|
LoadColumn(charID uint32, column string) ([]byte, error)
|
|
SaveColumn(charID uint32, column string, data []byte) error
|
|
ReadInt(charID uint32, column string) (int, error)
|
|
AdjustInt(charID uint32, column string, delta int) (int, error)
|
|
GetName(charID uint32) (string, error)
|
|
GetUserID(charID uint32) (uint32, error)
|
|
UpdateLastLogin(charID uint32, timestamp int64) error
|
|
UpdateTimePlayed(charID uint32, timePlayed int) error
|
|
GetCharIDsByUserID(userID uint32) ([]uint32, error)
|
|
ReadTime(charID uint32, column string, defaultVal time.Time) (time.Time, error)
|
|
SaveTime(charID uint32, column string, value time.Time) error
|
|
SaveInt(charID uint32, column string, value int) error
|
|
SaveBool(charID uint32, column string, value bool) error
|
|
SaveString(charID uint32, column string, value string) error
|
|
ReadBool(charID uint32, column string) (bool, error)
|
|
ReadString(charID uint32, column string) (string, error)
|
|
LoadColumnWithDefault(charID uint32, column string, defaultVal []byte) ([]byte, error)
|
|
SetDeleted(charID uint32) error
|
|
UpdateDailyCafe(charID uint32, dailyTime time.Time, bonusQuests, dailyQuests uint32) error
|
|
ResetDailyQuests(charID uint32) error
|
|
ReadEtcPoints(charID uint32) (bonusQuests, dailyQuests, promoPoints uint32, err error)
|
|
ResetCafeTime(charID uint32, cafeReset time.Time) error
|
|
UpdateGuildPostChecked(charID uint32) error
|
|
ReadGuildPostChecked(charID uint32) (time.Time, error)
|
|
SaveMercenary(charID uint32, data []byte, rastaID uint32) error
|
|
UpdateGCPAndPact(charID uint32, gcp uint32, pactID uint32) error
|
|
FindByRastaID(rastaID int) (charID uint32, name string, err error)
|
|
SaveCharacterData(charID uint32, compSave []byte, hr, gr uint16, isFemale bool, weaponType uint8, weaponID uint16) error
|
|
SaveHouseData(charID uint32, houseTier []byte, houseData, bookshelf, gallery, tore, garden []byte) error
|
|
LoadSaveData(charID uint32) (uint32, []byte, bool, string, error)
|
|
}
|
|
|
|
// GuildRepo defines the contract for guild data access.
|
|
type GuildRepo interface {
|
|
GetByID(guildID uint32) (*Guild, error)
|
|
GetByCharID(charID uint32) (*Guild, error)
|
|
ListAll() ([]*Guild, error)
|
|
Create(leaderCharID uint32, guildName string) (int32, error)
|
|
Save(guild *Guild) error
|
|
Disband(guildID uint32) error
|
|
RemoveCharacter(charID uint32) error
|
|
AcceptApplication(guildID, charID uint32) error
|
|
CreateApplication(guildID, charID, actorID uint32, appType GuildApplicationType) error
|
|
CreateApplicationWithMail(guildID, charID, actorID uint32, appType GuildApplicationType, mailSenderID, mailRecipientID uint32, mailSubject, mailBody string) error
|
|
CancelInvitation(guildID, charID uint32) error
|
|
RejectApplication(guildID, charID uint32) error
|
|
ArrangeCharacters(charIDs []uint32) error
|
|
GetApplication(guildID, charID uint32, appType GuildApplicationType) (*GuildApplication, error)
|
|
HasApplication(guildID, charID uint32) (bool, error)
|
|
GetItemBox(guildID uint32) ([]byte, error)
|
|
SaveItemBox(guildID uint32, data []byte) error
|
|
GetMembers(guildID uint32, applicants bool) ([]*GuildMember, error)
|
|
GetCharacterMembership(charID uint32) (*GuildMember, error)
|
|
SaveMember(member *GuildMember) error
|
|
SetRecruiting(guildID uint32, recruiting bool) error
|
|
SetPugiOutfits(guildID uint32, outfits uint32) error
|
|
SetRecruiter(charID uint32, allowed bool) error
|
|
AddMemberDailyRP(charID uint32, amount uint16) error
|
|
ExchangeEventRP(guildID uint32, amount uint16) (uint32, error)
|
|
AddRankRP(guildID uint32, amount uint16) error
|
|
AddEventRP(guildID uint32, amount uint16) error
|
|
GetRoomRP(guildID uint32) (uint16, error)
|
|
SetRoomRP(guildID uint32, rp uint16) error
|
|
AddRoomRP(guildID uint32, amount uint16) error
|
|
SetRoomExpiry(guildID uint32, expiry time.Time) error
|
|
ListPosts(guildID uint32, postType int) ([]*MessageBoardPost, error)
|
|
CreatePost(guildID, authorID, stampID uint32, postType int, title, body string, maxPosts int) error
|
|
DeletePost(postID uint32) error
|
|
UpdatePost(postID uint32, title, body string) error
|
|
UpdatePostStamp(postID, stampID uint32) error
|
|
GetPostLikedBy(postID uint32) (string, error)
|
|
SetPostLikedBy(postID uint32, likedBy string) error
|
|
CountNewPosts(guildID uint32, since time.Time) (int, error)
|
|
GetAllianceByID(allianceID uint32) (*GuildAlliance, error)
|
|
ListAlliances() ([]*GuildAlliance, error)
|
|
CreateAlliance(name string, parentGuildID uint32) error
|
|
DeleteAlliance(allianceID uint32) error
|
|
RemoveGuildFromAlliance(allianceID, guildID, subGuild1ID, subGuild2ID uint32) error
|
|
ListAdventures(guildID uint32) ([]*GuildAdventure, error)
|
|
CreateAdventure(guildID, destination uint32, depart, returnTime int64) error
|
|
CreateAdventureWithCharge(guildID, destination, charge uint32, depart, returnTime int64) error
|
|
CollectAdventure(adventureID uint32, charID uint32) error
|
|
ChargeAdventure(adventureID uint32, amount uint32) error
|
|
GetPendingHunt(charID uint32) (*TreasureHunt, error)
|
|
ListGuildHunts(guildID, charID uint32) ([]*TreasureHunt, error)
|
|
CreateHunt(guildID, hostID, destination, level uint32, huntData []byte, catsUsed string) error
|
|
AcquireHunt(huntID uint32) error
|
|
RegisterHuntReport(huntID, charID uint32) error
|
|
CollectHunt(huntID uint32) error
|
|
ClaimHuntReward(huntID, charID uint32) error
|
|
ListMeals(guildID uint32) ([]*GuildMeal, error)
|
|
CreateMeal(guildID, mealID, level uint32, createdAt time.Time) (uint32, error)
|
|
UpdateMeal(mealID, newMealID, level uint32, createdAt time.Time) error
|
|
ClaimHuntBox(charID uint32, claimedAt time.Time) error
|
|
ListGuildKills(guildID, charID uint32) ([]*GuildKill, error)
|
|
CountGuildKills(guildID, charID uint32) (int, error)
|
|
ClearTreasureHunt(charID uint32) error
|
|
InsertKillLog(charID uint32, monster int, quantity uint8, timestamp time.Time) error
|
|
ListInvitedCharacters(guildID uint32) ([]*ScoutedCharacter, error)
|
|
RolloverDailyRP(guildID uint32, noon time.Time) error
|
|
AddWeeklyBonusUsers(guildID uint32, numUsers uint8) error
|
|
}
|
|
|
|
// UserRepo defines the contract for user account data access.
|
|
type UserRepo interface {
|
|
GetGachaPoints(userID uint32) (fp, premium, trial uint32, err error)
|
|
GetTrialCoins(userID uint32) (uint16, error)
|
|
DeductTrialCoins(userID uint32, amount uint32) error
|
|
DeductPremiumCoins(userID uint32, amount uint32) error
|
|
AddPremiumCoins(userID uint32, amount uint32) error
|
|
AddTrialCoins(userID uint32, amount uint32) error
|
|
DeductFrontierPoints(userID uint32, amount uint32) error
|
|
AddFrontierPoints(userID uint32, amount uint32) error
|
|
AdjustFrontierPointsDeduct(userID uint32, amount int) (uint32, error)
|
|
AdjustFrontierPointsCredit(userID uint32, amount int) (uint32, error)
|
|
AddFrontierPointsFromGacha(userID uint32, gachaID uint32, entryType uint8) error
|
|
GetRights(userID uint32) (uint32, error)
|
|
SetRights(userID uint32, rights uint32) error
|
|
IsOp(userID uint32) (bool, error)
|
|
SetLastCharacter(userID uint32, charID uint32) error
|
|
GetTimer(userID uint32) (bool, error)
|
|
SetTimer(userID uint32, value bool) error
|
|
CountByPSNID(psnID string) (int, error)
|
|
SetPSNID(userID uint32, psnID string) error
|
|
GetDiscordToken(userID uint32) (string, error)
|
|
SetDiscordToken(userID uint32, token string) error
|
|
GetItemBox(userID uint32) ([]byte, error)
|
|
SetItemBox(userID uint32, data []byte) error
|
|
LinkDiscord(discordID string, token string) (string, error)
|
|
SetPasswordByDiscordID(discordID string, hash []byte) error
|
|
GetByIDAndUsername(charID uint32) (userID uint32, username string, err error)
|
|
BanUser(userID uint32, expires *time.Time) error
|
|
}
|
|
|
|
// GachaRepo defines the contract for gacha system data access.
|
|
type GachaRepo interface {
|
|
GetEntryForTransaction(gachaID uint32, rollID uint8) (itemType uint8, itemNumber uint16, rolls int, err error)
|
|
GetRewardPool(gachaID uint32) ([]GachaEntry, error)
|
|
GetItemsForEntry(entryID uint32) ([]GachaItem, error)
|
|
GetGuaranteedItems(rollType uint8, gachaID uint32) ([]GachaItem, error)
|
|
GetStepupStep(gachaID uint32, charID uint32) (uint8, error)
|
|
GetStepupWithTime(gachaID uint32, charID uint32) (uint8, time.Time, error)
|
|
HasEntryType(gachaID uint32, entryType uint8) (bool, error)
|
|
DeleteStepup(gachaID uint32, charID uint32) error
|
|
InsertStepup(gachaID uint32, step uint8, charID uint32) error
|
|
GetBoxEntryIDs(gachaID uint32, charID uint32) ([]uint32, error)
|
|
InsertBoxEntry(gachaID uint32, entryID uint32, charID uint32) error
|
|
DeleteBoxEntries(gachaID uint32, charID uint32) error
|
|
ListShop() ([]Gacha, error)
|
|
GetShopType(shopID uint32) (int, error)
|
|
GetAllEntries(gachaID uint32) ([]GachaEntry, error)
|
|
GetWeightDivisor(gachaID uint32) (float64, error)
|
|
}
|
|
|
|
// HouseRepo defines the contract for house/housing data access.
|
|
type HouseRepo interface {
|
|
UpdateInterior(charID uint32, data []byte) error
|
|
GetHouseByCharID(charID uint32) (HouseData, error)
|
|
SearchHousesByName(name string) ([]HouseData, error)
|
|
UpdateHouseState(charID uint32, state uint8, password string) error
|
|
GetHouseAccess(charID uint32) (state uint8, password string, err error)
|
|
GetHouseContents(charID uint32) (houseTier, houseData, houseFurniture, bookshelf, gallery, tore, garden []byte, err error)
|
|
GetMission(charID uint32) ([]byte, error)
|
|
UpdateMission(charID uint32, data []byte) error
|
|
InitializeWarehouse(charID uint32) error
|
|
GetWarehouseNames(charID uint32) (itemNames, equipNames [10]string, err error)
|
|
RenameWarehouseBox(charID uint32, boxType uint8, boxIndex uint8, name string) error
|
|
GetWarehouseItemData(charID uint32, index uint8) ([]byte, error)
|
|
SetWarehouseItemData(charID uint32, index uint8, data []byte) error
|
|
GetWarehouseEquipData(charID uint32, index uint8) ([]byte, error)
|
|
SetWarehouseEquipData(charID uint32, index uint8, data []byte) error
|
|
GetTitles(charID uint32) ([]Title, error)
|
|
AcquireTitle(titleID uint16, charID uint32) error
|
|
}
|
|
|
|
// FestaRepo defines the contract for festa event data access.
|
|
type FestaRepo interface {
|
|
CleanupAll() error
|
|
InsertEvent(startTime uint32) error
|
|
GetFestaEvents() ([]FestaEvent, error)
|
|
GetTeamSouls(team string) (uint32, error)
|
|
GetTrialsWithMonopoly() ([]FestaTrial, error)
|
|
GetTopGuildForTrial(trialType uint16) (FestaGuildRanking, error)
|
|
GetTopGuildInWindow(start, end uint32) (FestaGuildRanking, error)
|
|
GetCharSouls(charID uint32) (uint32, error)
|
|
HasClaimedMainPrize(charID uint32) bool
|
|
VoteTrial(charID uint32, trialID uint32) error
|
|
RegisterGuild(guildID uint32, team string) error
|
|
SubmitSouls(charID, guildID uint32, souls []uint16) error
|
|
ClaimPrize(prizeID uint32, charID uint32) error
|
|
ListPrizes(charID uint32, prizeType string) ([]Prize, error)
|
|
}
|
|
|
|
// TowerRepo defines the contract for tower/tenrouirai data access.
|
|
type TowerRepo interface {
|
|
GetTowerData(charID uint32) (TowerData, error)
|
|
GetSkills(charID uint32) (string, error)
|
|
UpdateSkills(charID uint32, skills string, cost int32) error
|
|
UpdateProgress(charID uint32, tr, trp, cost, block1 int32) error
|
|
GetGems(charID uint32) (string, error)
|
|
UpdateGems(charID uint32, gems string) error
|
|
GetTenrouiraiProgress(guildID uint32) (TenrouiraiProgressData, error)
|
|
GetTenrouiraiMissionScores(guildID uint32, missionIndex uint8) ([]TenrouiraiCharScore, error)
|
|
GetGuildTowerRP(guildID uint32) (uint32, error)
|
|
GetGuildTowerPageAndRP(guildID uint32) (page int, donated int, err error)
|
|
AdvanceTenrouiraiPage(guildID uint32) error
|
|
DonateGuildTowerRP(guildID uint32, rp uint16) error
|
|
}
|
|
|
|
// RengokuRepo defines the contract for rengoku score/ranking data access.
|
|
type RengokuRepo interface {
|
|
UpsertScore(charID uint32, maxStagesMp, maxPointsMp, maxStagesSp, maxPointsSp uint32) error
|
|
GetRanking(leaderboard uint32, guildID uint32) ([]RengokuScore, error)
|
|
}
|
|
|
|
// MailRepo defines the contract for in-game mail data access.
|
|
type MailRepo interface {
|
|
SendMail(senderID, recipientID uint32, subject, body string, itemID, itemAmount uint16, isGuildInvite, isSystemMessage bool) error
|
|
GetListForCharacter(charID uint32) ([]Mail, error)
|
|
GetByID(id int) (*Mail, error)
|
|
MarkRead(id int) error
|
|
MarkDeleted(id int) error
|
|
SetLocked(id int, locked bool) error
|
|
MarkItemReceived(id int) error
|
|
}
|
|
|
|
// StampRepo defines the contract for stamp card data access.
|
|
type StampRepo interface {
|
|
GetChecked(charID uint32, stampType string) (time.Time, error)
|
|
Init(charID uint32, now time.Time) error
|
|
SetChecked(charID uint32, stampType string, now time.Time) error
|
|
IncrementTotal(charID uint32, stampType string) error
|
|
GetTotals(charID uint32, stampType string) (total, redeemed uint16, err error)
|
|
ExchangeYearly(charID uint32) (total, redeemed uint16, err error)
|
|
Exchange(charID uint32, stampType string) (total, redeemed uint16, err error)
|
|
GetMonthlyClaimed(charID uint32, monthlyType string) (time.Time, error)
|
|
SetMonthlyClaimed(charID uint32, monthlyType string, now time.Time) error
|
|
}
|
|
|
|
// DistributionRepo defines the contract for distribution/event item data access.
|
|
type DistributionRepo interface {
|
|
List(charID uint32, distType uint8) ([]Distribution, error)
|
|
GetItems(distributionID uint32) ([]DistributionItem, error)
|
|
RecordAccepted(distributionID, charID uint32) error
|
|
GetDescription(distributionID uint32) (string, error)
|
|
}
|
|
|
|
// SessionRepo defines the contract for session/login token data access.
|
|
type SessionRepo interface {
|
|
ValidateLoginToken(token string, sessionID uint32, charID uint32) error
|
|
BindSession(token string, serverID uint16, charID uint32) error
|
|
ClearSession(token string) error
|
|
UpdatePlayerCount(serverID uint16, count int) error
|
|
}
|
|
|
|
// EventRepo defines the contract for event/login boost data access.
|
|
type EventRepo interface {
|
|
GetFeatureWeapon(startTime time.Time) (activeFeature, error)
|
|
InsertFeatureWeapon(startTime time.Time, features uint32) error
|
|
GetLoginBoosts(charID uint32) ([]loginBoost, error)
|
|
InsertLoginBoost(charID uint32, weekReq uint8, expiration, reset time.Time) error
|
|
UpdateLoginBoost(charID uint32, weekReq uint8, expiration, reset time.Time) error
|
|
GetEventQuests() ([]EventQuest, error)
|
|
UpdateEventQuestStartTimes(updates []EventQuestUpdate) error
|
|
}
|
|
|
|
// AchievementRepo defines the contract for achievement data access.
|
|
type AchievementRepo interface {
|
|
EnsureExists(charID uint32) error
|
|
GetAllScores(charID uint32) ([33]int32, error)
|
|
IncrementScore(charID uint32, achievementID uint8) error
|
|
}
|
|
|
|
// ShopRepo defines the contract for shop data access.
|
|
type ShopRepo interface {
|
|
GetShopItems(shopType uint8, shopID uint32, charID uint32) ([]ShopItem, error)
|
|
RecordPurchase(charID, shopItemID, quantity uint32) error
|
|
GetFpointItem(tradeID uint32) (quantity, fpoints int, err error)
|
|
GetFpointExchangeList() ([]FPointExchange, error)
|
|
}
|
|
|
|
// CafeRepo defines the contract for cafe bonus data access.
|
|
type CafeRepo interface {
|
|
ResetAccepted(charID uint32) error
|
|
GetBonuses(charID uint32) ([]CafeBonus, error)
|
|
GetClaimable(charID uint32, elapsedSec int64) ([]CafeBonus, error)
|
|
GetBonusItem(bonusID uint32) (itemType, quantity uint32, err error)
|
|
AcceptBonus(bonusID, charID uint32) error
|
|
}
|
|
|
|
// GoocooRepo defines the contract for goocoo (pet) data access.
|
|
type GoocooRepo interface {
|
|
EnsureExists(charID uint32) error
|
|
GetSlot(charID uint32, slot uint32) ([]byte, error)
|
|
ClearSlot(charID uint32, slot uint32) error
|
|
SaveSlot(charID uint32, slot uint32, data []byte) error
|
|
}
|
|
|
|
// DivaRepo defines the contract for diva event data access.
|
|
type DivaRepo interface {
|
|
DeleteEvents() error
|
|
InsertEvent(startEpoch uint32) error
|
|
GetEvents() ([]DivaEvent, error)
|
|
}
|
|
|
|
// MiscRepo defines the contract for miscellaneous data access.
|
|
type MiscRepo interface {
|
|
GetTrendWeapons(weaponType uint8) ([]uint16, error)
|
|
UpsertTrendWeapon(weaponID uint16, weaponType uint8) error
|
|
}
|
|
|
|
// ScenarioRepo defines the contract for scenario counter data access.
|
|
type ScenarioRepo interface {
|
|
GetCounters() ([]Scenario, error)
|
|
}
|
|
|
|
// MercenaryRepo defines the contract for mercenary/rasta data access.
|
|
type MercenaryRepo interface {
|
|
NextRastaID() (uint32, error)
|
|
NextAirouID() (uint32, error)
|
|
GetMercenaryLoans(charID uint32) ([]MercenaryLoan, error)
|
|
GetGuildHuntCatsUsed(charID uint32) ([]GuildHuntCatUsage, error)
|
|
GetGuildAirou(guildID uint32) ([][]byte, error)
|
|
}
|