// Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "context" "database/sql" "encoding/json" "github.com/heroiclabs/nakama-common/runtime" ) func InitModule(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, initializer runtime.Initializer) error { logger.Info("backend loaded.") if err := initializer.RegisterMatch("PvP", CreateMatchInternal); err != nil { return err } if err := initializer.RegisterMatchmakerMatched(DoMatchmaking); err != nil { logger.Error("Unable to register: %v", err) return err } return nil } func DoMatchmaking(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, entries []runtime.MatchmakerEntry) (string, error) { for _, e := range entries { logger.Info("Matched user '%s' named '%s'", e.GetPresence().GetUserId(), e.GetPresence().GetUsername()) for k, v := range e.GetProperties() { logger.Info("Matched on '%s' value '%v'", k, v) } } matchId, err := nk.MatchCreate(ctx, "davaaPvP", map[string]interface{}{"invited": entries, "debug": true}) if err != nil { return "", err } return matchId, nil } func CreateMatchInternal(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule) (runtime.Match, error) { return &Match{}, nil } type MatchState struct { debug bool presences map[string]runtime.Presence opponents map[string]runtime.Presence } type Match struct{} func (m *Match) MatchInit(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, params map[string]interface{}) (interface{}, int, string) { var debug bool if d, ok := params["debug"]; ok { if dv, ok := d.(bool); ok { debug = dv } } state := &MatchState{ debug: debug, presences: make(map[string]runtime.Presence), opponents: make(map[string]runtime.Presence), } if state.debug { logger.Printf("match init, starting with debug: %v", state.debug) } entries := params["invited"].([]runtime.MatchmakerEntry) for i := 0; i < len(entries); i++ { p := entries[(i+1)%len(entries)].GetPresence() state.opponents[entries[i].GetPresence().GetUsername()] = p logger.Info("setting %v 's opponent : %v", entries[i].GetPresence().GetUsername(), entries[(i+1)%len(entries)].GetPresence().GetUsername()) } label := "skill=100-150" tickRate := 20 // ticks per second return state, tickRate, label } func (m *Match) MatchJoinAttempt(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, dispatcher runtime.MatchDispatcher, tick int64, state interface{}, presence runtime.Presence, metadata map[string]string) (interface{}, bool, string) { if state.(*MatchState).debug { logger.Printf("match join attempt username %v user_id %v session_id %v node %v with metadata %v", presence.GetUsername(), presence.GetUserId(), presence.GetSessionId(), presence.GetNodeId(), metadata) } return state, true, "" } func (m *Match) MatchJoin(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, dispatcher runtime.MatchDispatcher, tick int64, state interface{}, presences []runtime.Presence) interface{} { mState := state.(*MatchState) if mState.debug { for _, presence := range presences { logger.Printf("match join username %v user_id %v session_id %v node %v", presence.GetUsername(), presence.GetUserId(), presence.GetSessionId(), presence.GetNodeId()) } } return mState } func (m *Match) MatchLeave(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, dispatcher runtime.MatchDispatcher, tick int64, state interface{}, presences []runtime.Presence) interface{} { if state.(*MatchState).debug { for _, presence := range presences { logger.Printf("match leave username %v user_id %v session_id %v node %v", presence.GetUsername(), presence.GetUserId(), presence.GetSessionId(), presence.GetNodeId()) } } return state } func (m *Match) MatchLoop(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, dispatcher runtime.MatchDispatcher, tick int64, state interface{}, messages []runtime.MatchData) interface{} { mState, _ := state.(*MatchState) if state.(*MatchState).debug { logger.Printf("match loop match_id %v tick %v", ctx.Value(runtime.RUNTIME_CTX_MATCH_ID), tick) logger.Printf("match loop match_id %v message count %v", ctx.Value(runtime.RUNTIME_CTX_MATCH_ID), len(messages)) } for _, message := range messages { target := mState.opponents[message.GetUsername()] dispatcher.BroadcastMessage(message.GetOpCode(), message.GetData(), []runtime.Presence{target}, nil, false) } return mState } func (m *Match) MatchTerminate(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, dispatcher runtime.MatchDispatcher, tick int64, state interface{}, graceSeconds int) interface{} { if state.(*MatchState).debug { logger.Printf("match terminate match_id %v tick %v", ctx.Value(runtime.RUNTIME_CTX_MATCH_ID), tick) logger.Printf("match terminate match_id %v grace seconds %v", ctx.Value(runtime.RUNTIME_CTX_MATCH_ID), graceSeconds) } return nil }