Skip to content

Commit

Permalink
Merge pull request #143 from inada-s/online-patch
Browse files Browse the repository at this point in the history
add online patch impl
  • Loading branch information
inada-s authored Jul 3, 2021
2 parents 646870d + 21b5f8f commit f07a451
Show file tree
Hide file tree
Showing 19 changed files with 669 additions and 87 deletions.
12 changes: 12 additions & 0 deletions gdxsv/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ type MLobbySetting struct {
TeamShuffle bool `db:"team_shuffle" json:"team_shuffle"`
PingLimit int `db:"ping_limit" json:"ping_limit"`
PingRegion string `db:"ping_region" json:"ping_region"`
PatchNames string `db:"patch_names" json:"patch_names"`
}

type MRule struct {
Expand Down Expand Up @@ -150,6 +151,14 @@ type MRule struct {
StageNo int `db:"stage_no" json:"stage_no"`
}

type MPatch struct {
Platform string `db:"platform" json:"platform"`
Disk string `db:"disk" json:"disk"`
Name string `db:"name" json:"name"`
WriteOnce bool `db:"write_once" json:"write_once"`
Codes string `db:"codes" json:"codes"`
}

// DB is an interface of database operation.
type DB interface {
// Init initializes the database.
Expand Down Expand Up @@ -227,4 +236,7 @@ type DB interface {

// GetRule returns game rule.
GetRule(id string) (*MRule, error)

// GetPatch returns game patch.
GetPatch(platform, disk, name string) (*MPatch, error)
}
19 changes: 19 additions & 0 deletions gdxsv/db_sqlite.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ CREATE TABLE IF NOT EXISTS m_lobby_setting
team_shuffle integer not null,
ping_limit integer not null,
ping_region text default '',
patch_names text default '',
PRIMARY KEY (platform, disk, no)
);
CREATE TABLE IF NOT EXISTS m_rule
Expand Down Expand Up @@ -158,6 +159,15 @@ CREATE TABLE IF NOT EXISTS m_rule
stage_no integer not null,
PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS m_patch
(
platform text not null,
disk text not null,
name text not null,
write_once integer not null,
codes text not null,
PRIMARY KEY (platform, disk, name)
);
`

const indexes = `
Expand Down Expand Up @@ -658,3 +668,12 @@ func (db SQLiteDB) GetRule(id string) (*MRule, error) {
}
return m, nil
}

func (db SQLiteDB) GetPatch(platform, disk, name string) (*MPatch, error) {
m := &MPatch{}
err := db.QueryRowx("SELECT * FROM m_patch WHERE platform = ? AND disk = ? AND name = ?", platform, disk, name).StructScan(m)
if err != nil {
return nil, err
}
return m, nil
}
21 changes: 21 additions & 0 deletions gdxsv/db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -603,3 +603,24 @@ INSERT INTO m_rule (
panic(err)
}
}

func mustInsertMPatch(patch MPatch) {
db := getDB().(SQLiteDB)
_, err := db.NamedExec(`
INSERT INTO m_patch (
platform ,
disk ,
name ,
write_once ,
codes
) VALUES (
:platform ,
:disk ,
:name ,
:write_once ,
:codes
)`, patch)
if err != nil {
panic(err)
}
}
16 changes: 12 additions & 4 deletions gdxsv/lbs_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ const (
// gdxsv extended commands
lbsExtSyncSharedData CmdID = 0x9900
lbsPlatformInfo CmdID = 0x9950
lbsGamePatch CmdID = 0x9960
)

