major refactoring: db.Player is now core.Player

- misc. cleanup
- core/db/players.go: works with core.Player types, will also grab inventory table
This commit is contained in:
CPunch 2023-03-22 00:30:58 -05:00
parent 735bdc5b36
commit 5b2a8b838e
20 changed files with 287 additions and 287 deletions

View File

@ -1,14 +1,18 @@
package config
const (
AEQUIP_COUNT = 9
AINVEN_COUNT = 50
ABANK_COUNT = 119
NANO_COUNT = 37
)
var (
SPAWN_X = 632032
SPAWN_Y = 187177
SPAWN_Z = -5500
AEQUIP_COUNT = 9
AINVEN_COUNT = 50
ABANK_COUNT = 119
LOGIN_PORT = 23000
SHARD_PORT = 23001
SHARD_IP = "127.0.0.1"

View File

@ -5,7 +5,7 @@ import (
"golang.org/x/crypto/bcrypt"
"github.com/CPunch/gopenfusion/protocol"
"github.com/CPunch/gopenfusion/core/protocol"
"github.com/blockloop/scan"
)

View File

@ -3,7 +3,7 @@ package db
import (
"database/sql"
"github.com/CPunch/gopenfusion/protocol"
"github.com/CPunch/gopenfusion/core/protocol"
)
type Inventory struct {

201
core/db/players.go Normal file
View File

@ -0,0 +1,201 @@
package db
import (
"database/sql"
"github.com/CPunch/gopenfusion/config"
"github.com/CPunch/gopenfusion/core"
"github.com/CPunch/gopenfusion/core/protocol"
"github.com/blockloop/scan"
)
// returns PlayerID, error
func (db *DBHandler) NewPlayer(AccountID int, FirstName, LastName string, slot int) (int, error) {
nameCheck := 1 // for now, we approve all names
QuestFlag := make([]byte, 128)
SkywayLocationFlag := make([]byte, 16)
FirstUseFlag := make([]byte, 16)
var PlayerID int
if err := db.Transaction(func(tx *sql.Tx) error {
// create player
row, err := tx.Query(
"INSERT INTO Players (AccountID, Slot, FirstName, LastName, XCoordinate, YCoordinate, ZCoordinate, Angle, HP, NameCheck, Quests, SkywayLocationFlag, FirstUseFlag) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING PlayerID",
AccountID, slot, FirstName, LastName, config.SPAWN_X, config.SPAWN_Y, config.SPAWN_Z, 0, config.GetMaxHP(1), nameCheck, QuestFlag, SkywayLocationFlag, FirstUseFlag)
if err != nil {
return err
}
if err := scan.Row(&PlayerID, row); err != nil {
return err
}
// create appearance
if _, err := tx.Exec("INSERT INTO Appearances (PlayerID) VALUES (?)", PlayerID); err != nil {
return err
}
return nil
}); err != nil {
return -1, nil
}
return PlayerID, nil
}
// TODO: should this operate on the raw packet? should we do validation here or prior?
func (db *DBHandler) FinishPlayer(character *protocol.SP_CL2LS_REQ_CHAR_CREATE, AccountId int) error {
return db.Transaction(func(tx *sql.Tx) error {
// update AppearanceFlag
_, err := tx.Exec("UPDATE Players SET AppearanceFlag = 1 WHERE PlayerID = ? AND AccountID = ? AND AppearanceFlag = 0", character.PCStyle.IPC_UID, AccountId)
if err != nil {
return err
}
// update Appearance
_, err = tx.Exec("UPDATE Appearances SET Body = ?, EyeColor = ?, FaceStyle = ?, Gender = ?, HairColor = ?, HairStyle = ?, Height = ?, SkinColor = ? WHERE PlayerID = ?",
character.PCStyle.IBody,
character.PCStyle.IEyeColor,
character.PCStyle.IFaceStyle,
character.PCStyle.IGender,
character.PCStyle.IHairColor,
character.PCStyle.IHairStyle,
character.PCStyle.IHeight,
character.PCStyle.ISkinColor,
character.PCStyle.IPC_UID)
if err != nil {
return err
}
// update Inventory
items := [3]int16{character.SOn_Item.IEquipUBID, character.SOn_Item.IEquipLBID, character.SOn_Item.IEquipFootID}
for i := 0; i < len(items); i++ {
_, err = tx.Exec("INSERT INTO Inventory (PlayerID, Slot, ID, Type, Opt) VALUES (?, ?, ?, ?, 1)", character.PCStyle.IPC_UID, i, items[i], i+1)
if err != nil {
return err
}
}
return nil
})
}
func (db *DBHandler) FinishTutorial(PlayerID, AccountID int) error {
_, err := db.Exec("UPDATE Players SET TutorialFlag = 1 WHERE PlayerID = ? AND AccountID = ? AND TutorialFlag = 0", PlayerID, AccountID)
if err != nil {
return err
}
// TODO: reference openfusion's finishTutorial for their academy specific patches
return nil
}
// returns the deleted Slot number
func (db *DBHandler) DeletePlayer(PlayerID, AccountID int) (int, error) {
row, err := db.Query("DELETE FROM Players WHERE AccountID = ? AND PlayerID = ? RETURNING Slot")
if err != nil {
return -1, err
}
var slot int
for row.Next() {
if err := row.Scan(&slot); err != nil {
return -1, err
}
}
return slot, nil
}
const (
QUERY_PLAYERS = `SELECT
p.PlayerID, p.AccountID, p.Slot, p.FirstName, p.LastName,
p.Level, p.Nano1, p.Nano2, p.Nano3,
p.AppearanceFlag, p.TutorialFlag, p.PayZoneFlag,
p.XCoordinate, p.YCoordinate, p.ZCoordinate, p.NameCheck,
p.Angle, p.HP, p.FusionMatter, p.Taros, p.Quests,
p.BatteryW, p.BatteryN, p.Mentor, p.WarpLocationFlag,
p.SkywayLocationFlag, p.CurrentMissionID, p.FirstUseFlag,
a.Body, a.EyeColor, a.FaceStyle, a.Gender, a.HairColor, a.HairStyle,
a.Height, a.SkinColor, acc.AccountLevel
FROM Players as p
INNER JOIN Appearances as a ON p.PlayerID = a.PlayerID
INNER JOIN Accounts as acc ON p.AccountID = acc.AccountID `
)
func (db *DBHandler) readPlayer(rows *sql.Rows) (*core.Player, error) {
plr := core.Player{}
if err := rows.Scan(
&plr.PlayerID, &plr.AccountID, &plr.Slot, &plr.PCStyle.SzFirstName, &plr.PCStyle.SzLastName,
&plr.Level, &plr.EquippedNanos[0], &plr.EquippedNanos[1], &plr.EquippedNanos[2],
&plr.PCStyle2.IAppearanceFlag, &plr.PCStyle2.ITutorialFlag, &plr.PCStyle2.IPayzoneFlag,
&plr.X, &plr.Y, &plr.Z, &plr.PCStyle.INameCheck,
&plr.Angle, &plr.HP, &plr.FusionMatter, &plr.Taros, &plr.Quests,
&plr.BatteryW, &plr.BatteryN, &plr.Mentor, &plr.WarpLocationFlag,
&plr.SkywayLocationFlag, &plr.CurrentMissionID, &plr.FirstUseFlag,
&plr.PCStyle.IBody, &plr.PCStyle.IEyeColor, &plr.PCStyle.IFaceStyle, &plr.PCStyle.IGender, &plr.PCStyle.IHairColor, &plr.PCStyle.IHairStyle,
&plr.PCStyle.IHeight, &plr.PCStyle.ISkinColor, &plr.AccountLevel); err != nil {
return nil, err
}
plr.PCStyle.IPC_UID = int64(plr.PlayerID)
inven, err := db.GetPlayerInventorySlots(plr.PlayerID, 0, config.AEQUIP_COUNT+config.AINVEN_COUNT+config.ABANK_COUNT)
if err != nil {
return nil, err
}
// populate player inven
for i, item := range inven {
if item.IID == 0 { // skip empty slots
continue
}
switch {
case i < config.AEQUIP_COUNT:
plr.Equip[i] = item
case i < config.AEQUIP_COUNT+config.AINVEN_COUNT:
plr.Inven[i-config.AEQUIP_COUNT] = item
default:
plr.Bank[i-config.AEQUIP_COUNT-config.AINVEN_COUNT] = item
}
}
return &plr, nil
}
func (db *DBHandler) GetPlayer(PlayerID int) (*core.Player, error) {
rows, err := db.Query(QUERY_PLAYERS+"WHERE p.PlayerID = ?", PlayerID)
if err != nil {
return nil, err
}
var plr *core.Player
for rows.Next() {
plr, err = db.readPlayer(rows)
if err != nil {
return nil, err
}
}
return plr, nil
}
func (db *DBHandler) GetPlayers(AccountID int) ([]core.Player, error) {
rows, err := db.Query(QUERY_PLAYERS+"WHERE p.AccountID = ?", AccountID)
if err != nil {
return nil, err
}
var plrs []core.Player
for rows.Next() {
plr, err := db.readPlayer(rows)
if err != nil {
return nil, err
}
plrs = append(plrs, *plr)
}
return plrs, nil
}

36
core/player.go Normal file
View File

@ -0,0 +1,36 @@
package core
import (
"github.com/CPunch/gopenfusion/config"
"github.com/CPunch/gopenfusion/core/protocol"
)
type Player struct {
PlayerID int
AccountID int
AccountLevel int
Slot int
PCStyle protocol.SPCStyle
PCStyle2 protocol.SPCStyle2
EquippedNanos [3]int
Nanos [config.NANO_COUNT]protocol.SNano
Equip [config.AEQUIP_COUNT]protocol.SItemBase
Inven [config.AINVEN_COUNT]protocol.SItemBase
Bank [config.ABANK_COUNT]protocol.SItemBase
SkywayLocationFlag []byte
FirstUseFlag []byte
Quests []byte
HP int
Level int
Taros int
FusionMatter int
Mentor int
X, Y, Z int
Angle int
BatteryN int
BatteryW int
WarpLocationFlag int
ActiveNanoSlotNum int
Fatigue int
CurrentMissionID int
}

View File

@ -7,7 +7,7 @@ import (
"log"
"net"
"github.com/CPunch/gopenfusion/protocol/pool"
"github.com/CPunch/gopenfusion/core/protocol/pool"
)
const (
@ -16,8 +16,8 @@ const (
)
type PeerHandler interface {
HandlePacket(client *CNPeer, typeID uint32, pkt Packet) error
Disconnect(client *CNPeer)
HandlePacket(peer *CNPeer, typeID uint32, pkt Packet) error
Disconnect(peer *CNPeer)
}
// CNPeer is a simple wrapper for net.Conn connections to send/recv packets over the Fusionfall packet protocol.

View File

@ -1,226 +0,0 @@
package db
import (
"database/sql"
"github.com/CPunch/gopenfusion/config"
"github.com/CPunch/gopenfusion/protocol"
"github.com/blockloop/scan"
)
type Player struct {
PlayerID int
AccountID int
FirstName string
LastName string
NameCheck int
Slot int
Created int
LastLogin int
Level int
Nano1 int
Nano2 int
Nano3 int
AppearanceFlag int
TutorialFlag int
PayZoneFlag int
XCoordinate int
YCoordinate int
ZCoordinate int
Angle int
HP int
FusionMatter int
Taros int
BatteryW int
BatteryN int
Mentor int
CurrentMissionID int
WarpLocationFlag int
SkywayLocationFlag []byte
FirstUseFlag []byte
Quests []byte
Body int /* Appearance tbl start */
EyeColor int
FaceStyle int
Gender int
HairColor int
HairStyle int
Height int
SkinColor int /* Appearance tbl end */
}
// returns PlayerID, error
func (db *DBHandler) NewPlayer(AccountID int, FirstName, LastName string, slot int) (int, error) {
nameCheck := 1 // for now, we approve all names
QuestFlag := make([]byte, 128)
SkywayLocationFlag := make([]byte, 16)
FirstUseFlag := make([]byte, 16)
var PlayerID int
if err := db.Transaction(func(tx *sql.Tx) error {
// create player
row, err := tx.Query(
"INSERT INTO Players (AccountID, Slot, FirstName, LastName, XCoordinate, YCoordinate, ZCoordinate, Angle, HP, NameCheck, Quests, SkywayLocationFlag, FirstUseFlag) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING PlayerID",
AccountID, slot, FirstName, LastName, config.SPAWN_X, config.SPAWN_Y, config.SPAWN_Z, 0, config.GetMaxHP(1), nameCheck, QuestFlag, SkywayLocationFlag, FirstUseFlag)
if err != nil {
return err
}
if err := scan.Row(&PlayerID, row); err != nil {
return err
}
// create appearance
if _, err := tx.Exec("INSERT INTO Appearances (PlayerID) VALUES (?)", PlayerID); err != nil {
return err
}
return nil
}); err != nil {
return -1, nil
}
return PlayerID, nil
}
// TODO: should this operate on the raw packet? should we do validation here or prior?
func (db *DBHandler) FinishPlayer(character *protocol.SP_CL2LS_REQ_CHAR_CREATE, AccountId int) error {
return db.Transaction(func(tx *sql.Tx) error {
// update AppearanceFlag
_, err := tx.Exec("UPDATE Players SET AppearanceFlag = 1 WHERE PlayerID = ? AND AccountID = ? AND AppearanceFlag = 0", character.PCStyle.IPC_UID, AccountId)
if err != nil {
return err
}
// update Appearance
_, err = tx.Exec("UPDATE Appearances SET Body = ?, EyeColor = ?, FaceStyle = ?, Gender = ?, HairColor = ?, HairStyle = ?, Height = ?, SkinColor = ? WHERE PlayerID = ?",
character.PCStyle.IBody,
character.PCStyle.IEyeColor,
character.PCStyle.IFaceStyle,
character.PCStyle.IGender,
character.PCStyle.IHairColor,
character.PCStyle.IHairStyle,
character.PCStyle.IHeight,
character.PCStyle.ISkinColor,
character.PCStyle.IPC_UID)
if err != nil {
return err
}
// update Inventory
items := [3]int16{character.SOn_Item.IEquipUBID, character.SOn_Item.IEquipLBID, character.SOn_Item.IEquipFootID}
for i := 0; i < len(items); i++ {
_, err = tx.Exec("INSERT INTO Inventory (PlayerID, Slot, ID, Type, Opt) VALUES (?, ?, ?, ?, 1)", character.PCStyle.IPC_UID, i, items[i], i+1)
if err != nil {
return err
}
}
return nil
})
}
func (db *DBHandler) FinishTutorial(PlayerID, AccountID int) error {
_, err := db.Exec("UPDATE Players SET TutorialFlag = 1 WHERE PlayerID = ? AND AccountID = ? AND TutorialFlag = 0", PlayerID, AccountID)
if err != nil {
return err
}
// TODO: reference openfusion's finishTutorial for their academy specific patches
return nil
}
// returns the deleted Slot number
func (db *DBHandler) DeletePlayer(PlayerID, AccountID int) (int, error) {
row, err := db.Query("DELETE FROM Players WHERE AccountID = ? AND PlayerID = ? RETURNING Slot")
if err != nil {
return -1, err
}
var slot int
for row.Next() {
if err := row.Scan(&slot); err != nil {
return -1, err
}
}
return slot, nil
}
func (db *DBHandler) GetPlayer(PlayerID int) (*Player, error) {
rows, err := db.Query(`SELECT
p.PlayerID, p.AccountID, p.Slot, p.FirstName, p.LastName,
p.Level, p.Nano1, p.Nano2, p.Nano3,
p.AppearanceFlag, p.TutorialFlag, p.PayZoneFlag,
p.XCoordinate, p.YCoordinate, p.ZCoordinate, p.NameCheck,
p.Angle, p.HP, p.FusionMatter, p.Taros, p.Quests,
p.BatteryW, p.BatteryN, p.Mentor, p.WarpLocationFlag,
p.SkywayLocationFlag, p.CurrentMissionID, p.FirstUseFlag,
a.Body, a.EyeColor, a.FaceStyle, a.Gender, a.HairColor, a.HairStyle,
a.Height, a.SkinColor
FROM Players as p
INNER JOIN Appearances as a ON p.PlayerID = a.PlayerID
WHERE p.PlayerID = ?`, PlayerID)
if err != nil {
return nil, err
}
var plr Player
for rows.Next() {
if err := rows.Scan(
&plr.PlayerID, &plr.AccountID, &plr.Slot, &plr.FirstName, &plr.LastName,
&plr.Level, &plr.Nano1, &plr.Nano2, &plr.Nano3,
&plr.AppearanceFlag, &plr.TutorialFlag, &plr.PayZoneFlag,
&plr.XCoordinate, &plr.YCoordinate, &plr.ZCoordinate, &plr.NameCheck,
&plr.Angle, &plr.HP, &plr.FusionMatter, &plr.Taros, &plr.Quests,
&plr.BatteryW, &plr.BatteryN, &plr.Mentor, &plr.WarpLocationFlag,
&plr.SkywayLocationFlag, &plr.CurrentMissionID, &plr.FirstUseFlag,
&plr.Body, &plr.EyeColor, &plr.FaceStyle, &plr.Gender, &plr.HairColor, &plr.HairStyle,
&plr.Height, &plr.SkinColor); err != nil {
return nil, err
}
}
return &plr, nil
}
func (db *DBHandler) GetPlayers(AccountID int) ([]Player, error) {
rows, err := db.Query(`SELECT
p.PlayerID, p.AccountID, p.Slot, p.FirstName, p.LastName,
p.Level, p.Nano1, p.Nano2, p.Nano3,
p.AppearanceFlag, p.TutorialFlag, p.PayZoneFlag,
p.XCoordinate, p.YCoordinate, p.ZCoordinate, p.NameCheck,
p.Angle, p.HP, p.FusionMatter, p.Taros, p.Quests,
p.BatteryW, p.BatteryN, p.Mentor, p.WarpLocationFlag,
p.SkywayLocationFlag, p.CurrentMissionID, p.FirstUseFlag,
a.Body, a.EyeColor, a.FaceStyle, a.Gender, a.HairColor, a.HairStyle,
a.Height, a.SkinColor
FROM Players as p
INNER JOIN Appearances as a ON p.PlayerID = a.PlayerID
WHERE p.AccountID = ?`, AccountID)
if err != nil {
return nil, err
}
var plrs []Player
for rows.Next() {
plr := Player{}
if err := rows.Scan(
&plr.PlayerID, &plr.AccountID, &plr.Slot, &plr.FirstName, &plr.LastName,
&plr.Level, &plr.Nano1, &plr.Nano2, &plr.Nano3,
&plr.AppearanceFlag, &plr.TutorialFlag, &plr.PayZoneFlag,
&plr.XCoordinate, &plr.YCoordinate, &plr.ZCoordinate, &plr.NameCheck,
&plr.Angle, &plr.HP, &plr.FusionMatter, &plr.Taros, &plr.Quests,
&plr.BatteryW, &plr.BatteryN, &plr.Mentor, &plr.WarpLocationFlag,
&plr.SkywayLocationFlag, &plr.CurrentMissionID, &plr.FirstUseFlag,
&plr.Body, &plr.EyeColor, &plr.FaceStyle, &plr.Gender, &plr.HairColor, &plr.HairStyle,
&plr.Height, &plr.SkinColor); err != nil {
return nil, err
}
plrs = append(plrs, plr)
}
return plrs, nil
}

View File

@ -4,7 +4,7 @@ import (
"log"
"github.com/CPunch/gopenfusion/config"
"github.com/CPunch/gopenfusion/db"
"github.com/CPunch/gopenfusion/core/db"
"github.com/CPunch/gopenfusion/server"
)

View File

@ -1,10 +1,25 @@
package server
import "github.com/CPunch/gopenfusion/protocol"
import "github.com/CPunch/gopenfusion/core/protocol"
func (server *ShardServer) RequestEnter(peer *protocol.CNPeer, pkt protocol.Packet) error {
func (server *ShardServer) RequestEnter(peer *protocol.CNPeer, pkt protocol.Packet) (retErr error) {
var enter protocol.SP_CL2FE_REQ_PC_ENTER
pkt.Decode(&enter)
loginData, err := server.CheckLogin(enter.IEnterSerialKey)
if err != nil {
// the error codes for P_FE2CL_REP_PC_ENTER_FAIL aren't referenced in the client :(
peer.Send(protocol.P_FE2CL_REP_PC_ENTER_FAIL, protocol.SP_FE2CL_REP_PC_ENTER_FAIL{})
return err
}
plr, err := server.dbHndlr.GetPlayer(int(loginData.PlayerID))
if err != nil {
peer.Send(protocol.P_FE2CL_REP_PC_ENTER_FAIL, protocol.SP_FE2CL_REP_PC_ENTER_FAIL{})
return err
}
// TODO
_ = plr
return nil
}

View File

@ -6,9 +6,8 @@ import (
"time"
"github.com/CPunch/gopenfusion/config"
"github.com/CPunch/gopenfusion/db"
"github.com/CPunch/gopenfusion/protocol"
"github.com/CPunch/gopenfusion/util"
"github.com/CPunch/gopenfusion/core/db"
"github.com/CPunch/gopenfusion/core/protocol"
)
const (
@ -113,15 +112,14 @@ func (server *LoginServer) Login(peer *protocol.CNPeer, pkt protocol.Packet) err
// build character list
charInfo := [4]protocol.SP_LS2CL_REP_CHAR_INFO{}
for i, plr := range plrs {
PCStyle, PCStyle2 := util.Player2PCStyle(&plr)
info := protocol.SP_LS2CL_REP_CHAR_INFO{
ISlot: int8(plr.Slot),
ILevel: int16(plr.Level),
SPC_Style: PCStyle,
SPC_Style2: PCStyle2,
IX: int32(plr.XCoordinate),
IY: int32(plr.YCoordinate),
IZ: int32(plr.ZCoordinate),
SPC_Style: plr.PCStyle,
SPC_Style2: plr.PCStyle2,
IX: int32(plr.X),
IY: int32(plr.Y),
IZ: int32(plr.Z),
}
AEquip, err := server.dbHndlr.GetPlayerInventorySlots(plr.PlayerID, 0, config.AEQUIP_COUNT-1)
@ -227,11 +225,10 @@ func (server *LoginServer) CharacterCreate(peer *protocol.CNPeer, pkt protocol.P
return SendFail(peer)
}
PCStyle, PCStyle2 := util.Player2PCStyle(plr)
return peer.Send(protocol.P_LS2CL_REP_CHAR_CREATE_SUCC, protocol.SP_LS2CL_REP_CHAR_CREATE_SUCC{
ILevel: int16(plr.Level),
SPC_Style: PCStyle,
SPC_Style2: PCStyle2,
SPC_Style: plr.PCStyle,
SPC_Style2: plr.PCStyle2,
SOn_Item: charPkt.SOn_Item, // if items were faked, we don't really care since the db only stores the sanitized fields
})
}

View File

@ -6,8 +6,8 @@ import (
"net"
"sync"
"github.com/CPunch/gopenfusion/db"
"github.com/CPunch/gopenfusion/protocol"
"github.com/CPunch/gopenfusion/core/db"
"github.com/CPunch/gopenfusion/core/protocol"
)
type LoginServer struct {

View File

@ -7,8 +7,9 @@ import (
"sync"
"time"
"github.com/CPunch/gopenfusion/db"
"github.com/CPunch/gopenfusion/protocol"
"github.com/CPunch/gopenfusion/core"
"github.com/CPunch/gopenfusion/core/db"
"github.com/CPunch/gopenfusion/core/protocol"
)
type LoginMetadata struct {
@ -22,7 +23,7 @@ type ShardServer struct {
port int
dbHndlr *db.DBHandler
packetHandlers map[uint32]PacketHandler
peers sync.Map // [*protocol.CNPeer]*db.Player
peers sync.Map // [*protocol.CNPeer]*core.Player
loginMetadataQueue sync.Map // [int64]*LoginMetadata w/ int64 = serialKey
}
@ -88,19 +89,19 @@ func (server *ShardServer) Connect(peer *protocol.CNPeer) {
server.peers.Store(peer, nil)
}
func (server *ShardServer) JoinPlayer(peer *protocol.CNPeer, player *db.Player) {
func (server *ShardServer) JoinPlayer(peer *protocol.CNPeer, player *core.Player) {
server.peers.Store(peer, player)
}
// Simple wrapper for server.peers.Range, if f returns false the iteration is stopped.
func (server *ShardServer) RangePeers(f func(peer *protocol.CNPeer, player *db.Player) bool) {
func (server *ShardServer) RangePeers(f func(peer *protocol.CNPeer, player *core.Player) bool) {
server.peers.Range(func(key, value any) bool { // simple wrapper to cast the datatypes
peer, ok := key.(*protocol.CNPeer)
if !ok { // this should never happen
panic(fmt.Errorf("ShardServer.peers has an invalid key: peers[%#v] = %#v", key, value))
}
player, ok := value.(*db.Player)
player, ok := value.(*core.Player)
if !ok { // this should also never happen
panic(fmt.Errorf("ShardServer.peers has an invalid value: peers[%#v] = %#v", key, value))
}

View File

@ -1,7 +1,7 @@
package server
import (
"github.com/CPunch/gopenfusion/protocol"
"github.com/CPunch/gopenfusion/core/protocol"
)
type PacketHandler func(peer *protocol.CNPeer, pkt protocol.Packet) error

View File

@ -1,28 +0,0 @@
package util
import (
"github.com/CPunch/gopenfusion/db"
"github.com/CPunch/gopenfusion/protocol"
)
func Player2PCStyle(plr *db.Player) (protocol.SPCStyle, protocol.SPCStyle2) {
return protocol.SPCStyle{
IPC_UID: int64(plr.PlayerID),
INameCheck: int8(plr.NameCheck),
SzFirstName: plr.FirstName,
SzLastName: plr.LastName,
IGender: int8(plr.Gender),
IFaceStyle: int8(plr.FaceStyle),
IHairStyle: int8(plr.HairStyle),
IHairColor: int8(plr.HairColor),
ISkinColor: int8(plr.SkinColor),
IEyeColor: int8(plr.EyeColor),
IHeight: int8(plr.Height),
IBody: int8(plr.Body),
},
protocol.SPCStyle2{
IAppearanceFlag: int8(plr.AppearanceFlag),
ITutorialFlag: int8(plr.TutorialFlag),
IPayzoneFlag: int8(plr.PayZoneFlag),
}
}