@@ -3,6 +3,7 @@ package rpc
33import (
44 "context"
55 "encoding/json"
6+ "fmt"
67 "time"
78
89 "github.com/ArmchairDevelopers/Kyber/API/api/v1/pbapi"
@@ -13,6 +14,7 @@ import (
1314 "github.com/ArmchairDevelopers/Kyber/API/pkg/mq"
1415 "github.com/ArmchairDevelopers/Kyber/API/pkg/util"
1516 "github.com/ArmchairDevelopers/Kyber/API/pkg/ws"
17+ "go.mongodb.org/mongo-driver/bson"
1618 "go.uber.org/zap"
1719 "google.golang.org/grpc/codes"
1820 "google.golang.org/grpc/status"
@@ -88,6 +90,33 @@ func (s *PartyService) LeaveParty(ctx context.Context, _ *pbcommon.Empty) (*pbco
8890 },
8991 },
9092 })
93+
94+ party , err := s .store .Parties .GetByID (ctx , partyID )
95+ if err == nil && party != nil && party .JoinGameState != nil && party .LeaderID == user .ID {
96+ if err := s .store .Parties .Update (ctx , partyID , bson.M {"$unset" : bson.M {"join_game_state" : "" }}); err != nil {
97+ logger .L ().Error ("Failed to clear join game state" , zap .Error (err ))
98+ }
99+ s .partyPub .Publish (partyID , memberIDs , & pbapi.PartyEvent {
100+ Body : & pbapi.PartyEvent_JoinGameCancelled {
101+ JoinGameCancelled : & pbapi.JoinGameCancelledEvent {},
102+ },
103+ })
104+ }
105+
106+ if party .LeaderID == user .ID {
107+ newLeaderID := remainingSessions [0 ].UserID
108+ if err := s .store .Parties .Update (ctx , partyID , bson.M {"$set" : bson.M {"leader_id" : newLeaderID }}); err != nil {
109+ logger .L ().Error ("Failed to update party leader" , zap .Error (err ))
110+ }
111+
112+ s .partyPub .Publish (partyID , memberIDs , & pbapi.PartyEvent {
113+ Body : & pbapi.PartyEvent_NewLeader {
114+ NewLeader : & pbapi.NewLeaderEvent {
115+ NewLeaderId : newLeaderID ,
116+ },
117+ },
118+ })
119+ }
91120 }
92121
93122 logger .L ().Debug ("User left party" , zap .Uint64 ("party_id" , partyID ), zap .String ("user_id" , user .ID ))
@@ -398,6 +427,116 @@ func (s *PartyService) GetParty(ctx context.Context, _ *pbcommon.Empty) (*pbapi.
398427 return & pbapi.GetPartyResponse {Party : party .Proto (sessions , mapped )}, nil
399428}
400429
430+ func (s * PartyService ) StartJoinGame (ctx context.Context , req * pbapi.StartJoinGameRequest ) (* pbcommon.Empty , error ) {
431+ user := ctx .Value ("user" ).(* models.UserModel )
432+
433+ session , err := s .store .Sessions .GetByUserID (ctx , user .ID )
434+ if err != nil {
435+ logger .L ().Error ("Failed to get session" , zap .Error (err ))
436+ return nil , status .Error (codes .Internal , "Failed to get session" )
437+ }
438+
439+ if session == nil || session .PartyID == nil {
440+ return nil , status .Error (codes .NotFound , "You are not in a party" )
441+ }
442+
443+ party , err := s .store .Parties .GetByID (ctx , * session .PartyID )
444+ if err != nil {
445+ logger .L ().Error ("Failed to get party" , zap .Error (err ))
446+ return nil , status .Error (codes .Internal , "Failed to get party" )
447+ }
448+
449+ if party == nil {
450+ return nil , status .Error (codes .NotFound , "Party not found" )
451+ }
452+
453+ if party .LeaderID != user .ID {
454+ return nil , status .Error (codes .PermissionDenied , "Only the party leader can join a game" )
455+ }
456+
457+ server , err := s .store .Servers .GetByID (ctx , req .GetServerId ())
458+ if err != nil {
459+ logger .L ().Error ("Failed to get server" , zap .Error (err ))
460+ return nil , status .Error (codes .Internal , "Failed to get server" )
461+ }
462+
463+ if server == nil {
464+ return nil , status .Error (codes .NotFound , "Server not found" )
465+ }
466+
467+ punishment , err := s .store .Punishments .GetBanForServer (ctx , server .HostID , user .ID )
468+ if err != nil {
469+ logger .L ().Error ("Failed to check ban" , zap .Error (err ))
470+ return nil , status .Error (codes .Internal , "Failed to check ban" )
471+ }
472+
473+ if punishment != nil {
474+ reason := fmt .Sprintf ("You are banned from this server: %s" , * punishment .Reason )
475+ return nil , status .Error (codes .PermissionDenied , reason )
476+ }
477+
478+ if server .Password != nil && * server .Password != req .Password {
479+ return nil , status .Error (codes .PermissionDenied , "Invalid password" )
480+ }
481+
482+ sessions , err := s .store .Sessions .GetByPartyID (ctx , party .ID )
483+ if err != nil {
484+ logger .L ().Error ("Failed to get party sessions" , zap .Error (err ))
485+ return nil , status .Error (codes .Internal , "Failed to get party sessions" )
486+ }
487+
488+ memberIDs := make ([]string , len (sessions ))
489+ for i , sess := range sessions {
490+ memberIDs [i ] = sess .UserID
491+ }
492+
493+ if party .JoinGameState != nil {
494+ s .partyPub .Publish (party .ID , memberIDs , & pbapi.PartyEvent {
495+ Body : & pbapi.PartyEvent_JoinGameCancelled {
496+ JoinGameCancelled : & pbapi.JoinGameCancelledEvent {},
497+ },
498+ })
499+ }
500+
501+ mods := make ([]models.ServerModModel , len (server .Mods ))
502+ copy (mods , server .Mods )
503+
504+ joinGameState := & models.PartyJoinGameState {
505+ ServerID : server .ID ,
506+ ServerName : server .Name ,
507+ Mods : mods ,
508+ // TODO: automatically share server passwords?
509+ }
510+
511+ if err := s .store .Parties .Update (ctx , party .ID , bson.M {"$set" : bson.M {"join_game_state" : joinGameState }}); err != nil {
512+ logger .L ().Error ("Failed to save join game state" , zap .Error (err ))
513+ return nil , status .Error (codes .Internal , "Failed to start join game" )
514+ }
515+
516+ protoMods := make ([]* pbcommon.ServerMod , len (server .Mods ))
517+ for i , mod := range server .Mods {
518+ protoMods [i ] = & pbcommon.ServerMod {
519+ Name : mod .Name ,
520+ Version : mod .Version ,
521+ Link : mod .Link ,
522+ FileSize : mod .FileSize ,
523+ }
524+ }
525+
526+ s .partyPub .Publish (party .ID , memberIDs , & pbapi.PartyEvent {
527+ Body : & pbapi.PartyEvent_JoinGame {
528+ JoinGame : & pbapi.JoinGameEvent {
529+ ServerId : server .ID ,
530+ ServerName : server .Name ,
531+ Mods : protoMods ,
532+ LeaderId : user .ID ,
533+ },
534+ },
535+ })
536+
537+ return & pbcommon.Empty {}, nil
538+ }
539+
401540func (s * PartyService ) createParty (ctx context.Context , user models.UserModel ) (* models.PartyModel , error ) {
402541 partyID , err := s .store .Parties .GetNextID (ctx )
403542 if err != nil {
0 commit comments