mirror of
https://github.com/CPunch/gopenfusion.git
synced 2024-11-21 23:10:06 +00:00
Switched to redis/postgres, major refactoring
- loginMetadata is passed to shards through redis now - shards announce they're alive via redis.AnnounceShard() which just populates a hashset keyed 'shards' - login servers grab the 'shards' hashset and randomly picks a shard to pass the player to (for now) - ./service shard && ./service login - Many new environment variables, check config/config.go for more info. or for a tl;dr just read the Dockerfile for the required ones - Shard and login services now run in different processes ! (and containers?? wooaaah)
This commit is contained in:
parent
983588b6c9
commit
d7445e0f0f
2
build.sh
2
build.sh
@ -1,5 +1,5 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
mkdir -p bin
|
mkdir -p bin
|
||||||
CGO_ENABLED=0 GOOS=linux go build -o ./bin/server
|
CGO_ENABLED=0 GOOS=linux go build -o ./bin/server ./cmd
|
||||||
echo 'Done'
|
echo 'Done'
|
42
cmd/login.go
Normal file
42
cmd/login.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/CPunch/gopenfusion/config"
|
||||||
|
"github.com/CPunch/gopenfusion/login"
|
||||||
|
"github.com/google/subcommands"
|
||||||
|
)
|
||||||
|
|
||||||
|
type loginCommand struct {
|
||||||
|
port int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *loginCommand) Name() string {
|
||||||
|
return "login"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *loginCommand) Synopsis() string {
|
||||||
|
return "Starts login service"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *loginCommand) Usage() string {
|
||||||
|
return s.Name() + " - " + s.Synopsis() + ":\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *loginCommand) SetFlags(f *flag.FlagSet) {
|
||||||
|
f.IntVar(&s.port, "port", config.LOGIN_PORT, "Hosts the service on this port")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *loginCommand) Execute(ctx context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
|
||||||
|
loginServer, err := login.NewLoginServer(dbHndlr, redisHndlr, s.port)
|
||||||
|
if err != nil {
|
||||||
|
log.Panicf("failed to create shard server: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
loginServer.Start()
|
||||||
|
|
||||||
|
return subcommands.ExitSuccess
|
||||||
|
}
|
43
cmd/main.go
Normal file
43
cmd/main.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/CPunch/gopenfusion/config"
|
||||||
|
"github.com/CPunch/gopenfusion/core/db"
|
||||||
|
"github.com/CPunch/gopenfusion/core/redis"
|
||||||
|
|
||||||
|
"github.com/google/subcommands"
|
||||||
|
)
|
||||||
|
|
||||||
|
var dbHndlr *db.DBHandler
|
||||||
|
var redisHndlr *redis.RedisHandler
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
subcommands.Register(subcommands.HelpCommand(), "")
|
||||||
|
subcommands.Register(subcommands.FlagsCommand(), "")
|
||||||
|
subcommands.Register(subcommands.CommandsCommand(), "")
|
||||||
|
subcommands.Register(&shardCommand{}, "")
|
||||||
|
subcommands.Register(&loginCommand{}, "")
|
||||||
|
|
||||||
|
var err error
|
||||||
|
dbHndlr, err = db.OpenPostgresDB(config.GetDBAddr())
|
||||||
|
if err != nil {
|
||||||
|
log.Panicf("failed to open db: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = dbHndlr.Setup(); err != nil {
|
||||||
|
log.Panicf("failed to setup db: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
redisHndlr, err = redis.OpenRedis(config.GetRedisAddr())
|
||||||
|
if err != nil {
|
||||||
|
log.Panicf("failed to open redis: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
flag.Parse()
|
||||||
|
os.Exit(int(subcommands.Execute(context.Background())))
|
||||||
|
}
|
42
cmd/shard.go
Normal file
42
cmd/shard.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/CPunch/gopenfusion/config"
|
||||||
|
"github.com/CPunch/gopenfusion/shard"
|
||||||
|
"github.com/google/subcommands"
|
||||||
|
)
|
||||||
|
|
||||||
|
type shardCommand struct {
|
||||||
|
port int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *shardCommand) Name() string {
|
||||||
|
return "shard"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *shardCommand) Synopsis() string {
|
||||||
|
return "Starts shard service"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *shardCommand) Usage() string {
|
||||||
|
return s.Name() + " - " + s.Synopsis() + ":\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *shardCommand) SetFlags(f *flag.FlagSet) {
|
||||||
|
f.IntVar(&s.port, "port", config.SHARD_PORT, "Hosts the service on this port")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *shardCommand) Execute(ctx context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
|
||||||
|
shardServer, err := shard.NewShardServer(dbHndlr, redisHndlr, s.port)
|
||||||
|
if err != nil {
|
||||||
|
log.Panicf("failed to create shard server: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
shardServer.Start()
|
||||||
|
|
||||||
|
return subcommands.ExitSuccess
|
||||||
|
}
|
45
compose.yaml
45
compose.yaml
@ -1,19 +1,42 @@
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
# redis:
|
postgresql:
|
||||||
# image: 'redislabs/redismod'
|
image: 'postgres:15'
|
||||||
# ports:
|
environment:
|
||||||
# - '6379:6379'
|
- POSTGRES_USER=gopenfusion
|
||||||
|
- POSTGRES_DB=gopenfusion
|
||||||
|
- POSTGRES_PASSWORD=gopenfusion
|
||||||
|
redis:
|
||||||
|
image: 'redis:7-alpine'
|
||||||
login:
|
login:
|
||||||
restart: on-failure
|
restart: on-failure
|
||||||
build: .
|
build: .
|
||||||
hostname: login
|
hostname: login
|
||||||
|
command: login
|
||||||
|
environment:
|
||||||
|
- DB_ADDR=postgresql:5432
|
||||||
|
- DB_USER=gopenfusion
|
||||||
|
- DB_PASS=gopenfusion
|
||||||
|
- DB_NAME=gopenfusion
|
||||||
|
- REDIS_ADDR=redis:6379
|
||||||
|
ports:
|
||||||
|
- '23000:23000'
|
||||||
|
links:
|
||||||
|
- postgresql
|
||||||
|
- redis
|
||||||
|
shard0:
|
||||||
|
restart: on-failure
|
||||||
|
build: .
|
||||||
|
hostname: shard
|
||||||
|
command: shard
|
||||||
|
environment:
|
||||||
|
- DB_ADDR=postgresql:5432
|
||||||
|
- DB_USER=gopenfusion
|
||||||
|
- DB_PASS=gopenfusion
|
||||||
|
- DB_NAME=gopenfusion
|
||||||
|
- REDIS_ADDR=redis:6379
|
||||||
ports:
|
ports:
|
||||||
- '23001:23001'
|
- '23001:23001'
|
||||||
- '23000:23000'
|
links:
|
||||||
# shard0:
|
- postgresql
|
||||||
# restart: on-failure
|
- redis
|
||||||
# build: .
|
|
||||||
# hostname: shard0
|
|
||||||
# ports:
|
|
||||||
# - '23001:23001'
|
|
||||||
|
@ -1,5 +1,21 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
Available environment variables:
|
||||||
|
REDIS_ADDR
|
||||||
|
REDIS_USER
|
||||||
|
REDIS_PASS
|
||||||
|
DB_ADDR
|
||||||
|
DB_USER
|
||||||
|
DB_PASS
|
||||||
|
ANNOUNCE_IP
|
||||||
|
*/
|
||||||
|
|
||||||
const (
|
const (
|
||||||
AEQUIP_COUNT = 9
|
AEQUIP_COUNT = 9
|
||||||
AINVEN_COUNT = 50
|
AINVEN_COUNT = 50
|
||||||
@ -15,9 +31,49 @@ var (
|
|||||||
|
|
||||||
LOGIN_PORT = 23000
|
LOGIN_PORT = 23000
|
||||||
SHARD_PORT = 23001
|
SHARD_PORT = 23001
|
||||||
SHARD_IP = "127.0.0.1"
|
|
||||||
|
LOGIN_TIMEOUT = time.Second * 30
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func getEnv(key string, fallback string) string {
|
||||||
|
if value, ok := os.LookupEnv(key); ok {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
|
||||||
func GetMaxHP(level int) int {
|
func GetMaxHP(level int) int {
|
||||||
return (925 + 75*(level))
|
return (925 + 75*(level))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetRedisAddr() string {
|
||||||
|
return getEnv("REDIS_ADDR", "localhost:6379")
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetRedisCredentials() func() (string, string) {
|
||||||
|
return func() (string, string) {
|
||||||
|
return getEnv("REDIS_USER", ""), getEnv("REDIS_PASS", "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDBName() string {
|
||||||
|
return getEnv("DB_NAME", "postgres")
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDBAddr() string {
|
||||||
|
return getEnv("DB_ADDR", "localhost:5432")
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDBUser() string {
|
||||||
|
return getEnv("DB_USER", "postgres")
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDBPass() string {
|
||||||
|
return getEnv("DB_PASS", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// needed for shard
|
||||||
|
func GetAnnounceIP() string {
|
||||||
|
return getEnv("ANNOUNCE_IP", "127.0.0.1")
|
||||||
|
}
|
||||||
|
@ -2,24 +2,25 @@ package db
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
|
||||||
"github.com/CPunch/gopenfusion/core/protocol"
|
"github.com/CPunch/gopenfusion/core/protocol"
|
||||||
"github.com/blockloop/scan"
|
"github.com/georgysavva/scany/v2/sqlscan"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Account struct {
|
type Account struct {
|
||||||
AccountID int
|
AccountID int `db:"accountid"`
|
||||||
Login string
|
Login string `db:"login"`
|
||||||
Password string
|
Password string `db:"password"`
|
||||||
Selected int
|
Selected int `db:"selected"`
|
||||||
AccountLevel int
|
AccountLevel int `db:"accountlevel"`
|
||||||
Created int
|
Created int `db:"created"`
|
||||||
LastLogin int
|
LastLogin int `db:"lastlogin"`
|
||||||
BannedUntil int
|
BannedUntil int `db:"banneduntil"`
|
||||||
BannedSince int
|
BannedSince int `db:"bannedsince"`
|
||||||
BanReason string
|
BanReason string `db:"banreason"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DBHandler) NewAccount(Login, Password string) (*Account, error) {
|
func (db *DBHandler) NewAccount(Login, Password string) (*Account, error) {
|
||||||
@ -28,13 +29,14 @@ func (db *DBHandler) NewAccount(Login, Password string) (*Account, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
row, err := db.Query("INSERT INTO Accounts (Login, Password, AccountLevel) VALUES(?, ?, ?) RETURNING *", Login, hash, protocol.CN_ACCOUNT_LEVEL__USER)
|
row, err := db.Query("INSERT INTO Accounts (Login, Password, AccountLevel) VALUES($1, $2, $3) RETURNING *", Login, hash, protocol.CN_ACCOUNT_LEVEL__USER)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var account Account
|
var account Account
|
||||||
if err := scan.Row(&account, row); err != nil {
|
row.Next()
|
||||||
|
if err := sqlscan.ScanRow(&account, row); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,13 +49,15 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (db *DBHandler) TryLogin(Login, Password string) (*Account, error) {
|
func (db *DBHandler) TryLogin(Login, Password string) (*Account, error) {
|
||||||
row, err := db.Query("SELECT * FROM Accounts WHERE Login=?", Login)
|
row, err := db.Query("SELECT * FROM Accounts WHERE Login=$1", Login)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var account Account
|
var account Account
|
||||||
if err := scan.Row(&account, row); err != nil {
|
row.Next()
|
||||||
|
if err := sqlscan.ScanRow(&account, row); err != nil {
|
||||||
|
log.Printf("Error scanning row: %v", err)
|
||||||
return nil, LoginErrorInvalidID
|
return nil, LoginErrorInvalidID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,17 +7,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Inventory struct {
|
type Inventory struct {
|
||||||
PlayerID int
|
PlayerID int `db:"playerid"`
|
||||||
Slot int
|
Slot int `db:"slot"`
|
||||||
ID int
|
ID int `db:"id"`
|
||||||
Type int
|
Type int `db:"type"`
|
||||||
Opt int
|
Opt int `db:"opt"`
|
||||||
TimeLimit int
|
TimeLimit int `db:"timelimit"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// start && end are both inclusive
|
// start && end are both inclusive
|
||||||
func (db *DBHandler) GetPlayerInventorySlots(PlayerID int, start int, end int) ([]protocol.SItemBase, error) {
|
func (db *DBHandler) GetPlayerInventorySlots(PlayerID int, start int, end int) ([]protocol.SItemBase, error) {
|
||||||
rows, err := db.Query("SELECT Slot, Type, ID, Opt, TimeLimit FROM Inventory WHERE Slot BETWEEN ? AND ? AND PlayerID = ?", start, end, PlayerID)
|
rows, err := db.Query("SELECT Slot, Type, ID, Opt, TimeLimit FROM Inventory WHERE Slot BETWEEN $1 AND $2 AND PlayerID = $3", start, end, PlayerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -42,7 +42,7 @@ func (db *DBHandler) GetPlayerInventorySlots(PlayerID int, start int, end int) (
|
|||||||
func (db *DBHandler) SetPlayerInventorySlots(PlayerID int, start int, items []protocol.SItemBase) error {
|
func (db *DBHandler) SetPlayerInventorySlots(PlayerID int, start int, items []protocol.SItemBase) error {
|
||||||
return db.Transaction(func(tx *sql.Tx) error {
|
return db.Transaction(func(tx *sql.Tx) error {
|
||||||
// delete inventory slots
|
// delete inventory slots
|
||||||
_, err := db.Exec("DELETE FROM Inventory WHERE Slot BETWEEN ? AND ? AND PlayerID = ?", start, start+len(items)-1, PlayerID)
|
_, err := db.Exec("DELETE FROM Inventory WHERE Slot BETWEEN $1 AND $2 AND PlayerID = $3", start, start+len(items)-1, PlayerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -50,7 +50,7 @@ func (db *DBHandler) SetPlayerInventorySlots(PlayerID int, start int, items []pr
|
|||||||
// insert inventory
|
// insert inventory
|
||||||
for i, item := range items {
|
for i, item := range items {
|
||||||
if item.IID != 0 {
|
if item.IID != 0 {
|
||||||
_, err := db.Exec("INSERT INTO Inventory (PlayerID, Slot, ID, Type, Opt, TimeLimit) VALUES (?, ?, ?, ?, ?, ?)", PlayerID, start+i, item.IID, item.IType, item.IOpt, item.ITimeLimit)
|
_, err := db.Exec("INSERT INTO Inventory (PlayerID, Slot, ID, Type, Opt, TimeLimit) VALUES ($1, $2, $3, $4, $5, $6)", PlayerID, start+i, item.IID, item.IType, item.IOpt, item.ITimeLimit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,31 @@
|
|||||||
-- this file has been lifted from https://github.com/OpenFusionProject/OpenFusion/blob/master/sql/tables.sql
|
-- this file has been lifted from https://github.com/OpenFusionProject/OpenFusion/bytea/master/sql/tables.sql
|
||||||
-- all credit to original contributors!
|
-- all credit to original contributors!
|
||||||
|
|
||||||
|
CREATE EXTENSION IF NOT EXISTS citext;
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS Accounts (
|
CREATE TABLE IF NOT EXISTS Accounts (
|
||||||
AccountID INTEGER NOT NULL,
|
AccountID SERIAL NOT NULL,
|
||||||
Login TEXT NOT NULL UNIQUE COLLATE NOCASE,
|
Login CITEXT NOT NULL UNIQUE,
|
||||||
Password TEXT NOT NULL,
|
Password TEXT NOT NULL,
|
||||||
Selected INTEGER DEFAULT 1 NOT NULL,
|
Selected INTEGER DEFAULT 1 NOT NULL,
|
||||||
AccountLevel INTEGER NOT NULL,
|
AccountLevel INTEGER NOT NULL,
|
||||||
Created INTEGER DEFAULT (strftime('%s', 'now')) NOT NULL,
|
Created INTEGER DEFAULT (extract(EPOCH FROM current_time)) NOT NULL,
|
||||||
LastLogin INTEGER DEFAULT (strftime('%s', 'now')) NOT NULL,
|
LastLogin INTEGER DEFAULT (extract(EPOCH FROM current_time)) NOT NULL,
|
||||||
BannedUntil INTEGER DEFAULT 0 NOT NULL,
|
BannedUntil INTEGER DEFAULT 0 NOT NULL,
|
||||||
BannedSince INTEGER DEFAULT 0 NOT NULL,
|
BannedSince INTEGER DEFAULT 0 NOT NULL,
|
||||||
BanReason TEXT DEFAULT '' NOT NULL,
|
BanReason TEXT DEFAULT '' NOT NULL,
|
||||||
PRIMARY KEY(AccountID AUTOINCREMENT)
|
PRIMARY KEY(AccountID)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS Players (
|
CREATE TABLE IF NOT EXISTS Players (
|
||||||
PlayerID INTEGER NOT NULL,
|
PlayerID SERIAL NOT NULL,
|
||||||
AccountID INTEGER NOT NULL,
|
AccountID INTEGER NOT NULL,
|
||||||
FirstName TEXT NOT NULL COLLATE NOCASE,
|
FirstName CITEXT NOT NULL,
|
||||||
LastName TEXT NOT NULL COLLATE NOCASE,
|
LastName CITEXT NOT NULL,
|
||||||
NameCheck INTEGER NOT NULL,
|
NameCheck INTEGER NOT NULL,
|
||||||
Slot INTEGER NOT NULL,
|
Slot INTEGER NOT NULL,
|
||||||
Created INTEGER DEFAULT (strftime('%s', 'now')) NOT NULL,
|
Created INTEGER DEFAULT (extract(EPOCH FROM current_time)) NOT NULL,
|
||||||
LastLogin INTEGER DEFAULT (strftime('%s', 'now')) NOT NULL,
|
LastLogin INTEGER DEFAULT (extract(EPOCH FROM current_time)) NOT NULL,
|
||||||
Level INTEGER DEFAULT 1 NOT NULL,
|
Level INTEGER DEFAULT 1 NOT NULL,
|
||||||
Nano1 INTEGER DEFAULT 0 NOT NULL,
|
Nano1 INTEGER DEFAULT 0 NOT NULL,
|
||||||
Nano2 INTEGER DEFAULT 0 NOT NULL,
|
Nano2 INTEGER DEFAULT 0 NOT NULL,
|
||||||
@ -43,10 +45,10 @@ CREATE TABLE IF NOT EXISTS Players (
|
|||||||
Mentor INTEGER DEFAULT 5 NOT NULL,
|
Mentor INTEGER DEFAULT 5 NOT NULL,
|
||||||
CurrentMissionID INTEGER DEFAULT 0 NOT NULL,
|
CurrentMissionID INTEGER DEFAULT 0 NOT NULL,
|
||||||
WarpLocationFlag INTEGER DEFAULT 0 NOT NULL,
|
WarpLocationFlag INTEGER DEFAULT 0 NOT NULL,
|
||||||
SkywayLocationFlag BLOB NOT NULL,
|
SkywayLocationFlag bytea NOT NULL,
|
||||||
FirstUseFlag BLOB NOT NULL,
|
FirstUseFlag bytea NOT NULL,
|
||||||
Quests BLOB NOT NULL,
|
Quests bytea NOT NULL,
|
||||||
PRIMARY KEY(PlayerID AUTOINCREMENT),
|
PRIMARY KEY(PlayerID),
|
||||||
FOREIGN KEY(AccountID) REFERENCES Accounts(AccountID) ON DELETE CASCADE,
|
FOREIGN KEY(AccountID) REFERENCES Accounts(AccountID) ON DELETE CASCADE,
|
||||||
UNIQUE (AccountID, Slot),
|
UNIQUE (AccountID, Slot),
|
||||||
UNIQUE (FirstName, LastName)
|
UNIQUE (FirstName, LastName)
|
||||||
@ -123,8 +125,8 @@ CREATE TABLE IF NOT EXISTS EmailData (
|
|||||||
ReadFlag INTEGER NOT NULL,
|
ReadFlag INTEGER NOT NULL,
|
||||||
ItemFlag INTEGER NOT NULL,
|
ItemFlag INTEGER NOT NULL,
|
||||||
SenderID INTEGER NOT NULL,
|
SenderID INTEGER NOT NULL,
|
||||||
SenderFirstName TEXT NOT NULL COLLATE NOCASE,
|
SenderFirstName CITEXT NOT NULL,
|
||||||
SenderLastName TEXT NOT NULL COLLATE NOCASE,
|
SenderLastName CITEXT NOT NULL,
|
||||||
SubjectLine TEXT NOT NULL,
|
SubjectLine TEXT NOT NULL,
|
||||||
MsgBody TEXT NOT NULL,
|
MsgBody TEXT NOT NULL,
|
||||||
Taros INTEGER NOT NULL,
|
Taros INTEGER NOT NULL,
|
||||||
|
@ -19,19 +19,19 @@ func (db *DBHandler) NewPlayer(AccountID int, FirstName, LastName string, slot i
|
|||||||
var PlayerID int
|
var PlayerID int
|
||||||
if err := db.Transaction(func(tx *sql.Tx) error {
|
if err := db.Transaction(func(tx *sql.Tx) error {
|
||||||
// create player
|
// create player
|
||||||
row, err := tx.Query(
|
rows, err := tx.Query(
|
||||||
"INSERT INTO Players (AccountID, Slot, FirstName, LastName, XCoordinate, YCoordinate, ZCoordinate, Angle, HP, NameCheck, Quests, SkywayLocationFlag, FirstUseFlag) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING PlayerID",
|
"INSERT INTO Players (AccountID, Slot, FirstName, LastName, XCoordinate, YCoordinate, ZCoordinate, Angle, HP, NameCheck, Quests, SkywayLocationFlag, FirstUseFlag) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) RETURNING PlayerID",
|
||||||
AccountID, slot, FirstName, LastName, config.SPAWN_X, config.SPAWN_Y, config.SPAWN_Z, 0, config.GetMaxHP(1), nameCheck, QuestFlag, SkywayLocationFlag, FirstUseFlag)
|
AccountID, slot, FirstName, LastName, config.SPAWN_X, config.SPAWN_Y, config.SPAWN_Z, 0, config.GetMaxHP(1), nameCheck, QuestFlag, SkywayLocationFlag, FirstUseFlag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := scan.Row(&PlayerID, row); err != nil {
|
if err := scan.Row(&PlayerID, rows); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// create appearance
|
// create appearance
|
||||||
if _, err := tx.Exec("INSERT INTO Appearances (PlayerID) VALUES (?)", PlayerID); err != nil {
|
if _, err := tx.Exec("INSERT INTO Appearances (PlayerID) VALUES ($1)", PlayerID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,13 +47,13 @@ func (db *DBHandler) NewPlayer(AccountID int, FirstName, LastName string, slot i
|
|||||||
func (db *DBHandler) FinishPlayer(character *protocol.SP_CL2LS_REQ_CHAR_CREATE, AccountId int) error {
|
func (db *DBHandler) FinishPlayer(character *protocol.SP_CL2LS_REQ_CHAR_CREATE, AccountId int) error {
|
||||||
return db.Transaction(func(tx *sql.Tx) error {
|
return db.Transaction(func(tx *sql.Tx) error {
|
||||||
// update AppearanceFlag
|
// update AppearanceFlag
|
||||||
_, err := tx.Exec("UPDATE Players SET AppearanceFlag = 1 WHERE PlayerID = ? AND AccountID = ? AND AppearanceFlag = 0", character.PCStyle.IPC_UID, AccountId)
|
_, err := tx.Exec("UPDATE Players SET AppearanceFlag = 1 WHERE PlayerID = $1 AND AccountID = $2 AND AppearanceFlag = 0", character.PCStyle.IPC_UID, AccountId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// update Appearance
|
// update Appearance
|
||||||
_, err = tx.Exec("UPDATE Appearances SET Body = ?, EyeColor = ?, FaceStyle = ?, Gender = ?, HairColor = ?, HairStyle = ?, Height = ?, SkinColor = ? WHERE PlayerID = ?",
|
_, err = tx.Exec("UPDATE Appearances SET Body = $1, EyeColor = $2, FaceStyle = $3, Gender = $4, HairColor = $5, HairStyle = $6, Height = $7, SkinColor = $8 WHERE PlayerID = $9",
|
||||||
character.PCStyle.IBody,
|
character.PCStyle.IBody,
|
||||||
character.PCStyle.IEyeColor,
|
character.PCStyle.IEyeColor,
|
||||||
character.PCStyle.IFaceStyle,
|
character.PCStyle.IFaceStyle,
|
||||||
@ -70,7 +70,7 @@ func (db *DBHandler) FinishPlayer(character *protocol.SP_CL2LS_REQ_CHAR_CREATE,
|
|||||||
// update Inventory
|
// update Inventory
|
||||||
items := [3]int16{character.SOn_Item.IEquipUBID, character.SOn_Item.IEquipLBID, character.SOn_Item.IEquipFootID}
|
items := [3]int16{character.SOn_Item.IEquipUBID, character.SOn_Item.IEquipLBID, character.SOn_Item.IEquipFootID}
|
||||||
for i := 0; i < len(items); i++ {
|
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)
|
_, err = tx.Exec("INSERT INTO Inventory (PlayerID, Slot, ID, Type, Opt) VALUES ($1, $2, $3, $4, 1)", character.PCStyle.IPC_UID, i, items[i], i+1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -81,7 +81,7 @@ func (db *DBHandler) FinishPlayer(character *protocol.SP_CL2LS_REQ_CHAR_CREATE,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (db *DBHandler) FinishTutorial(PlayerID, AccountID int) error {
|
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)
|
_, err := db.Exec("UPDATE Players SET TutorialFlag = 1 WHERE PlayerID = $1 AND AccountID = $2 AND TutorialFlag = 0", PlayerID, AccountID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -92,16 +92,14 @@ func (db *DBHandler) FinishTutorial(PlayerID, AccountID int) error {
|
|||||||
|
|
||||||
// returns the deleted Slot number
|
// returns the deleted Slot number
|
||||||
func (db *DBHandler) DeletePlayer(PlayerID, AccountID int) (int, error) {
|
func (db *DBHandler) DeletePlayer(PlayerID, AccountID int) (int, error) {
|
||||||
row, err := db.Query("DELETE FROM Players WHERE AccountID = ? AND PlayerID = ? RETURNING Slot")
|
row, err := db.Query("DELETE FROM Players WHERE AccountID = $1 AND PlayerID = $2 RETURNING Slot")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var slot int
|
var slot int
|
||||||
for row.Next() {
|
if err := row.Scan(&slot); err != nil {
|
||||||
if err := row.Scan(&slot); err != nil {
|
return -1, err
|
||||||
return -1, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return slot, nil
|
return slot, nil
|
||||||
@ -165,7 +163,7 @@ func (db *DBHandler) readPlayer(rows *sql.Rows) (*core.Player, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (db *DBHandler) GetPlayer(PlayerID int) (*core.Player, error) {
|
func (db *DBHandler) GetPlayer(PlayerID int) (*core.Player, error) {
|
||||||
rows, err := db.Query(QUERY_PLAYERS+"WHERE p.PlayerID = ?", PlayerID)
|
rows, err := db.Query(QUERY_PLAYERS+"WHERE p.PlayerID = $1", PlayerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -182,7 +180,7 @@ func (db *DBHandler) GetPlayer(PlayerID int) (*core.Player, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (db *DBHandler) GetPlayers(AccountID int) ([]core.Player, error) {
|
func (db *DBHandler) GetPlayers(AccountID int) ([]core.Player, error) {
|
||||||
rows, err := db.Query(QUERY_PLAYERS+"WHERE p.AccountID = ?", AccountID)
|
rows, err := db.Query(QUERY_PLAYERS+"WHERE p.AccountID = $1", AccountID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,8 @@ import (
|
|||||||
_ "embed"
|
_ "embed"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
_ "github.com/glebarez/go-sqlite"
|
"github.com/CPunch/gopenfusion/config"
|
||||||
|
_ "github.com/lib/pq"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DBHandler struct {
|
type DBHandler struct {
|
||||||
@ -20,10 +21,10 @@ type DBHandler struct {
|
|||||||
//go:embed migrations/new.sql
|
//go:embed migrations/new.sql
|
||||||
var createDBQuery string
|
var createDBQuery string
|
||||||
|
|
||||||
func OpenLiteDB(dbPath string) (*DBHandler, error) {
|
func OpenPostgresDB(dbAddr string) (*DBHandler, error) {
|
||||||
sqliteFmt := fmt.Sprintf("%s", dbPath)
|
fmt := fmt.Sprintf("postgresql://%s:%s@%s/%s?sslmode=disable", config.GetDBUser(), config.GetDBPass(), dbAddr, config.GetDBName())
|
||||||
|
|
||||||
db, err := sql.Open("sqlite", sqliteFmt)
|
db, err := sql.Open("postgres", fmt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
112
core/redis/redis.go
Normal file
112
core/redis/redis.go
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
package redis
|
||||||
|
|
||||||
|
/*
|
||||||
|
used for state management between shard and login servers
|
||||||
|
*/
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/CPunch/gopenfusion/config"
|
||||||
|
|
||||||
|
"github.com/redis/go-redis/v9"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RedisHandler struct {
|
||||||
|
client *redis.Client
|
||||||
|
ctx context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
type LoginMetadata struct {
|
||||||
|
FEKey []byte `json:",omitempty"`
|
||||||
|
PlayerID int32 `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ShardMetadata struct {
|
||||||
|
IP string
|
||||||
|
Port int
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
SHARD_SET = "shards"
|
||||||
|
)
|
||||||
|
|
||||||
|
func OpenRedis(addr string) (*RedisHandler, error) {
|
||||||
|
client := redis.NewClient(&redis.Options{
|
||||||
|
Addr: addr,
|
||||||
|
CredentialsProvider: config.GetRedisCredentials(),
|
||||||
|
})
|
||||||
|
|
||||||
|
_, err := client.Ping(context.Background()).Result()
|
||||||
|
return &RedisHandler{client: client, ctx: context.Background()}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RedisHandler) Close() error {
|
||||||
|
return r.client.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// we store login queues into redis with the name "loginMetadata_<serialKey>"
|
||||||
|
// set to expire after config.LOGIN_TIMEOUT duration. this way we can easily
|
||||||
|
// have a shared pool of active serial keys & player login data which any
|
||||||
|
// shard can pull from
|
||||||
|
|
||||||
|
func makeLoginMetadataKey(serialKey int64) string {
|
||||||
|
return fmt.Sprintf("loginMetadata_%s", strconv.Itoa(int(serialKey)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RedisHandler) QueueLogin(serialKey int64, data LoginMetadata) error {
|
||||||
|
value, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// add to table
|
||||||
|
return r.client.Set(r.ctx, makeLoginMetadataKey(serialKey), value, config.LOGIN_TIMEOUT).Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RedisHandler) GetLogin(serialKey int64) (LoginMetadata, error) {
|
||||||
|
value, err := r.client.Get(r.ctx, makeLoginMetadataKey(serialKey)).Result()
|
||||||
|
if err != nil {
|
||||||
|
return LoginMetadata{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var data LoginMetadata
|
||||||
|
if err := json.Unmarshal([]byte(value), &data); err != nil {
|
||||||
|
return LoginMetadata{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RedisHandler) RemoveLogin(serialKey int64) error {
|
||||||
|
return r.client.Del(r.ctx, makeLoginMetadataKey(serialKey)).Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RedisHandler) RegisterShard(shard ShardMetadata) error {
|
||||||
|
value, err := json.Marshal(shard)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.client.SAdd(r.ctx, SHARD_SET, value).Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RedisHandler) GetShards() []ShardMetadata {
|
||||||
|
shardData := r.client.SMembers(r.ctx, SHARD_SET).Val()
|
||||||
|
|
||||||
|
// unmarshal all shards
|
||||||
|
shards := make([]ShardMetadata, 0, len(shardData))
|
||||||
|
for _, data := range shardData {
|
||||||
|
var shard ShardMetadata
|
||||||
|
if err := json.Unmarshal([]byte(data), &shard); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
shards = append(shards, shard)
|
||||||
|
}
|
||||||
|
|
||||||
|
return shards
|
||||||
|
}
|
17
go.mod
17
go.mod
@ -4,18 +4,15 @@ go 1.19
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/blockloop/scan v1.3.0
|
github.com/blockloop/scan v1.3.0
|
||||||
github.com/glebarez/go-sqlite v1.21.0
|
github.com/georgysavva/scany/v2 v2.0.0
|
||||||
|
github.com/google/subcommands v1.2.0
|
||||||
|
github.com/lib/pq v1.10.9
|
||||||
|
github.com/redis/go-redis/v9 v9.0.5
|
||||||
golang.org/x/crypto v0.7.0
|
golang.org/x/crypto v0.7.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
github.com/mattn/go-sqlite3 v1.14.15 // indirect
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230126093431-47fa9a501578 // indirect
|
|
||||||
golang.org/x/sys v0.6.0 // indirect
|
|
||||||
modernc.org/libc v1.22.2 // indirect
|
|
||||||
modernc.org/mathutil v1.5.0 // indirect
|
|
||||||
modernc.org/memory v1.5.0 // indirect
|
|
||||||
modernc.org/sqlite v1.20.4 // indirect
|
|
||||||
)
|
)
|
||||||
|
51
go.sum
51
go.sum
@ -1,36 +1,39 @@
|
|||||||
github.com/blockloop/scan v1.3.0 h1:p8xnajpGA3d/V6o23IBFdQ764+JnNJ+PQj+OwT+rkdg=
|
github.com/blockloop/scan v1.3.0 h1:p8xnajpGA3d/V6o23IBFdQ764+JnNJ+PQj+OwT+rkdg=
|
||||||
github.com/blockloop/scan v1.3.0/go.mod h1:qd+3w68+o7m5Xhj9X5SlJH2rbFyK8w0WT47Rkuer010=
|
github.com/blockloop/scan v1.3.0/go.mod h1:qd+3w68+o7m5Xhj9X5SlJH2rbFyK8w0WT47Rkuer010=
|
||||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
github.com/bsm/ginkgo/v2 v2.7.0 h1:ItPMPH90RbmZJt5GtkcNvIRuGEdwlBItdNVoyzaNQao=
|
||||||
|
github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y=
|
||||||
|
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||||
|
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/cockroachdb/cockroach-go/v2 v2.2.0 h1:/5znzg5n373N/3ESjHF5SMLxiW4RKB05Ql//KWfeTFs=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||||
github.com/glebarez/go-sqlite v1.21.0 h1:b8MHPtBagkSD2gntImZPsG3o3QEXgMDxguW/GLUonHQ=
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||||
github.com/glebarez/go-sqlite v1.21.0/go.mod h1:GodsA6yGSa3eKbvpr7dS+JaqazzVfMcjIXvx6KHhW/c=
|
github.com/georgysavva/scany/v2 v2.0.0 h1:RGXqxDv4row7/FYoK8MRXAZXqoWF/NM+NP0q50k3DKU=
|
||||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
|
github.com/georgysavva/scany/v2 v2.0.0/go.mod h1:sigOdh+0qb/+aOs3TVhehVT10p8qJL7K/Zhyz8vWo38=
|
||||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE=
|
||||||
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
|
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
|
||||||
|
github.com/jackc/pgx/v5 v5.0.0 h1:3UdmB3yUeTnJtZ+nDv3Mxzd4GHHvHkl9XN3oboIbOrY=
|
||||||
|
github.com/jackc/puddle/v2 v2.0.0 h1:Kwk/AlLigcnZsDssc3Zun1dk1tAtQNPaBBxBHWn0Mjc=
|
||||||
|
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||||
|
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||||
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
|
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
github.com/redis/go-redis/v9 v9.0.5 h1:CuQcn5HIEeK7BgElubPP8CGtE0KakrnbBSTLjathl5o=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230126093431-47fa9a501578 h1:VstopitMQi3hZP0fzvnsLmzXZdQGc4bEcgu24cp+d4M=
|
github.com/redis/go-redis/v9 v9.0.5/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230126093431-47fa9a501578/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||||
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
||||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||||
modernc.org/libc v1.22.2 h1:4U7v51GyhlWqQmwCHj28Rdq2Yzwk55ovjFrdPjs8Hb0=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
modernc.org/libc v1.22.2/go.mod h1:uvQavJ1pZ0hIoC/jfqNoMLURIMhKzINIWypNM17puug=
|
|
||||||
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
|
|
||||||
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
|
||||||
modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds=
|
|
||||||
modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
|
|
||||||
modernc.org/sqlite v1.20.4 h1:J8+m2trkN+KKoE7jglyHYYYiaq5xmz2HoHJIiBlRzbE=
|
|
||||||
modernc.org/sqlite v1.20.4/go.mod h1:zKcGyrICaxNTMEHSr1HQ2GUraP0j+845GYw37+EyT6A=
|
|
||||||
|
@ -3,12 +3,14 @@ package login
|
|||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/CPunch/gopenfusion/config"
|
"github.com/CPunch/gopenfusion/config"
|
||||||
"github.com/CPunch/gopenfusion/core/db"
|
"github.com/CPunch/gopenfusion/core/db"
|
||||||
"github.com/CPunch/gopenfusion/core/protocol"
|
"github.com/CPunch/gopenfusion/core/protocol"
|
||||||
"github.com/CPunch/gopenfusion/shard"
|
"github.com/CPunch/gopenfusion/core/redis"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -104,6 +106,7 @@ func (server *LoginServer) Login(peer *protocol.CNPeer, pkt protocol.Packet) err
|
|||||||
SendError(LOGIN_DATABASE_ERROR)
|
SendError(LOGIN_DATABASE_ERROR)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
log.Printf("Account (%d) %s has logged in", account.AccountID, account.Login)
|
||||||
|
|
||||||
// truncate plrs
|
// truncate plrs
|
||||||
if len(plrs) > 3 {
|
if len(plrs) > 3 {
|
||||||
@ -218,11 +221,13 @@ func (server *LoginServer) CharacterCreate(peer *protocol.CNPeer, pkt protocol.P
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := server.dbHndlr.FinishPlayer(&charPkt, peer.AccountID); err != nil {
|
if err := server.dbHndlr.FinishPlayer(&charPkt, peer.AccountID); err != nil {
|
||||||
|
log.Printf("Error finishing player: %v", err)
|
||||||
return SendFail(peer)
|
return SendFail(peer)
|
||||||
}
|
}
|
||||||
|
|
||||||
plr, err := server.dbHndlr.GetPlayer(int(charPkt.PCStyle.IPC_UID))
|
plr, err := server.dbHndlr.GetPlayer(int(charPkt.PCStyle.IPC_UID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("Error getting player: %v", err)
|
||||||
return SendFail(peer)
|
return SendFail(peer)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,8 +257,10 @@ func (server *LoginServer) ShardSelect(peer *protocol.CNPeer, pkt protocol.Packe
|
|||||||
var selection protocol.SP_CL2LS_REQ_CHAR_SELECT
|
var selection protocol.SP_CL2LS_REQ_CHAR_SELECT
|
||||||
pkt.Decode(&selection)
|
pkt.Decode(&selection)
|
||||||
|
|
||||||
if server.shard == nil {
|
shards := server.redisHndlr.GetShards()
|
||||||
return fmt.Errorf("LoginServer currently has no linked shard")
|
if len(shards) == 0 {
|
||||||
|
SendFail(peer)
|
||||||
|
return fmt.Errorf("LoginServer has found no linked shards!")
|
||||||
}
|
}
|
||||||
|
|
||||||
key, err := protocol.GenSerialKey()
|
key, err := protocol.GenSerialKey()
|
||||||
@ -261,21 +268,36 @@ func (server *LoginServer) ShardSelect(peer *protocol.CNPeer, pkt protocol.Packe
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: verify peer->AccountID and selection->IPC_UID are valid!!!!
|
// TODO: better shard selection logic pls
|
||||||
|
// for now, pick random shard
|
||||||
|
shard := shards[rand.Intn(len(shards))]
|
||||||
|
|
||||||
|
// make sure the player is owned by the account
|
||||||
|
plr, err := server.dbHndlr.GetPlayer(int(selection.IPC_UID))
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error getting player: %v", err)
|
||||||
|
return SendFail(peer)
|
||||||
|
}
|
||||||
|
|
||||||
|
if plr.AccountID != peer.AccountID {
|
||||||
|
log.Printf("HACK: player %d tried to join shard as player %d", peer.AccountID, plr.AccountID)
|
||||||
|
return SendFail(peer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// share the login attempt
|
||||||
|
server.redisHndlr.QueueLogin(key, redis.LoginMetadata{
|
||||||
|
FEKey: peer.FE_key,
|
||||||
|
PlayerID: int32(selection.IPC_UID),
|
||||||
|
})
|
||||||
|
|
||||||
|
// craft response
|
||||||
resp := protocol.SP_LS2CL_REP_SHARD_SELECT_SUCC{
|
resp := protocol.SP_LS2CL_REP_SHARD_SELECT_SUCC{
|
||||||
G_FE_ServerPort: int32(server.shard.GetPort()),
|
G_FE_ServerPort: int32(shard.Port),
|
||||||
IEnterSerialKey: key,
|
IEnterSerialKey: key,
|
||||||
}
|
}
|
||||||
|
|
||||||
// the rest of the bytes in G_FE_ServerIP will be zero'd, so there's no need to write the NULL byte
|
// the rest of the bytes in G_FE_ServerIP will be zero'd, so there's no need to write the NULL byte
|
||||||
copy(resp.G_FE_ServerIP[:], []byte(config.SHARD_IP))
|
copy(resp.G_FE_ServerIP[:], []byte(shard.IP))
|
||||||
|
|
||||||
server.shard.QueueLogin(key, &shard.LoginMetadata{
|
|
||||||
FEKey: peer.FE_key,
|
|
||||||
Timestamp: time.Now(),
|
|
||||||
PlayerID: int32(selection.IPC_UID),
|
|
||||||
})
|
|
||||||
|
|
||||||
return peer.Send(protocol.P_LS2CL_REP_SHARD_SELECT_SUCC, resp)
|
return peer.Send(protocol.P_LS2CL_REP_SHARD_SELECT_SUCC, resp)
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,10 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/CPunch/gopenfusion/config"
|
||||||
"github.com/CPunch/gopenfusion/core/db"
|
"github.com/CPunch/gopenfusion/core/db"
|
||||||
"github.com/CPunch/gopenfusion/core/protocol"
|
"github.com/CPunch/gopenfusion/core/protocol"
|
||||||
"github.com/CPunch/gopenfusion/shard"
|
"github.com/CPunch/gopenfusion/core/redis"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PacketHandler func(peer *protocol.CNPeer, pkt protocol.Packet) error
|
type PacketHandler func(peer *protocol.CNPeer, pkt protocol.Packet) error
|
||||||
@ -19,23 +20,24 @@ type LoginServer struct {
|
|||||||
listener net.Listener
|
listener net.Listener
|
||||||
port int
|
port int
|
||||||
dbHndlr *db.DBHandler
|
dbHndlr *db.DBHandler
|
||||||
|
redisHndlr *redis.RedisHandler
|
||||||
packetHandlers map[uint32]PacketHandler
|
packetHandlers map[uint32]PacketHandler
|
||||||
peers map[*protocol.CNPeer]bool
|
peers map[*protocol.CNPeer]bool
|
||||||
peersLock sync.Mutex
|
peersLock sync.Mutex
|
||||||
shard *shard.ShardServer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLoginServer(dbHndlr *db.DBHandler, port int) (*LoginServer, error) {
|
func NewLoginServer(dbHndlr *db.DBHandler, redisHndlr *redis.RedisHandler, port int) (*LoginServer, error) {
|
||||||
listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
|
listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
server := &LoginServer{
|
server := &LoginServer{
|
||||||
listener: listener,
|
listener: listener,
|
||||||
port: port,
|
port: port,
|
||||||
dbHndlr: dbHndlr,
|
dbHndlr: dbHndlr,
|
||||||
peers: make(map[*protocol.CNPeer]bool),
|
redisHndlr: redisHndlr,
|
||||||
|
peers: make(map[*protocol.CNPeer]bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
server.packetHandlers = map[uint32]PacketHandler{
|
server.packetHandlers = map[uint32]PacketHandler{
|
||||||
@ -59,7 +61,7 @@ func NewLoginServer(dbHndlr *db.DBHandler, port int) (*LoginServer, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (server *LoginServer) Start() {
|
func (server *LoginServer) Start() {
|
||||||
log.Printf("Server hosted on 127.0.0.1:%d\n", server.port)
|
log.Printf("Login service hosted on %s:%d\n", config.GetAnnounceIP(), server.port)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
conn, err := server.listener.Accept()
|
conn, err := server.listener.Accept()
|
||||||
@ -99,7 +101,3 @@ func (server *LoginServer) Connect(peer *protocol.CNPeer) {
|
|||||||
server.peers[peer] = true
|
server.peers[peer] = true
|
||||||
server.peersLock.Unlock()
|
server.peersLock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (server *LoginServer) AddShard(shard *shard.ShardServer) {
|
|
||||||
server.shard = shard
|
|
||||||
}
|
|
||||||
|
33
main.go
33
main.go
@ -1,33 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/CPunch/gopenfusion/config"
|
|
||||||
"github.com/CPunch/gopenfusion/core/db"
|
|
||||||
"github.com/CPunch/gopenfusion/login"
|
|
||||||
"github.com/CPunch/gopenfusion/shard"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
dbHndlr, err := db.OpenLiteDB("test.db")
|
|
||||||
if err != nil {
|
|
||||||
log.Panicf("failed to open db: %v", err)
|
|
||||||
}
|
|
||||||
dbHndlr.Setup()
|
|
||||||
|
|
||||||
loginServer, err := login.NewLoginServer(dbHndlr, config.LOGIN_PORT)
|
|
||||||
if err != nil {
|
|
||||||
log.Panicf("failed to create login server: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
shardServer, err := shard.NewShardServer(dbHndlr, config.SHARD_PORT)
|
|
||||||
if err != nil {
|
|
||||||
log.Panicf("failed to create shard server: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
loginServer.AddShard(shardServer)
|
|
||||||
go loginServer.Start()
|
|
||||||
|
|
||||||
shardServer.Start()
|
|
||||||
}
|
|
@ -2,6 +2,7 @@ package shard
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/CPunch/gopenfusion/core"
|
"github.com/CPunch/gopenfusion/core"
|
||||||
@ -12,7 +13,7 @@ func (server *ShardServer) RequestEnter(peer *protocol.CNPeer, pkt protocol.Pack
|
|||||||
var enter protocol.SP_CL2FE_REQ_PC_ENTER
|
var enter protocol.SP_CL2FE_REQ_PC_ENTER
|
||||||
pkt.Decode(&enter)
|
pkt.Decode(&enter)
|
||||||
|
|
||||||
loginData, err := server.CheckLogin(enter.IEnterSerialKey)
|
loginData, err := server.redisHndlr.GetLogin(enter.IEnterSerialKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// the error codes for P_FE2CL_REP_PC_ENTER_FAIL aren't referenced in the client :(
|
// 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{})
|
peer.Send(protocol.P_FE2CL_REP_PC_ENTER_FAIL, protocol.SP_FE2CL_REP_PC_ENTER_FAIL{})
|
||||||
@ -48,6 +49,7 @@ func (server *ShardServer) RequestEnter(peer *protocol.CNPeer, pkt protocol.Pack
|
|||||||
peer.FE_key = loginData.FEKey
|
peer.FE_key = loginData.FEKey
|
||||||
peer.SetActiveKey(protocol.USE_FE)
|
peer.SetActiveKey(protocol.USE_FE)
|
||||||
|
|
||||||
|
log.Printf("Player %d (AccountID %d) entered\n", resp.IID, loginData.PlayerID)
|
||||||
return peer.Send(protocol.P_FE2CL_REP_PC_ENTER_SUCC, resp)
|
return peer.Send(protocol.P_FE2CL_REP_PC_ENTER_SUCC, resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1
shard/movement.go
Normal file
1
shard/movement.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package shard
|
@ -5,19 +5,14 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
|
|
||||||
|
"github.com/CPunch/gopenfusion/config"
|
||||||
"github.com/CPunch/gopenfusion/core"
|
"github.com/CPunch/gopenfusion/core"
|
||||||
"github.com/CPunch/gopenfusion/core/db"
|
"github.com/CPunch/gopenfusion/core/db"
|
||||||
"github.com/CPunch/gopenfusion/core/protocol"
|
"github.com/CPunch/gopenfusion/core/protocol"
|
||||||
|
"github.com/CPunch/gopenfusion/core/redis"
|
||||||
)
|
)
|
||||||
|
|
||||||
type LoginMetadata struct {
|
|
||||||
FEKey []byte
|
|
||||||
Timestamp time.Time
|
|
||||||
PlayerID int32
|
|
||||||
}
|
|
||||||
|
|
||||||
type PacketHandler func(peer *protocol.CNPeer, pkt protocol.Packet) error
|
type PacketHandler func(peer *protocol.CNPeer, pkt protocol.Packet) error
|
||||||
|
|
||||||
func stubbedPacket(_ *protocol.CNPeer, _ protocol.Packet) error { /* stubbed */ return nil }
|
func stubbedPacket(_ *protocol.CNPeer, _ protocol.Packet) error { /* stubbed */ return nil }
|
||||||
@ -26,13 +21,14 @@ type ShardServer struct {
|
|||||||
listener net.Listener
|
listener net.Listener
|
||||||
port int
|
port int
|
||||||
dbHndlr *db.DBHandler
|
dbHndlr *db.DBHandler
|
||||||
|
redisHndlr *redis.RedisHandler
|
||||||
packetHandlers map[uint32]PacketHandler
|
packetHandlers map[uint32]PacketHandler
|
||||||
loginMetadataQueue sync.Map // [int64]*LoginMetadata w/ int64 = serialKey
|
loginMetadataQueue sync.Map // [int64]*LoginMetadata w/ int64 = serialKey
|
||||||
peersLock sync.Mutex
|
peersLock sync.Mutex
|
||||||
peers sync.Map // [*protocol.CNPeer]core.Player
|
peers sync.Map // [*protocol.CNPeer]core.Player
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewShardServer(dbHndlr *db.DBHandler, port int) (*ShardServer, error) {
|
func NewShardServer(dbHndlr *db.DBHandler, redisHndlr *redis.RedisHandler, port int) (*ShardServer, error) {
|
||||||
listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
|
listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -42,6 +38,7 @@ func NewShardServer(dbHndlr *db.DBHandler, port int) (*ShardServer, error) {
|
|||||||
listener: listener,
|
listener: listener,
|
||||||
port: port,
|
port: port,
|
||||||
dbHndlr: dbHndlr,
|
dbHndlr: dbHndlr,
|
||||||
|
redisHndlr: redisHndlr,
|
||||||
packetHandlers: make(map[uint32]PacketHandler),
|
packetHandlers: make(map[uint32]PacketHandler),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,6 +47,11 @@ func NewShardServer(dbHndlr *db.DBHandler, port int) (*ShardServer, error) {
|
|||||||
protocol.P_CL2FE_REQ_PC_LOADING_COMPLETE: server.LoadingComplete,
|
protocol.P_CL2FE_REQ_PC_LOADING_COMPLETE: server.LoadingComplete,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
redisHndlr.RegisterShard(redis.ShardMetadata{
|
||||||
|
IP: config.GetAnnounceIP(),
|
||||||
|
Port: port,
|
||||||
|
})
|
||||||
|
|
||||||
return server, nil
|
return server, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +60,7 @@ func (server *ShardServer) RegisterPacketHandler(typeID uint32, hndlr PacketHand
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (server *ShardServer) Start() {
|
func (server *ShardServer) Start() {
|
||||||
log.Printf("Server hosted on 127.0.0.1:%d\n", server.port)
|
log.Printf("Shard service hosted on %s:%d\n", config.GetAnnounceIP(), server.port)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
conn, err := server.listener.Accept()
|
conn, err := server.listener.Accept()
|
||||||
@ -151,21 +153,3 @@ func (server *ShardServer) RangePeers(f func(peer *protocol.CNPeer, player *core
|
|||||||
return f(peer, player)
|
return f(peer, player)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (server *ShardServer) QueueLogin(serialKey int64, meta *LoginMetadata) {
|
|
||||||
server.loginMetadataQueue.Store(serialKey, meta)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (server *ShardServer) CheckLogin(serialKey int64) (*LoginMetadata, error) {
|
|
||||||
value, ok := server.loginMetadataQueue.Load(serialKey)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("serialKey %x is not valid!", serialKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
meta, ok := value.(*LoginMetadata)
|
|
||||||
if !ok { // should never happen
|
|
||||||
panic(fmt.Errorf("ShardServer.loginMetadataQueue has an invalid value: loginMetadataQueue[%x] = %#v", serialKey, value))
|
|
||||||
}
|
|
||||||
|
|
||||||
return meta, nil
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user