Merge branch 'main' into feature/diva

# Conflicts:
#	bundled-schema/DivaShops.sql
#	bundled-schema/OtherShops.sql
#	patch-schema/shop-db.sql
#	server/channelserver/handlers_guild.go
#	server/channelserver/handlers_tactics.go
This commit is contained in:
wish
2023-04-15 13:57:33 +10:00
43 changed files with 471 additions and 685 deletions

View File

@@ -3,6 +3,7 @@ package channelserver
import (
"encoding/binary"
"encoding/hex"
"erupe-ce/common/mhfcourse"
ps "erupe-ce/common/pascalstring"
"erupe-ce/common/stringsupport"
"fmt"
@@ -11,11 +12,11 @@ import (
"strings"
"time"
"crypto/rand"
"erupe-ce/common/byteframe"
"erupe-ce/network/mhfpacket"
"go.uber.org/zap"
"math/bits"
"math/rand"
)
// Temporary function to just return no results for a MSG_MHF_ENUMERATE* packet
@@ -74,23 +75,13 @@ func doAckSimpleFail(s *Session, ackHandle uint32, data []byte) {
}
func updateRights(s *Session) {
rightsInt := uint32(0x0E)
rightsInt := uint32(2)
s.server.db.QueryRow("SELECT rights FROM users u INNER JOIN characters c ON u.id = c.user_id WHERE c.id = $1", s.charID).Scan(&rightsInt)
s.courses = mhfpacket.GetCourseStruct(rightsInt)
rights := []mhfpacket.ClientRight{{1, 0, 0}}
var netcafeBitSet bool
for _, course := range s.courses {
if (course.ID == 9 || course.ID == 25 || course.ID == 26) && !netcafeBitSet {
netcafeBitSet = true
rightsInt += 0x40000000 // set netcafe bit
rights = append(rights, mhfpacket.ClientRight{ID: 30})
}
rights = append(rights, mhfpacket.ClientRight{ID: course.ID, Timestamp: 0x70DB59F0})
}
s.courses, rightsInt = mhfcourse.GetCourseStruct(rightsInt)
update := &mhfpacket.MsgSysUpdateRight{
ClientRespAckHandle: 0,
Bitfield: rightsInt,
Rights: rights,
Rights: s.courses,
UnkSize: 0,
}
s.QueueSendMHF(update)
@@ -221,7 +212,7 @@ func logoutPlayer(s *Session) {
timePlayed += sessionTime
var rpGained int
if s.FindCourse("NetCafe").ID != 0 || s.FindCourse("N").ID != 0 {
if mhfcourse.CourseExists(30, s.courses) {
rpGained = timePlayed / 900
timePlayed = timePlayed % 900
s.server.db.Exec("UPDATE characters SET cafe_time=cafe_time+$1 WHERE id=$2", sessionTime, s.charID)

View File

@@ -2,6 +2,7 @@ package channelserver
import (
"erupe-ce/common/byteframe"
"erupe-ce/common/mhfcourse"
ps "erupe-ce/common/pascalstring"
"erupe-ce/network/mhfpacket"
"fmt"
@@ -88,7 +89,7 @@ func handleMsgMhfGetCafeDuration(s *Session, p mhfpacket.MHFPacket) {
if err != nil {
panic(err)
}
if s.FindCourse("NetCafe").ID != 0 || s.FindCourse("N").ID != 0 {
if mhfcourse.CourseExists(30, s.courses) {
cafeTime = uint32(TimeAdjusted().Unix()) - uint32(s.sessionStart) + cafeTime
}
bf.WriteUint32(cafeTime) // Total cafe time

View File

@@ -3,13 +3,14 @@ package channelserver
import (
"encoding/hex"
"erupe-ce/common/byteframe"
"erupe-ce/common/mhfcourse"
"erupe-ce/common/token"
"erupe-ce/config"
"erupe-ce/network/binpacket"
"erupe-ce/network/mhfpacket"
"fmt"
"golang.org/x/exp/slices"
"math"
"math/rand"
"strings"
"time"
@@ -81,6 +82,21 @@ func sendServerChatMessage(s *Session, message string) {
}
func parseChatCommand(s *Session, command string) {
if strings.HasPrefix(command, commands["PSN"].Prefix) {
if commands["PSN"].Enabled {
var id string
n, err := fmt.Sscanf(command, fmt.Sprintf("%s %%s", commands["PSN"].Prefix), &id)
if err != nil || n != 1 {
sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandPSNError"], commands["PSN"].Prefix))
} else {
_, err = s.server.db.Exec(`UPDATE users u SET psn_id=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, id, s.charID)
if err == nil {
sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandPSNSuccess"], id))
}
}
}
}
if strings.HasPrefix(command, commands["Reload"].Prefix) {
// Flush all objects and users and reload
if commands["Reload"].Enabled {
@@ -192,13 +208,14 @@ func parseChatCommand(s *Session, command string) {
sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandCourseError"], commands["Course"].Prefix))
} else {
name = strings.ToLower(name)
for _, course := range mhfpacket.Courses() {
for _, alias := range course.Aliases {
for _, course := range mhfcourse.Courses() {
for _, alias := range course.Aliases() {
if strings.ToLower(name) == strings.ToLower(alias) {
if slices.Contains(s.server.erupeConfig.Courses, config.Course{Name: course.Aliases[0], Enabled: true}) {
if s.FindCourse(name).ID != 0 {
ei := slices.IndexFunc(s.courses, func(c mhfpacket.Course) bool {
for _, alias := range c.Aliases {
if slices.Contains(s.server.erupeConfig.Courses, config.Course{Name: course.Aliases()[0], Enabled: true}) {
var delta, rightsInt uint32
if mhfcourse.CourseExists(course.ID, s.courses) {
ei := slices.IndexFunc(s.courses, func(c mhfcourse.Course) bool {
for _, alias := range c.Aliases() {
if strings.ToLower(name) == strings.ToLower(alias) {
return true
}
@@ -206,25 +223,26 @@ func parseChatCommand(s *Session, command string) {
return false
})
if ei != -1 {
s.courses = append(s.courses[:ei], s.courses[ei+1:]...)
sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandCourseDisabled"], course.Aliases[0]))
delta = uint32(-1 * math.Pow(2, float64(course.ID)))
sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandCourseDisabled"], course.Aliases()[0]))
}
} else {
s.courses = append(s.courses, course)
sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandCourseEnabled"], course.Aliases[0]))
delta = uint32(math.Pow(2, float64(course.ID)))
sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandCourseEnabled"], course.Aliases()[0]))
}
var newInt uint32
for _, course := range s.courses {
newInt += uint32(math.Pow(2, float64(course.ID)))
err = s.server.db.QueryRow("SELECT rights FROM users u INNER JOIN characters c ON u.id = c.user_id WHERE c.id = $1", s.charID).Scan(&rightsInt)
if err == nil {
s.server.db.Exec("UPDATE users u SET rights=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", rightsInt+delta, s.charID)
}
s.server.db.Exec("UPDATE users u SET rights=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)", newInt, s.charID)
updateRights(s)
} else {
sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandCourseLocked"], course.Aliases[0]))
sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandCourseLocked"], course.Aliases()[0]))
}
return
}
}
}
sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandCourseError"], commands["Course"].Prefix))
}
} else {
sendDisabledCommandMessage(s, commands["Course"])
@@ -367,8 +385,7 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
roll.SetLE()
roll.WriteUint16(4) // Unk
roll.WriteUint16(authorLen)
rand.Seed(time.Now().UnixNano())
dice := fmt.Sprintf("%d", rand.Intn(100)+1)
dice := fmt.Sprintf("%d", token.RNG().Intn(100)+1)
roll.WriteUint16(uint16(len(dice) + 1))
roll.WriteNullTerminatedBytes([]byte(dice))
roll.WriteNullTerminatedBytes(tmp.ReadNullTerminatedBytes())

View File

@@ -12,7 +12,7 @@ import (
)
const (
pointerGender = 0x81 // +1
pointerGender = 0x51 // +1
pointerRP = 0x22D16 // +2
pointerHouseTier = 0x1FB6C // +5
pointerHouseData = 0x1FE01 // +195

View File

@@ -5,7 +5,6 @@ import (
"erupe-ce/common/stringsupport"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
@@ -260,7 +259,7 @@ func dumpSaveData(s *Session, data []byte, suffix string) {
func handleMsgMhfLoaddata(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfLoaddata)
if _, err := os.Stat(filepath.Join(s.server.erupeConfig.BinPath, "save_override.bin")); err == nil {
data, _ := ioutil.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, "save_override.bin"))
data, _ := os.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, "save_override.bin"))
doAckBufSucceed(s, pkt.AckHandle, data)
return
}

View File

@@ -1,8 +1,8 @@
package channelserver
import (
"erupe-ce/common/token"
"math"
"math/rand"
"time"
"erupe-ce/common/byteframe"
@@ -95,9 +95,9 @@ func generateFeatureWeapons(count int) activeFeature {
}
nums := make([]int, 0)
var result int
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for len(nums) < count {
num := r.Intn(14)
rng := token.RNG()
num := rng.Intn(14)
exist := false
for _, v := range nums {
if v == num {
@@ -131,6 +131,7 @@ func handleMsgMhfGetKeepLoginBoostStatus(s *Session, p mhfpacket.MHFPacket) {
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)
if err != nil || s.server.erupeConfig.GameplayOptions.DisableLoginBoost {
rows.Close()
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 35))
return
}

View File

@@ -4,8 +4,8 @@ import (
"encoding/hex"
"erupe-ce/common/byteframe"
ps "erupe-ce/common/pascalstring"
"erupe-ce/common/token"
"erupe-ce/network/mhfpacket"
"math/rand"
"sort"
"time"
)
@@ -336,8 +336,7 @@ func handleMsgMhfEntryFesta(s *Session, p mhfpacket.MHFPacket) {
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
return
}
rand.Seed(time.Now().UnixNano())
team := uint32(rand.Intn(2))
team := uint32(token.RNG().Intn(2))
switch team {
case 0:
s.server.db.Exec("INSERT INTO festa_registrations VALUES ($1, 'blue')", guild.ID)

View File

@@ -1060,7 +1060,7 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
uint32 guild id
uint32 guild leader id (for mail)
uint32 unk (always null in pcap)
uint16 unk (always 0001 in pcap)
uint16 member count
uint16 len guild name
string nullterm guild name
uint16 len guild leader name
@@ -1862,7 +1862,6 @@ func handleMsgMhfEnumerateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfUpdateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUpdateGuildMessageBoard)
bf := byteframe.NewByteFrameFromBytes(pkt.Request)
guild, err := GetGuildInfoByCharacterId(s, s.charID)
applicant := false
if guild != nil {
@@ -1874,45 +1873,26 @@ func handleMsgMhfUpdateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
}
switch pkt.MessageOp {
case 0: // Create message
postType := bf.ReadUint32() // 0 = message, 1 = news
stampID := bf.ReadUint32()
titleLength := bf.ReadUint32()
bodyLength := bf.ReadUint32()
title := stringsupport.SJISToUTF8(bf.ReadBytes(uint(titleLength)))
body := stringsupport.SJISToUTF8(bf.ReadBytes(uint(bodyLength)))
s.server.db.Exec("INSERT INTO guild_posts (guild_id, author_id, stamp_id, post_type, title, body) VALUES ($1, $2, $3, $4, $5, $6)", guild.ID, s.charID, stampID, postType, title, body)
s.server.db.Exec("INSERT INTO guild_posts (guild_id, author_id, stamp_id, post_type, title, body) VALUES ($1, $2, $3, $4, $5, $6)", guild.ID, s.charID, pkt.StampID, pkt.PostType, pkt.Title, pkt.Body)
// TODO: if there are too many messages, purge excess
case 1: // Delete message
postID := bf.ReadUint32()
s.server.db.Exec("DELETE FROM guild_posts WHERE id = $1", postID)
s.server.db.Exec("DELETE FROM guild_posts WHERE id = $1", pkt.PostID)
case 2: // Update message
postID := bf.ReadUint32()
bf.ReadBytes(8)
titleLength := bf.ReadUint32()
bodyLength := bf.ReadUint32()
title := stringsupport.SJISToUTF8(bf.ReadBytes(uint(titleLength)))
body := stringsupport.SJISToUTF8(bf.ReadBytes(uint(bodyLength)))
s.server.db.Exec("UPDATE guild_posts SET title = $1, body = $2 WHERE id = $3", title, body, postID)
s.server.db.Exec("UPDATE guild_posts SET title = $1, body = $2 WHERE id = $3", pkt.Title, pkt.Body, pkt.PostID)
case 3: // Update stamp
postID := bf.ReadUint32()
bf.ReadBytes(8)
stampID := bf.ReadUint32()
s.server.db.Exec("UPDATE guild_posts SET stamp_id = $1 WHERE id = $2", stampID, postID)
s.server.db.Exec("UPDATE guild_posts SET stamp_id = $1 WHERE id = $2", pkt.StampID, pkt.PostID)
case 4: // Like message
postID := bf.ReadUint32()
bf.ReadBytes(8)
likeState := bf.ReadBool()
var likedBy string
err := s.server.db.QueryRow("SELECT liked_by FROM guild_posts WHERE id = $1", postID).Scan(&likedBy)
err := s.server.db.QueryRow("SELECT liked_by FROM guild_posts WHERE id = $1", pkt.PostID).Scan(&likedBy)
if err != nil {
s.logger.Error("Failed to get guild message like data from db", zap.Error(err))
} else {
if likeState {
if pkt.LikeState {
likedBy = stringsupport.CSVAdd(likedBy, int(s.charID))
s.server.db.Exec("UPDATE guild_posts SET liked_by = $1 WHERE id = $2", likedBy, postID)
s.server.db.Exec("UPDATE guild_posts SET liked_by = $1 WHERE id = $2", likedBy, pkt.PostID)
} else {
likedBy = stringsupport.CSVRemove(likedBy, int(s.charID))
s.server.db.Exec("UPDATE guild_posts SET liked_by = $1 WHERE id = $2", likedBy, postID)
s.server.db.Exec("UPDATE guild_posts SET liked_by = $1 WHERE id = $2", likedBy, pkt.PostID)
}
}
case 5: // Check for new messages

View File

@@ -1,14 +1,12 @@
package channelserver
import (
"fmt"
"io"
"time"
"erupe-ce/common/byteframe"
"erupe-ce/common/stringsupport"
"erupe-ce/network/mhfpacket"
"fmt"
"go.uber.org/zap"
"io"
)
func handleMsgMhfPostGuildScout(s *Session, p mhfpacket.MHFPacket) {
@@ -206,7 +204,7 @@ func handleMsgMhfGetGuildScoutList(s *Session, p mhfpacket.MHFPacket) {
}
rows, err := s.server.db.Queryx(`
SELECT c.id, c.name, ga.actor_id
SELECT c.id, c.name, c.hrp, c.gr, ga.actor_id
FROM guild_applications ga
JOIN characters c ON c.id = ga.character_id
WHERE ga.guild_id = $1 AND ga.application_type = 'invited'
@@ -231,14 +229,14 @@ func handleMsgMhfGetGuildScoutList(s *Session, p mhfpacket.MHFPacket) {
for rows.Next() {
var charName string
var charID uint32
var actorID uint32
var charID, actorID uint32
var hrp, gr uint16
err = rows.Scan(&charID, &charName, &actorID)
err = rows.Scan(&charID, &charName, &hrp, &gr, &actorID)
if err != nil {
doAckSimpleFail(s, pkt.AckHandle, nil)
panic(err)
continue
}
// This seems to be used as a unique ID for the invitation sent
@@ -247,14 +245,10 @@ func handleMsgMhfGetGuildScoutList(s *Session, p mhfpacket.MHFPacket) {
bf.WriteUint32(charID)
bf.WriteUint32(actorID)
bf.WriteUint32(charID)
bf.WriteUint32(uint32(time.Now().Unix()))
bf.WriteUint16(0x00) // HR?
bf.WriteUint16(0x00) // GR?
charNameBytes, _ := stringsupport.ConvertUTF8ToShiftJIS(charName)
bf.WriteBytes(charNameBytes)
bf.WriteBytes(make([]byte, 32-len(charNameBytes))) // Fixed length string
bf.WriteUint32(uint32(TimeAdjusted().Unix()))
bf.WriteUint16(hrp) // HR?
bf.WriteUint16(gr) // GR?
bf.WriteBytes(stringsupport.PaddedString(charName, 32, true))
count++
}

View File

@@ -326,15 +326,8 @@ func handleMsgMhfListMail(s *Session, p mhfpacket.MHFPacket) {
flags |= 0x04
}
// Workaround until EN mail items are patched
if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.DisableMailItems {
if itemAttached {
flags |= 0x08
}
} else {
if m.AttachedItemReceived {
flags |= 0x08
}
if m.AttachedItemReceived {
flags |= 0x08
}
if m.IsGuildInvite {

View File

@@ -8,7 +8,6 @@ import (
"erupe-ce/server/channelserver/compression/nullcomp"
"go.uber.org/zap"
"io"
"io/ioutil"
"os"
"path/filepath"
"time"
@@ -292,7 +291,7 @@ func handleMsgMhfEnumerateAiroulist(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumerateAiroulist)
resp := byteframe.NewByteFrame()
if _, err := os.Stat(filepath.Join(s.server.erupeConfig.BinPath, "airoulist.bin")); err == nil {
data, _ := ioutil.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, "airoulist.bin"))
data, _ := os.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, "airoulist.bin"))
resp.WriteBytes(data)
doAckBufSucceed(s, pkt.AckHandle, resp.Data())
return

View File

@@ -4,7 +4,7 @@ import (
ps "erupe-ce/common/pascalstring"
"fmt"
"github.com/jmoiron/sqlx"
"io/ioutil"
"os"
"path/filepath"
"erupe-ce/common/byteframe"
@@ -92,7 +92,7 @@ func handleMsgMhfLoadRengokuData(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfGetRengokuBinary(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetRengokuBinary)
// a (massively out of date) version resides in the game's /dat/ folder or up to date can be pulled from packets
data, err := ioutil.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, "rengoku_data.bin"))
data, err := os.ReadFile(filepath.Join(s.server.erupeConfig.BinPath, "rengoku_data.bin"))
if err != nil {
panic(err)
}

View File

@@ -358,6 +358,9 @@ func getRandomEntries(entries []GachaEntry, rolls int, isBox bool) ([]GachaEntry
totalWeight += entries[i].Weight
}
for {
if rolls == len(chosen) {
break
}
if !isBox {
result := rand.Float64() * totalWeight
for _, entry := range entries {
@@ -373,9 +376,6 @@ func getRandomEntries(entries []GachaEntry, rolls int, isBox bool) ([]GachaEntry
entries[result] = entries[len(entries)-1]
entries = entries[:len(entries)-1]
}
if rolls == len(chosen) {
break
}
}
return chosen, nil
}

View File

@@ -57,6 +57,8 @@ func getLangStrings(s *Server) map[string]string {
strings["commandCourseLocked"] = "%sコースはロックされています"
strings["commandTeleportError"] = "テレポートコマンドエラー 構文:%s x y"
strings["commandTeleportSuccess"] = "%d %dにテレポート"
strings["commandPSNError"] = "PSN連携コマンドエラー %s <psn id>"
strings["commandPSNSuccess"] = "PSN「%s」が連携されています"
strings["commandRaviNoCommand"] = "ラヴィコマンドが指定されていません"
strings["commandRaviStartSuccess"] = "大討伐を開始します"
@@ -142,6 +144,8 @@ func getLangStrings(s *Server) map[string]string {
strings["commandCourseLocked"] = "%s Course is locked"
strings["commandTeleportError"] = "Error in command. Format: %s x y"
strings["commandTeleportSuccess"] = "Teleporting to %d %d"
strings["commandPSNError"] = "Error in command. Format: %s <psn id>"
strings["commandPSNSuccess"] = "Connected PSN ID: %s"
strings["commandRaviNoCommand"] = "No Raviente command specified!"
strings["commandRaviStartSuccess"] = "The Great Slaying will begin in a moment"

View File

@@ -3,10 +3,10 @@ package channelserver
import (
"encoding/binary"
"encoding/hex"
"erupe-ce/common/mhfcourse"
"fmt"
"io"
"net"
"strings"
"sync"
"time"
@@ -32,6 +32,7 @@ type Session struct {
cryptConn *network.CryptConn
sendPackets chan packet
clientContext *clientctx.ClientContext
lastPacket time.Time
userEnteredStage bool // If the user has entered a stage before
stageID string
@@ -42,7 +43,7 @@ type Session struct {
charID uint32
logKey []byte
sessionStart int64
courses []mhfpacket.Course
courses []mhfcourse.Course
token string
kqf []byte
kqfOverride bool
@@ -73,6 +74,7 @@ func NewSession(server *Server, conn net.Conn) *Session {
cryptConn: network.NewCryptConn(conn),
sendPackets: make(chan packet, 20),
clientContext: &clientctx.ClientContext{}, // Unused
lastPacket: time.Now(),
sessionStart: TimeAdjusted().Unix(),
stageMoveStack: stringstack.New(),
}
@@ -160,6 +162,10 @@ func (s *Session) sendLoop() {
func (s *Session) recvLoop() {
for {
if time.Now().Add(-30 * time.Second).After(s.lastPacket) {
logoutPlayer(s)
return
}
if s.closed {
logoutPlayer(s)
return
@@ -181,6 +187,7 @@ func (s *Session) recvLoop() {
}
func (s *Session) handlePacketGroup(pktGroup []byte) {
s.lastPacket = time.Now()
bf := byteframe.NewByteFrameFromBytes(pktGroup)
opcodeUint16 := bf.ReadUint16()
opcode := network.PacketID(opcodeUint16)
@@ -228,7 +235,6 @@ func ignored(opcode network.PacketID) bool {
network.MSG_SYS_TIME,
network.MSG_SYS_EXTEND_THRESHOLD,
network.MSG_SYS_POSITION_OBJECT,
network.MSG_MHF_ENUMERATE_QUEST,
network.MSG_MHF_SAVEDATA,
}
set := make(map[network.PacketID]struct{}, len(ignoreList))
@@ -262,14 +268,3 @@ func (s *Session) logMessage(opcode uint16, data []byte, sender string, recipien
fmt.Printf("Data [%d bytes]:\n(Too long!)\n\n", len(data))
}
}
func (s *Session) FindCourse(name string) mhfpacket.Course {
for _, course := range s.courses {
for _, alias := range course.Aliases {
if strings.ToLower(name) == strings.ToLower(alias) {
return course
}
}
}
return mhfpacket.Course{}
}

View File

@@ -3,8 +3,6 @@ package channelserver
import (
"sync"
"time"
"erupe-ce/common/byteframe"
"erupe-ce/network/mhfpacket"
)
@@ -49,7 +47,6 @@ type Stage struct {
host *Session
maxPlayers uint16
password string
createdAt string
}
// NewStage creates a new stage with intialized values.
@@ -62,7 +59,6 @@ func NewStage(ID string) *Stage {
objectIndex: 0,
rawBinaryData: make(map[stageBinaryKey][]byte),
maxPlayers: 4,
createdAt: time.Now().Format("01-02-2006 15:04:05"),
}
return s
}