func RequestLineCheck(p *LbsPeer) {
Expand Down Expand Up @@ -250,12 +251,12 @@ func sendUserList(p *LbsPeer) {
p.SendMessage(n)
}

func isOldFlycastVersion(userVersion string) bool {
func isOldFlycastVersion(userVersion string, minVersion string) bool {
if strings.HasPrefix(userVersion, "gdxsv-") {
// New version-string have the prefix.
userVersion = "v" + strings.TrimPrefix(userVersion, "gdxsv-")
}
if semver.Compare(userVersion, requiredFlycastVersion) < 0 {
if semver.Compare(userVersion, minVersion) < 0 {
return true
}
return false
Expand Down Expand Up @@ -284,7 +285,7 @@ var _ = register(lbsLoginType, func(p *LbsPeer, m *LbsMessage) {

switch loginType {
case 0:
if p.PlatformInfo["flycast"] != "" && isOldFlycastVersion(p.PlatformInfo["flycast"]) {
if p.PlatformInfo["flycast"] != "" && isOldFlycastVersion(p.PlatformInfo["flycast"], requiredFlycastVersion) {
p.SendMessage(NewServerNotice(lbsShutDown).Writer().
WriteString("<LF=5><BODY><CENTER>PLEASE UPDATE Flycast<END>").Msg())
return
Expand Down Expand Up @@ -334,7 +335,7 @@ var _ = register(lbsLoginType, func(p *LbsPeer, m *LbsMessage) {
p.SendMessage(NewServerNotice(lbsShutDown).Writer().
WriteString("<LF=5><BODY><CENTER>UNSUPPORTED LOGIN TYPE<END>").Msg())
case 2:
if p.PlatformInfo["flycast"] != "" && isOldFlycastVersion(p.PlatformInfo["flycast"]) {
if p.PlatformInfo["flycast"] != "" && isOldFlycastVersion(p.PlatformInfo["flycast"], requiredFlycastVersion) {
p.SendMessage(NewServerNotice(lbsShutDown).Writer().
WriteString("<LF=5><BODY><CENTER>PLEASE UPDATE Flycast<END>").Msg())
return
Expand Down Expand Up @@ -842,6 +843,13 @@ var _ = register(lbsPlazaStatus, func(p *LbsPeer, m *LbsMessage) {
}
}

// Check GamePatch feature is available
if lobby.LobbySetting.PatchNames != "" {
if p.PlatformInfo["flycast"] != "" && isOldFlycastVersion(p.PlatformInfo["flycast"], novelFlycastVersion) {
status = 1
}
}

p.SendMessage(NewServerAnswer(m).Writer().
Write16(lobbyID).
Write8(uint8(status)).Msg())
Expand Down
8 changes: 7 additions & 1 deletion gdxsv/lbs_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,19 @@ func Test_isOldFlycastVersion(t *testing.T) {
args: args{userVersion: "gdxsv-0.6.9"},
want: true,
},
{
name: "real semver dev version is old",
requiredVersion: "v1.0.4",
args: args{userVersion: "v1.0.4-dev.3+100e01d4"},
want: true,
},
}

backup := requiredFlycastVersion
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
requiredFlycastVersion = tt.requiredVersion
if got := isOldFlycastVersion(tt.args.userVersion); got != tt.want {
if got := isOldFlycastVersion(tt.args.userVersion, requiredFlycastVersion); got != tt.want {
t.Errorf("isOldFlycastVersion() = %v, want %v", got, tt.want)
}
})
Expand Down
65 changes: 65 additions & 0 deletions gdxsv/lbs_lobby.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package main
import (
"database/sql"
"fmt"
"gdxsv/gdxsv/proto"
"go.uber.org/zap"
pb "google.golang.org/protobuf/proto"
"math/rand"
"sort"
"strconv"
Expand Down Expand Up @@ -349,6 +351,20 @@ func (l *LbsLobby) printLobbyReminder(p *LbsPeer) {

func (l *LbsLobby) Enter(p *LbsPeer) {
l.Users[p.UserID] = &p.DBUser

// Send game patch for offline testing
if l.LobbySetting.PatchNames != "" {
patchList := l.makePatchList()
logger.Info("patchList", zap.Any("patchList", patchList))
patchBin, err := pb.Marshal(patchList)
if err != nil {
logger.Error("pb.Marshal patch", zap.Error(err))
return
}
patchMsg := NewServerNotice(lbsGamePatch)
patchMsg.Writer().Write(patchBin)
p.SendMessage(patchMsg)
}
}

func (l *LbsLobby) Exit(userID string) {
Expand Down Expand Up @@ -593,6 +609,33 @@ func (l *LbsLobby) Update() {
l.checkRoomBattleStart()
}

func (l *LbsLobby) makePatchList() *proto.GamePatchList {
sp := strings.Split(strings.TrimSpace(l.LobbySetting.PatchNames), ",")
if len(sp) == 0 {
return nil
}

patchList := new(proto.GamePatchList)

for _, name := range sp {
mPatch, err := getDB().GetPatch(l.Platform, l.GameDisk, name)
if err != nil {
logger.Warn("failed to load patch", zap.String("name", name), zap.Error(err))
continue
}

gamePatch, err := convertGamePatch(mPatch)
if err != nil {
logger.Warn("failed to convert patch", zap.String("name", name), zap.Error(err))
continue
}

patchList.Patches = append(patchList.Patches, gamePatch)
}

return patchList
}

func (l *LbsLobby) checkLobbyBattleStart(force bool) {
if !(force || l.canStartBattle()) {
return
Expand Down Expand Up @@ -669,13 +712,24 @@ func (l *LbsLobby) checkLobbyBattleStart(force bool) {
}
}

patchList := l.makePatchList()
logger.Info("patchList", zap.Any("patchList", patchList))
patchBin, err := pb.Marshal(patchList)
if err != nil {
logger.Error("pb.Marshal patch", zap.Error(err))
return
}
patchMsg := NewServerNotice(lbsGamePatch)
patchMsg.Writer().Write(patchBin)

sharedData.ShareMcsGame(&McsGame{
BattleCode: b.BattleCode,
Rule: *b.Rule,
GameDisk: l.GameDisk,
UpdatedAt: time.Now(),
State: McsGameStateCreated,
McsAddr: mcsAddr,
PatchList: patchList,
})

for _, q := range participants {
Expand All @@ -697,6 +751,7 @@ func (l *LbsLobby) checkLobbyBattleStart(force bool) {
State: McsUserStateCreated,
})
NotifyReadyBattle(q)
q.SendMessage(patchMsg)
}

if mcsPeer != nil {
Expand Down Expand Up @@ -830,13 +885,23 @@ func (l *LbsLobby) checkRoomBattleStart() {
}
}

patchList := l.makePatchList()
patchBin, err := pb.Marshal(patchList)
if err != nil {
logger.Error("pb.Marshal patch", zap.Error(err))
return
}
patchMsg := NewServerNotice(lbsGamePatch)
patchMsg.Writer().Write(patchBin)

sharedData.ShareMcsGame(&McsGame{
BattleCode: b.BattleCode,
Rule: *b.Rule,
GameDisk: l.GameDisk,
UpdatedAt: time.Now(),
State: McsGameStateCreated,
McsAddr: mcsAddr,
PatchList: patchList,
})

for _, q := range participants {
Expand Down
4 changes: 3 additions & 1 deletion gdxsv/lbs_message.string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions gdxsv/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"log"
"math/rand"
"net/http"
_ "net/http/pprof"
"os"
"os/signal"
"runtime"
Expand All @@ -31,6 +32,9 @@ var (

// Minimum required flycast version.
requiredFlycastVersion = "v0.7.0"

// New feature installed version.
novelFlycastVersion = "v1.0.5"
)

var (
Expand Down
7 changes: 7 additions & 0 deletions gdxsv/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ func TestMain(m *testing.M) {
})
mustInsertMRule(MRule{ID: "dummy"})
mustInsertMString("dummy", "dummy string")
mustInsertMPatch(MPatch{
Platform: "emu-x86/64",
Disk: "dc2",
Name: "dummy-patch",
WriteOnce: true,
Codes: "1, 8, 0c391d97, 1, 0",
})

os.Exit(m.Run())
}
7 changes: 7 additions & 0 deletions gdxsv/mcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,11 +287,18 @@ func (mcs *Mcs) Join(p McsPeer, sessionID string) *McsRoom {
mcs.mtx.Lock()
mcs.updated = time.Now()
room := mcs.rooms[user.BattleCode]
created := false
if room == nil {
room = newMcsRoom(mcs, game)
mcs.rooms[user.BattleCode] = room
created = true
}
mcs.mtx.Unlock()

if created {
logger.Info("new McsRoom", zap.String("battle_code", user.BattleCode), zap.Any("game", game))
}

room.Join(p, user)

sharedData.UpdateMcsUserState(sessionID, McsUserStateJoined)
Expand Down
6 changes: 4 additions & 2 deletions gdxsv/mcs_room.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,20 @@ type McsRoom struct {
}

func newMcsRoom(mcs *Mcs, gameInfo *McsGame) *McsRoom {
return &McsRoom{
room := &McsRoom{
mcs: mcs,
game: gameInfo,
battleLog: &proto.BattleLogFile{
LogFileVersion: 20201212,
LogFileVersion: 20210702,
GameDisk: gameInfo.GameDisk,
GdxsvVersion: gdxsvVersion,
BattleCode: gameInfo.BattleCode,
RuleBin: SerializeRule(&gameInfo.Rule),
Patches: gameInfo.PatchList.GetPatches(),
StartAt: time.Now().UnixNano(),
},
}
return room
}

func (r *McsRoom) PeerCount() int {
Expand Down
1 change: 1 addition & 0 deletions gdxsv/mcs_udp.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ func (u *McsUDPPeer) Serve(mcs *Mcs) {
var err error
pbBuf, err = pbm.MarshalAppend(pbBuf[:0], pkt)
proto.PutPacket(pkt)

if err != nil {
u.logger.Error("Marshal error", zap.Error(err))
u.SetCloseReason("sv_marshal_error")
Expand Down
Loading

0 comments on commit f07a451

Please sign in to comment.