diff --git a/.github/workflows/build_dev.yml b/.github/workflows/build_dev.yml index f6b5efa..e5f9026 100644 --- a/.github/workflows/build_dev.yml +++ b/.github/workflows/build_dev.yml @@ -57,18 +57,16 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 - - name: Build Plugin + - name: Build Nakma Plugin id: build_plugin uses: josephbmanley/build-nakama-plugin-action@v0.1.1 with: nakamaVersion: "2.12.0" - moduleDirectory: server/plugins/world_rpc + moduleDirectory: server/plugin - name: Move Binary - env: - plugin: ${{ steps.build_plugin.outputs.binary }} run: | mkdir -p server/data/modules - mv $plugin server/data/modules + mv ${{ steps.build_plugin.outputs.binary }} server/data/modules - id: get_tag name: Get Tag env: diff --git a/.github/workflows/build_release.yml b/.github/workflows/build_release.yml index 12bde47..da1fd22 100644 --- a/.github/workflows/build_release.yml +++ b/.github/workflows/build_release.yml @@ -52,18 +52,23 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 - - name: Build Plugin - id: build_plugin + - name: Build RPC Plugin + id: build_rpc_plugin uses: josephbmanley/build-nakama-plugin-action@v0.1.1 with: nakamaVersion: "2.12.0" moduleDirectory: server/plugins/world_rpc + - name: Build Control Plugin + id: build_control_plugin + uses: josephbmanley/build-nakama-plugin-action@v0.1.1 + with: + nakamaVersion: "2.12.0" + moduleDirectory: server/plugins/control - name: Move Binary - env: - plugin: ${{ steps.build_plugin.outputs.binary }} run: | mkdir -p server/data/modules - mv $plugin server/data/modules + mv ${{ steps.build_rpc_plugin.outputs.binary }} server/data/modules + mv ${{ steps.build_control_plugin.outputs.binary }} server/data/modules - id: get_tag name: Get Tag env: diff --git a/.github/workflows/build_stage.yml b/.github/workflows/build_stage.yml index 74cf3bb..2e24b75 100644 --- a/.github/workflows/build_stage.yml +++ b/.github/workflows/build_stage.yml @@ -39,18 +39,23 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 - - name: Build Plugin - id: build_plugin + - name: Build RPC Plugin + id: build_rpc_plugin uses: josephbmanley/build-nakama-plugin-action@v0.1.1 with: nakamaVersion: "2.12.0" moduleDirectory: server/plugins/world_rpc + - name: Build Control Plugin + id: build_control_plugin + uses: josephbmanley/build-nakama-plugin-action@v0.1.1 + with: + nakamaVersion: "2.12.0" + moduleDirectory: server/plugins/control - name: Move Binary - env: - plugin: ${{ steps.build_plugin.outputs.binary }} run: | mkdir -p server/data/modules - mv $plugin server/data/modules + mv ${{ steps.build_rpc_plugin.outputs.binary }} server/data/modules + mv ${{ steps.build_control_plugin.outputs.binary }} server/data/modules - name: Get Docker Repo Name id: find_repo run: | diff --git a/client/scripts/menus/login_form.gd b/client/scripts/menus/login_form.gd index b1eaf0e..06a3b83 100644 --- a/client/scripts/menus/login_form.gd +++ b/client/scripts/menus/login_form.gd @@ -31,9 +31,18 @@ func login(_text=""): # Check for error if error: passwordEdit.text = "" - errorLabel.add_color_override("font_color", Color.red) - errorLabel.text = error.message + display_message(error.message) else: - errorLabel.add_color_override("font_color", Color.green) - errorLabel.text = "Logged in successfully!" - print("Logged in successfully!") + display_message("Logged in successfully!", Color.green) + display_message("Connecting to server...", Color.gray) + error = yield(ServerConnection.connect_to_server_async(), "completed") + if error: + display_message(error.message) + else: + display_message("Connected to server!", Color.green) + yield(ServerConnection.join_world_async(), "completed") + +func display_message(message="", color=Color.red): + errorLabel.add_color_override("font_color", color) + errorLabel.text = message + print(message) diff --git a/client/scripts/singletons/ServerConnection.gd b/client/scripts/singletons/ServerConnection.gd index ae27970..fe4da27 100644 --- a/client/scripts/singletons/ServerConnection.gd +++ b/client/scripts/singletons/ServerConnection.gd @@ -5,6 +5,7 @@ const SERVER_ENDPOINT := "nakama.cloudsumu.com" var _session : NakamaSession var _client : NakamaClient = Nakama.create_client(KEY, SERVER_ENDPOINT, 7350, "http") +var _socket : NakamaSocket func authenticate_async(email : String, password : String) -> NakamaException: var result : NakamaException = null @@ -21,7 +22,7 @@ func authenticate_async(email : String, password : String) -> NakamaException: func signup_async(email : String, password : String) -> NakamaException: var result : NakamaException = null - var new_session : NakamaSession = yield(_client.authenticate_email_async(email, password, null, true), "completed") + var new_session : NakamaSession = yield(_client.authenticate_email_async(email, password, email, true), "completed") if not new_session.is_exception(): _session = new_session @@ -29,3 +30,23 @@ func signup_async(email : String, password : String) -> NakamaException: result = new_session.get_exception() return result + +func connect_to_server_async() -> NakamaException: + _socket = Nakama.create_socket_from(_client) + var result : NakamaAsyncResult = yield(_socket.connect_async(_session), "completed") + if not result.is_exception(): + _socket.connect("closed", self, "_on_socket_closed") + return null + return result.exception + +func join_world_async() -> Dictionary: + var world : NakamaAPI.ApiRpc = yield(_client.rpc_async(_session, "get_world_id", ""), "completed") + if world.is_exception(): + print("Join world error occured: %s" % world.exception.message) + return {} + var _world_id : String = world.payload + print(_world_id) + return {} + +func _on_socket_closed(): + _socket = null diff --git a/server/plugin/control/control.go b/server/plugin/control/control.go new file mode 100644 index 0000000..6aeb31e --- /dev/null +++ b/server/plugin/control/control.go @@ -0,0 +1,73 @@ +package control + +import ( + "context" + "database/sql" + + "github.com/heroiclabs/nakama-common/runtime" +) + +type Match struct{} + +type MatchState struct { + presences map[string]runtime.Presence + inputs map[string]string + positions map[string]string + jumps map[string]string + colors map[string]string + names map[string]string +} + +func (m *Match) MatchInit(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, params map[string]interface{}) (interface{}, int, string) { + state := &MatchState{ + presences: map[string]runtime.Presence{}, + inputs: map[string]string{}, + positions: map[string]string{}, + jumps: map[string]string{}, + colors: map[string]string{}, + names: map[string]string{}, + } + tickRate := 10 + label := "{\"name\": \"Game World\"}" + + 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) { + mState, _ := state.(*MatchState) + if _, ok := mState.presences[presence.GetUserId()]; ok { + return mState, true, "" + } else { + return mState, false, "User already logged in." + } + +} + +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) + for _, precense := range presences { + mState.presences[precense.GetUserId()] = precense + } + return state +} + +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{} { + mState, _ := state.(*MatchState) + for _, presence := range presences { + delete(mState.presences, presence.GetUserId()) + } + 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{} { + // Custom code to: + // - Process the messages received. + // - Update the match state based on the messages and time elapsed. + // - Broadcast new data messages to match participants. + + return state +} + +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{} { + return state +} diff --git a/server/plugin/family_plugin.go b/server/plugin/family_plugin.go new file mode 100644 index 0000000..a4ddf6a --- /dev/null +++ b/server/plugin/family_plugin.go @@ -0,0 +1,24 @@ +package main + +import ( + "context" + "database/sql" + "github.com/heroiclabs/nakama-common/runtime" + "github.com/josephbmanley/family/server/plugin/control" + "github.com/josephbmanley/family/server/plugin/rpc" +) + +func InitModule(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, initializer runtime.Initializer) error { + logger.Info("Loaded family plugin!") + + if err := initializer.RegisterMatch("control", func(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule) (runtime.Match, error) { + return &control.Match{}, nil + }); err != nil { + return err + } + if err := initializer.RegisterRpc("get_world_id", rpc.GetWorldId); err != nil { + logger.Error("Unable to register: %v", err) + return err + } + return nil +} diff --git a/server/plugins/world_rpc/go.mod b/server/plugin/go.mod similarity index 53% rename from server/plugins/world_rpc/go.mod rename to server/plugin/go.mod index 4887533..509bb99 100644 --- a/server/plugins/world_rpc/go.mod +++ b/server/plugin/go.mod @@ -1,4 +1,4 @@ -module world_rpc +module github.com/josephbmanley/family/server/plugin go 1.13 diff --git a/server/plugins/world_rpc/go.sum b/server/plugin/go.sum similarity index 95% rename from server/plugins/world_rpc/go.sum rename to server/plugin/go.sum index 30c51d5..2015c67 100644 --- a/server/plugins/world_rpc/go.sum +++ b/server/plugin/go.sum @@ -13,8 +13,8 @@ github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgj github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/heroiclabs/nakama-common v1.5.1 h1:ViCm9AvYYdQOCSKEa34SuSQ80JyZOHl6ODawESWf2wk= github.com/heroiclabs/nakama-common v1.5.1/go.mod h1:nZAXHdeo4SyPlCyf7pU9rCVizxEhBF74gt7teDe/EaQ= -github.com/heroiclabs/nakama-common v1.6.0 h1:2ZUNI3y8LnEpLEXUXYfERgWS1nm1l0TKPAwnyGMU96U= -github.com/heroiclabs/nakama-common v1.6.1 h1:A2n8Jsr+wGuK8qQj5enMpu65NigChrcAMZYDLAJMY88= +github.com/heroiclabs/nakama-common v1.7.2 h1:FQedePGCorBl3tXW4Ro8+XLGbEDQfGrT5Tb07j1UaLc= +github.com/josephbmanley/family v0.0.0-20200815220504-0d9d05943cef h1:6oijVkew6eKI1fGE+YMaxmiNlp/hkN9wDpStoid9/ZI= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= diff --git a/server/plugin/rpc/rpc.go b/server/plugin/rpc/rpc.go new file mode 100644 index 0000000..c4c42eb --- /dev/null +++ b/server/plugin/rpc/rpc.go @@ -0,0 +1,52 @@ +package rpc + +import ( + "context" + "database/sql" + "github.com/heroiclabs/nakama-common/runtime" +) + +func getFirstWorld(ctx context.Context, logger runtime.Logger, nk runtime.NakamaModule) (string, error) { + + // List existing matches + // that have been 1 & 4 players + minSize := 1 + maxSize := 4 + matches, listErr := nk.MatchList(ctx, 1, false, "", &minSize, &maxSize, "") //local matches = nakama.match_list() + + // Return if listing error + if listErr != nil { + logger.Printf("Failed to list matches when grabing first world! Error: %v\n", listErr) + return "", listErr + } + + // If no matches exist, create one + if len(matches) <= 0 { + + // Create match + //params := map[string]interface{}{} + matchID, createErr := nk.MatchCreate(ctx, "control", map[string]interface{}{}) + //return nakama.match_create("world_control", {}) + + // Return if creation error + if createErr != nil { + logger.Printf("Failed to create match when grabing first world! Error: %v\n", createErr) + return "", createErr + } + logger.Info("Successfully created new match!") + + // Return newly created match + return matchID, nil + + } else { + + // Return first found match + return matches[0].GetMatchId(), nil + } + +} + +func GetWorldId(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, payload string) (string, error) { + matchID, err := getFirstWorld(ctx, logger, nk) + return matchID, err +} diff --git a/server/plugins/world_rpc/world_rpc.go b/server/plugins/world_rpc/world_rpc.go deleted file mode 100644 index ea2d70a..0000000 --- a/server/plugins/world_rpc/world_rpc.go +++ /dev/null @@ -1,14 +0,0 @@ -package main - -import ( - "context" - "database/sql" - - "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("Loaded World RPC plugin!") - - return nil -}