diff --git a/server/channelserver/handlers_achievement.go b/server/channelserver/handlers_achievement.go index e43299946..d26f8a1c2 100644 --- a/server/channelserver/handlers_achievement.go +++ b/server/channelserver/handlers_achievement.go @@ -3,7 +3,6 @@ package channelserver import ( "erupe-ce/common/byteframe" "erupe-ce/network/mhfpacket" - "fmt" "io" "go.uber.org/zap" @@ -98,20 +97,11 @@ func GetAchData(id uint8, score int32) Achievement { func handleMsgMhfGetAchievement(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfGetAchievement) - var exists int - err := s.server.db.QueryRow("SELECT id FROM achievements WHERE id=$1", pkt.CharID).Scan(&exists) - if err != nil { - if _, err := s.server.db.Exec("INSERT INTO achievements (id) VALUES ($1)", pkt.CharID); err != nil { - s.logger.Error("Failed to insert achievements record", zap.Error(err)) - } + if err := s.server.achievementRepo.EnsureExists(pkt.CharID); err != nil { + s.logger.Error("Failed to ensure achievements record", zap.Error(err)) } - var scores [33]int32 - err = s.server.db.QueryRow("SELECT * FROM achievements WHERE id=$1", pkt.CharID).Scan(&scores[0], - &scores[0], &scores[1], &scores[2], &scores[3], &scores[4], &scores[5], &scores[6], &scores[7], &scores[8], - &scores[9], &scores[10], &scores[11], &scores[12], &scores[13], &scores[14], &scores[15], &scores[16], - &scores[17], &scores[18], &scores[19], &scores[20], &scores[21], &scores[22], &scores[23], &scores[24], - &scores[25], &scores[26], &scores[27], &scores[28], &scores[29], &scores[30], &scores[31], &scores[32]) + scores, err := s.server.achievementRepo.GetAllScores(pkt.CharID) if err != nil { doAckBufSucceed(s, pkt.AckHandle, make([]byte, 20)) return @@ -165,15 +155,11 @@ func handleMsgMhfAddAchievement(s *Session, p mhfpacket.MHFPacket) { return } - var exists int - err := s.server.db.QueryRow("SELECT id FROM achievements WHERE id=$1", s.charID).Scan(&exists) - if err != nil { - if _, err := s.server.db.Exec("INSERT INTO achievements (id) VALUES ($1)", s.charID); err != nil { - s.logger.Error("Failed to insert achievements record", zap.Error(err)) - } + if err := s.server.achievementRepo.EnsureExists(s.charID); err != nil { + s.logger.Error("Failed to ensure achievements record", zap.Error(err)) } - if _, err := s.server.db.Exec(fmt.Sprintf("UPDATE achievements SET ach%d=ach%d+1 WHERE id=$1", pkt.AchievementID, pkt.AchievementID), s.charID); err != nil { + if err := s.server.achievementRepo.IncrementScore(s.charID, pkt.AchievementID); err != nil { s.logger.Error("Failed to update achievement score", zap.Error(err)) } } diff --git a/server/channelserver/handlers_cafe.go b/server/channelserver/handlers_cafe.go index 38de82e5f..6b8d96c7a 100644 --- a/server/channelserver/handlers_cafe.go +++ b/server/channelserver/handlers_cafe.go @@ -84,7 +84,7 @@ func handleMsgMhfGetCafeDuration(s *Session, p mhfpacket.MHFPacket) { if err := s.server.charRepo.ResetCafeTime(s.charID, cafeReset); err != nil { s.logger.Error("Failed to reset cafe time", zap.Error(err)) } - if _, err := s.server.db.Exec(`DELETE FROM cafe_accepted WHERE character_id=$1`, s.charID); err != nil { + if err := s.server.cafeRepo.ResetAccepted(s.charID); err != nil { s.logger.Error("Failed to delete accepted cafe bonuses", zap.Error(err)) } } @@ -121,14 +121,7 @@ func handleMsgMhfGetCafeDurationBonusInfo(s *Session, p mhfpacket.MHFPacket) { bf := byteframe.NewByteFrame() var count uint32 - rows, err := s.server.db.Queryx(` - SELECT cb.id, time_req, item_type, item_id, quantity, - ( - SELECT count(*) - FROM cafe_accepted ca - WHERE cb.id = ca.cafe_id AND ca.character_id = $1 - )::int::bool AS claimed - FROM cafebonus cb ORDER BY id ASC;`, s.charID) + rows, err := s.server.cafeRepo.GetBonuses(s.charID) if err != nil { s.logger.Error("Error getting cafebonus", zap.Error(err)) doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4)) @@ -160,18 +153,7 @@ func handleMsgMhfReceiveCafeDurationBonus(s *Session, p mhfpacket.MHFPacket) { bf := byteframe.NewByteFrame() var count uint32 bf.WriteUint32(0) - rows, err := s.server.db.Queryx(` - SELECT c.id, time_req, item_type, item_id, quantity - FROM cafebonus c - WHERE ( - SELECT count(*) - FROM cafe_accepted ca - WHERE c.id = ca.cafe_id AND ca.character_id = $1 - ) < 1 AND ( - SELECT ch.cafe_time + $2 - FROM characters ch - WHERE ch.id = $1 - ) >= time_req`, s.charID, TimeAdjusted().Unix()-s.sessionStart) + rows, err := s.server.cafeRepo.GetClaimable(s.charID, TimeAdjusted().Unix()-s.sessionStart) if err != nil || !mhfcourse.CourseExists(30, s.courses) { doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } else { @@ -195,17 +177,14 @@ func handleMsgMhfReceiveCafeDurationBonus(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfPostCafeDurationBonusReceived(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfPostCafeDurationBonusReceived) - var cafeBonus CafeBonus for _, cbID := range pkt.CafeBonusID { - err := s.server.db.QueryRow(` - SELECT cb.id, item_type, quantity FROM cafebonus cb WHERE cb.id=$1 - `, cbID).Scan(&cafeBonus.ID, &cafeBonus.ItemType, &cafeBonus.Quantity) + itemType, quantity, err := s.server.cafeRepo.GetBonusItem(cbID) if err == nil { - if cafeBonus.ItemType == 17 { - _ = addPointNetcafe(s, int(cafeBonus.Quantity)) + if itemType == 17 { + _ = addPointNetcafe(s, int(quantity)) } } - if _, err := s.server.db.Exec("INSERT INTO public.cafe_accepted VALUES ($1, $2)", cbID, s.charID); err != nil { + if err := s.server.cafeRepo.AcceptBonus(cbID, s.charID); err != nil { s.logger.Error("Failed to insert accepted cafe bonus", zap.Error(err)) } } diff --git a/server/channelserver/handlers_event.go b/server/channelserver/handlers_event.go index 404b52630..064f4b7ed 100644 --- a/server/channelserver/handlers_event.go +++ b/server/channelserver/handlers_event.go @@ -65,13 +65,12 @@ func handleMsgMhfGetWeeklySchedule(s *Session, p mhfpacket.MHFPacket) { } for _, t := range times { - var temp activeFeature - err := s.server.db.QueryRowx(`SELECT start_time, featured FROM feature_weapon WHERE start_time=$1`, t).StructScan(&temp) + temp, err := s.server.eventRepo.GetFeatureWeapon(t) if err != nil || temp.StartTime.IsZero() { weapons := token.RNG.Intn(s.server.erupeConfig.GameplayOptions.MaxFeatureWeapons-s.server.erupeConfig.GameplayOptions.MinFeatureWeapons+1) + s.server.erupeConfig.GameplayOptions.MinFeatureWeapons temp = generateFeatureWeapons(weapons, s.server.erupeConfig.RealClientMode) temp.StartTime = t - if _, err := s.server.db.Exec(`INSERT INTO feature_weapon VALUES ($1, $2)`, temp.StartTime, temp.ActiveFeatures); err != nil { + if err := s.server.eventRepo.InsertFeatureWeapon(temp.StartTime, temp.ActiveFeatures); err != nil { s.logger.Error("Failed to insert feature weapon", zap.Error(err)) } } @@ -138,7 +137,7 @@ func handleMsgMhfGetKeepLoginBoostStatus(s *Session, p mhfpacket.MHFPacket) { bf := byteframe.NewByteFrame() var loginBoosts []loginBoost - rows, err := s.server.db.Queryx("SELECT week_req, expiration, reset FROM login_boost WHERE char_id=$1 ORDER BY week_req", s.charID) + rows, err := s.server.eventRepo.GetLoginBoosts(s.charID) if err != nil || s.server.erupeConfig.GameplayOptions.DisableLoginBoost { _ = rows.Close() doAckBufSucceed(s, pkt.AckHandle, make([]byte, 35)) @@ -159,7 +158,7 @@ func handleMsgMhfGetKeepLoginBoostStatus(s *Session, p mhfpacket.MHFPacket) { {WeekReq: 5, Expiration: temp}, } for _, boost := range loginBoosts { - if _, err := s.server.db.Exec(`INSERT INTO login_boost VALUES ($1, $2, $3, $4)`, s.charID, boost.WeekReq, boost.Expiration, time.Time{}); err != nil { + if err := s.server.eventRepo.InsertLoginBoost(s.charID, boost.WeekReq, boost.Expiration, time.Time{}); err != nil { s.logger.Error("Failed to insert login boost", zap.Error(err)) } } @@ -170,7 +169,7 @@ func handleMsgMhfGetKeepLoginBoostStatus(s *Session, p mhfpacket.MHFPacket) { if !boost.Reset.IsZero() && boost.Reset.Before(TimeAdjusted()) { boost.Expiration = TimeWeekStart() boost.Reset = time.Time{} - if _, err := s.server.db.Exec(`UPDATE login_boost SET expiration=$1, reset=$2 WHERE char_id=$3 AND week_req=$4`, boost.Expiration, boost.Reset, s.charID, boost.WeekReq); err != nil { + if err := s.server.eventRepo.UpdateLoginBoost(s.charID, boost.WeekReq, boost.Expiration, boost.Reset); err != nil { s.logger.Error("Failed to reset login boost", zap.Error(err)) } } @@ -215,7 +214,7 @@ func handleMsgMhfUseKeepLoginBoost(s *Session, p mhfpacket.MHFPacket) { expiration = TimeAdjusted().Add(240 * time.Minute) } bf.WriteUint32(uint32(expiration.Unix())) - if _, err := s.server.db.Exec(`UPDATE login_boost SET expiration=$1, reset=$2 WHERE char_id=$3 AND week_req=$4`, expiration, TimeWeekNext(), s.charID, pkt.BoostWeekUsed); err != nil { + if err := s.server.eventRepo.UpdateLoginBoost(s.charID, pkt.BoostWeekUsed, expiration, TimeWeekNext()); err != nil { s.logger.Error("Failed to use login boost", zap.Error(err)) } doAckBufSucceed(s, pkt.AckHandle, bf.Data()) diff --git a/server/channelserver/handlers_shop.go b/server/channelserver/handlers_shop.go index 72f9e0ad7..2e213707a 100644 --- a/server/channelserver/handlers_shop.go +++ b/server/channelserver/handlers_shop.go @@ -59,10 +59,7 @@ func writeShopItems(bf *byteframe.ByteFrame, items []ShopItem, mode _config.Mode func getShopItems(s *Session, shopType uint8, shopID uint32) []ShopItem { var items []ShopItem var temp ShopItem - rows, err := s.server.db.Queryx(`SELECT id, item_id, cost, quantity, min_hr, min_sr, min_gr, store_level, max_quantity, - COALESCE((SELECT bought FROM shop_items_bought WHERE shop_item_id=si.id AND character_id=$3), 0) as used_quantity, - road_floors, road_fatalis FROM shop_items si WHERE shop_type=$1 AND shop_id=$2 - `, shopType, shopID, s.charID) + rows, err := s.server.shopRepo.GetShopItems(shopType, shopID, s.charID) if err == nil { for rows.Next() { err = rows.StructScan(&temp) @@ -212,11 +209,7 @@ func handleMsgMhfAcquireExchangeShop(s *Session, p mhfpacket.MHFPacket) { continue } buyCount := bf.ReadUint32() - if _, err := s.server.db.Exec(`INSERT INTO shop_items_bought (character_id, shop_item_id, bought) - VALUES ($1,$2,$3) ON CONFLICT (character_id, shop_item_id) - DO UPDATE SET bought = bought + $3 - WHERE EXCLUDED.character_id=$1 AND EXCLUDED.shop_item_id=$2 - `, s.charID, itemHash, buyCount); err != nil { + if err := s.server.shopRepo.RecordPurchase(s.charID, itemHash, buyCount); err != nil { s.logger.Error("Failed to update shop item purchase count", zap.Error(err)) } } @@ -235,8 +228,8 @@ type FPointExchange struct { func handleMsgMhfExchangeFpoint2Item(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfExchangeFpoint2Item) - var itemValue, quantity int - if err := s.server.db.QueryRow("SELECT quantity, fpoints FROM fpoint_items WHERE id=$1", pkt.TradeID).Scan(&quantity, &itemValue); err != nil { + quantity, itemValue, err := s.server.shopRepo.GetFpointItem(pkt.TradeID) + if err != nil { s.logger.Error("Failed to read fpoint item cost", zap.Error(err)) doAckSimpleFail(s, pkt.AckHandle, nil) return @@ -255,8 +248,8 @@ func handleMsgMhfExchangeFpoint2Item(s *Session, p mhfpacket.MHFPacket) { func handleMsgMhfExchangeItem2Fpoint(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfExchangeItem2Fpoint) - var itemValue, quantity int - if err := s.server.db.QueryRow("SELECT quantity, fpoints FROM fpoint_items WHERE id=$1", pkt.TradeID).Scan(&quantity, &itemValue); err != nil { + quantity, itemValue, err := s.server.shopRepo.GetFpointItem(pkt.TradeID) + if err != nil { s.logger.Error("Failed to read fpoint item value", zap.Error(err)) doAckSimpleFail(s, pkt.AckHandle, nil) return @@ -280,7 +273,7 @@ func handleMsgMhfGetFpointExchangeList(s *Session, p mhfpacket.MHFPacket) { var exchange FPointExchange var exchanges []FPointExchange var buyables uint16 - rows, err := s.server.db.Queryx(`SELECT id, item_type, item_id, quantity, fpoints, buyable FROM fpoint_items ORDER BY buyable DESC`) + rows, err := s.server.shopRepo.GetFpointExchangeList() if err == nil { for rows.Next() { err = rows.StructScan(&exchange) diff --git a/server/channelserver/repo_achievement.go b/server/channelserver/repo_achievement.go new file mode 100644 index 000000000..26e12dd79 --- /dev/null +++ b/server/channelserver/repo_achievement.go @@ -0,0 +1,44 @@ +package channelserver + +import ( + "fmt" + + "github.com/jmoiron/sqlx" +) + +// AchievementRepository centralizes all database access for the achievements table. +type AchievementRepository struct { + db *sqlx.DB +} + +// NewAchievementRepository creates a new AchievementRepository. +func NewAchievementRepository(db *sqlx.DB) *AchievementRepository { + return &AchievementRepository{db: db} +} + +// EnsureExists creates an achievements record for the character if one doesn't exist. +func (r *AchievementRepository) EnsureExists(charID uint32) error { + _, err := r.db.Exec("INSERT INTO achievements (id) VALUES ($1) ON CONFLICT DO NOTHING", charID) + return err +} + +// GetAllScores returns all 33 achievement scores for a character. +func (r *AchievementRepository) GetAllScores(charID uint32) ([33]int32, error) { + var scores [33]int32 + err := r.db.QueryRow("SELECT * FROM achievements WHERE id=$1", charID).Scan(&scores[0], + &scores[0], &scores[1], &scores[2], &scores[3], &scores[4], &scores[5], &scores[6], &scores[7], &scores[8], + &scores[9], &scores[10], &scores[11], &scores[12], &scores[13], &scores[14], &scores[15], &scores[16], + &scores[17], &scores[18], &scores[19], &scores[20], &scores[21], &scores[22], &scores[23], &scores[24], + &scores[25], &scores[26], &scores[27], &scores[28], &scores[29], &scores[30], &scores[31], &scores[32]) + return scores, err +} + +// IncrementScore increments the score for a specific achievement column. +// achievementID must be in the range [0, 32] to prevent SQL injection. +func (r *AchievementRepository) IncrementScore(charID uint32, achievementID uint8) error { + if achievementID > 32 { + return fmt.Errorf("achievement ID %d out of range [0, 32]", achievementID) + } + _, err := r.db.Exec(fmt.Sprintf("UPDATE achievements SET ach%d=ach%d+1 WHERE id=$1", achievementID, achievementID), charID) + return err +} diff --git a/server/channelserver/repo_cafe.go b/server/channelserver/repo_cafe.go new file mode 100644 index 000000000..4eb7ceb3e --- /dev/null +++ b/server/channelserver/repo_cafe.go @@ -0,0 +1,61 @@ +package channelserver + +import ( + "github.com/jmoiron/sqlx" +) + +// CafeRepository centralizes all database access for cafe-related tables. +type CafeRepository struct { + db *sqlx.DB +} + +// NewCafeRepository creates a new CafeRepository. +func NewCafeRepository(db *sqlx.DB) *CafeRepository { + return &CafeRepository{db: db} +} + +// ResetAccepted deletes all accepted cafe bonuses for a character. +func (r *CafeRepository) ResetAccepted(charID uint32) error { + _, err := r.db.Exec(`DELETE FROM cafe_accepted WHERE character_id=$1`, charID) + return err +} + +// GetBonuses returns all cafe bonuses with their claimed status for a character. +func (r *CafeRepository) GetBonuses(charID uint32) (*sqlx.Rows, error) { + return r.db.Queryx(` + SELECT cb.id, time_req, item_type, item_id, quantity, + ( + SELECT count(*) + FROM cafe_accepted ca + WHERE cb.id = ca.cafe_id AND ca.character_id = $1 + )::int::bool AS claimed + FROM cafebonus cb ORDER BY id ASC;`, charID) +} + +// GetClaimable returns unclaimed cafe bonuses where the character has enough accumulated time. +func (r *CafeRepository) GetClaimable(charID uint32, elapsedSec int64) (*sqlx.Rows, error) { + return r.db.Queryx(` + SELECT c.id, time_req, item_type, item_id, quantity + FROM cafebonus c + WHERE ( + SELECT count(*) + FROM cafe_accepted ca + WHERE c.id = ca.cafe_id AND ca.character_id = $1 + ) < 1 AND ( + SELECT ch.cafe_time + $2 + FROM characters ch + WHERE ch.id = $1 + ) >= time_req`, charID, elapsedSec) +} + +// GetBonusItem returns the item type and quantity for a specific cafe bonus. +func (r *CafeRepository) GetBonusItem(bonusID uint32) (itemType, quantity uint32, err error) { + err = r.db.QueryRow(`SELECT cb.id, item_type, quantity FROM cafebonus cb WHERE cb.id=$1`, bonusID).Scan(&bonusID, &itemType, &quantity) + return +} + +// AcceptBonus records that a character has accepted a cafe bonus. +func (r *CafeRepository) AcceptBonus(bonusID, charID uint32) error { + _, err := r.db.Exec("INSERT INTO cafe_accepted VALUES ($1, $2)", bonusID, charID) + return err +} diff --git a/server/channelserver/repo_event.go b/server/channelserver/repo_event.go new file mode 100644 index 000000000..9bfb00efa --- /dev/null +++ b/server/channelserver/repo_event.go @@ -0,0 +1,47 @@ +package channelserver + +import ( + "time" + + "github.com/jmoiron/sqlx" +) + +// EventRepository centralizes all database access for event-related tables. +type EventRepository struct { + db *sqlx.DB +} + +// NewEventRepository creates a new EventRepository. +func NewEventRepository(db *sqlx.DB) *EventRepository { + return &EventRepository{db: db} +} + +// GetFeatureWeapon returns the featured weapon bitfield for a given start time. +func (r *EventRepository) GetFeatureWeapon(startTime time.Time) (activeFeature, error) { + var af activeFeature + err := r.db.QueryRowx(`SELECT start_time, featured FROM feature_weapon WHERE start_time=$1`, startTime).StructScan(&af) + return af, err +} + +// InsertFeatureWeapon stores a new featured weapon entry. +func (r *EventRepository) InsertFeatureWeapon(startTime time.Time, features uint32) error { + _, err := r.db.Exec(`INSERT INTO feature_weapon VALUES ($1, $2)`, startTime, features) + return err +} + +// GetLoginBoosts returns all login boost rows for a character, ordered by week_req. +func (r *EventRepository) GetLoginBoosts(charID uint32) (*sqlx.Rows, error) { + return r.db.Queryx("SELECT week_req, expiration, reset FROM login_boost WHERE char_id=$1 ORDER BY week_req", charID) +} + +// InsertLoginBoost creates a new login boost entry. +func (r *EventRepository) InsertLoginBoost(charID uint32, weekReq uint8, expiration, reset time.Time) error { + _, err := r.db.Exec(`INSERT INTO login_boost VALUES ($1, $2, $3, $4)`, charID, weekReq, expiration, reset) + return err +} + +// UpdateLoginBoost updates expiration and reset for a login boost entry. +func (r *EventRepository) UpdateLoginBoost(charID uint32, weekReq uint8, expiration, reset time.Time) error { + _, err := r.db.Exec(`UPDATE login_boost SET expiration=$1, reset=$2 WHERE char_id=$3 AND week_req=$4`, expiration, reset, charID, weekReq) + return err +} diff --git a/server/channelserver/repo_shop.go b/server/channelserver/repo_shop.go new file mode 100644 index 000000000..f51ac8a17 --- /dev/null +++ b/server/channelserver/repo_shop.go @@ -0,0 +1,44 @@ +package channelserver + +import ( + "github.com/jmoiron/sqlx" +) + +// ShopRepository centralizes all database access for shop-related tables. +type ShopRepository struct { + db *sqlx.DB +} + +// NewShopRepository creates a new ShopRepository. +func NewShopRepository(db *sqlx.DB) *ShopRepository { + return &ShopRepository{db: db} +} + +// GetShopItems returns shop items with per-character purchase counts. +func (r *ShopRepository) GetShopItems(shopType uint8, shopID uint32, charID uint32) (*sqlx.Rows, error) { + return r.db.Queryx(`SELECT id, item_id, cost, quantity, min_hr, min_sr, min_gr, store_level, max_quantity, + COALESCE((SELECT bought FROM shop_items_bought WHERE shop_item_id=si.id AND character_id=$3), 0) as used_quantity, + road_floors, road_fatalis FROM shop_items si WHERE shop_type=$1 AND shop_id=$2 + `, shopType, shopID, charID) +} + +// RecordPurchase upserts a purchase record, adding to the bought count. +func (r *ShopRepository) RecordPurchase(charID, shopItemID, quantity uint32) error { + _, err := r.db.Exec(`INSERT INTO shop_items_bought (character_id, shop_item_id, bought) + VALUES ($1,$2,$3) ON CONFLICT (character_id, shop_item_id) + DO UPDATE SET bought = bought + $3 + WHERE EXCLUDED.character_id=$1 AND EXCLUDED.shop_item_id=$2 + `, charID, shopItemID, quantity) + return err +} + +// GetFpointItem returns the quantity and fpoints cost for a frontier point item. +func (r *ShopRepository) GetFpointItem(tradeID uint32) (quantity, fpoints int, err error) { + err = r.db.QueryRow("SELECT quantity, fpoints FROM fpoint_items WHERE id=$1", tradeID).Scan(&quantity, &fpoints) + return +} + +// GetFpointExchangeList returns all frontier point exchange items ordered by buyable status. +func (r *ShopRepository) GetFpointExchangeList() (*sqlx.Rows, error) { + return r.db.Queryx(`SELECT id, item_type, item_id, quantity, fpoints, buyable FROM fpoint_items ORDER BY buyable DESC`) +} diff --git a/server/channelserver/sys_channel_server.go b/server/channelserver/sys_channel_server.go index 605a457d7..740b0ed4b 100644 --- a/server/channelserver/sys_channel_server.go +++ b/server/channelserver/sys_channel_server.go @@ -58,6 +58,10 @@ type Server struct { stampRepo *StampRepository distRepo *DistributionRepository sessionRepo *SessionRepository + eventRepo *EventRepository + achievementRepo *AchievementRepository + shopRepo *ShopRepository + cafeRepo *CafeRepository erupeConfig *_config.Config acceptConns chan net.Conn deleteConns chan net.Conn @@ -140,6 +144,10 @@ func NewServer(config *Config) *Server { s.stampRepo = NewStampRepository(config.DB) s.distRepo = NewDistributionRepository(config.DB) s.sessionRepo = NewSessionRepository(config.DB) + s.eventRepo = NewEventRepository(config.DB) + s.achievementRepo = NewAchievementRepository(config.DB) + s.shopRepo = NewShopRepository(config.DB) + s.cafeRepo = NewCafeRepository(config.DB) // Mezeporta s.stages["sl1Ns200p0a0u0"] = NewStage("sl1Ns200p0a0u0")