Finished basic party v2 functionality

This commit is contained in:
Eccentric 2024-02-14 22:20:17 +00:00
parent 8021c1d436
commit bb3dbe5718
6 changed files with 96 additions and 53 deletions

View File

@ -117,8 +117,10 @@ func PostPartyCreate(c *fiber.Ctx) error {
party.AddMember(person)
party.UpdateMemberMeta(person, body.JoinInformation.Meta)
party.UpdateMemberConnection(person, body.JoinInformation.Connection)
party.ChangeNewCaptain()
socket.EmitPartyMemberJoined(party, party.GetMember(person))
member := party.GetMember(person)
party.PromoteMember(member)
socket.EmitPartyMemberJoined(party, member)
return c.Status(200).JSON(party.GenerateFortniteParty())
}
@ -134,11 +136,9 @@ func PatchPartyUpdateState(c *fiber.Ctx) error {
} `json:"meta"`
}
if err := c.BodyParser(&body); err != nil {
return c.Status(400).JSON(aid.ErrorBadRequest("Invalid Request"))
}
aid.PrintJSON(body)
party, ok := person.Parties.Get(c.Params("partyId"))
if !ok {
@ -212,8 +212,8 @@ func DeletePartyMember(c *fiber.Ctx) error {
party.RemoveMember(person)
if party.Captain.Person.ID == person.ID && len(party.Members) > 0 {
party.ChangeNewCaptain()
go socket.EmitPartyNewCaptain(party)
party.PromoteMember(party.GetFirstMember())
socket.EmitPartyNewCaptain(party)
}
return c.SendStatus(204)
@ -266,21 +266,6 @@ func PostPartyJoin(c *fiber.Ctx) error {
return c.Status(400).JSON(aid.ErrorBadRequest("Invalid Request"))
}
// joinability, ok := party.Config["joinability"].(string)
// if ok && joinability != "OPEN" {
// invite, ok := person.Invites.Get(c.Params("partyId"))
// if !ok {
// return c.Status(400).JSON(aid.ErrorBadRequest("Invite Not Found"))
// }
// if invite.Party.ID != party.ID {
// return c.Status(400).JSON(aid.ErrorBadRequest("Invite Not Found"))
// }
// person.Invites.Delete(c.Params("partyId"))
// party.RemoveInvite(invite)
// }
party.AddMember(person)
party.UpdateMemberMeta(person, body.Meta)
party.UpdateMemberConnection(person, body.Connection)
@ -295,3 +280,25 @@ func PostPartyJoin(c *fiber.Ctx) error {
"status": "JOINED",
})
}
func PostPartyPromoteMember(c *fiber.Ctx) error {
person := c.Locals("person").(*p.Person)
party, ok := person.Parties.Get(c.Params("partyId"))
if !ok {
return c.Status(400).JSON(aid.ErrorBadRequest("Party Not Found"))
}
member := party.GetMember(p.Find(c.Params("accountId")))
if member == nil {
return c.Status(400).JSON(aid.ErrorBadRequest("Member Not Found"))
}
if party.Captain.Person.ID != person.ID {
return c.Status(400).JSON(aid.ErrorBadRequest("Not Captain"))
}
party.PromoteMember(member)
socket.EmitPartyNewCaptain(party)
return c.SendStatus(204)
}

View File

@ -162,12 +162,12 @@ func main() {
party.Post("/parties", handlers.PostPartyCreate)
party.Post("/parties/:partyId/invites/:accountId", handlers.PostPartyInvite)
party.Post("/parties/:partyId/members/:accountId/join", handlers.PostPartyJoin)
party.Post("/parties/:partyId/members/:accountId/promote", handlers.PostPartyPromoteMember)
party.Patch("/parties/:partyId", handlers.PatchPartyUpdateState)
party.Patch("/parties/:partyId/members/:accountId/meta", handlers.PatchPartyUpdateMemberState)
party.Delete("/parties/:partyId/members/:accountId", handlers.DeletePartyMember)
// post /parties/:partyId/members/:accountId/conferences/connection (join a voip channel)
// delete /parties/:partyId/members/:accountid (remove a person from a party)
// get /user/:accountId/pings/:pinger/friendId/parties (get pings from a friend)
// post /user/:accountId/pings/:pinger/join (join a party from a ping)

View File

@ -55,6 +55,11 @@ type PartyMember struct{
Role string
JoinedAt time.Time
UpdatedAt time.Time
Revision int
}
func (pm *PartyMember) IncreaseRevision() {
pm.Revision++
}
func (pm *PartyMember) GenerateFortnitePartyMember() aid.JSON {
@ -67,7 +72,7 @@ func (pm *PartyMember) GenerateFortnitePartyMember() aid.JSON {
"meta": pm.Meta,
"joined_at": pm.JoinedAt.Format(time.RFC3339),
"connections": []aid.JSON{conn},
"revision": 0,
"revision": pm.Revision,
}
}
@ -79,6 +84,7 @@ type Party struct{
Config map[string]interface{}
Meta map[string]interface{}
CreatedAt time.Time
Revision int
m sync.Mutex
}
@ -105,6 +111,13 @@ func NewParty() *Party {
return party
}
func (p *Party) IncreaseRevision() {
p.m.Lock()
defer p.m.Unlock()
p.Revision++
}
func (p *Party) GetMember(person *Person) *PartyMember {
p.m.Lock()
defer p.m.Unlock()
@ -112,16 +125,24 @@ func (p *Party) GetMember(person *Person) *PartyMember {
return p.Members[person.ID]
}
func (p *Party) ChangeNewCaptain() {
func (p *Party) PromoteMember(member *PartyMember) {
p.m.Lock()
defer p.m.Unlock()
member.Role = "CAPTAIN"
member.UpdatedAt = time.Now()
p.Captain = member
}
func (p *Party) GetFirstMember() *PartyMember {
p.m.Lock()
defer p.m.Unlock()
for _, member := range p.Members {
p.Captain = member
p.Captain.Role = "CAPTAIN"
p.Captain.UpdatedAt = time.Now()
break
return member
}
return nil
}
func (p *Party) AddMember(person *Person) {

View File

@ -13,7 +13,6 @@
## What's up next?
- **Party System V2** Currently it relies on the automatic XMPP solution which is very hard to keep track of.
- Seeded randomization for the **Item Shop** instead of a random number generator. This will ensure that even if the backend is restarted, the same random items will be in the shop during that day.
- Purchasing the **Battle Pass**. This will require the Battle Pass Storefront ID for every build. I am yet to think of a solution for this.
- Interaction with a Game Server to handle **Event Tracking** for player statistics and challenges. This will be a very large task as a new specialised game server will need to be created.
@ -33,4 +32,4 @@ And once battle royale is completed ...
## Contributing
Contributions are welcome! Please open an issue or pull request if you would like to contribute. Make sure to follow the same format (2 space indents) and style! Make sure to keep commits concise and readable e.g. do not change formating to mess up code review!
Contributions are welcome! Please open an issue or pull request if you would like to contribute. Make sure to follow the same formatting and to keep commits concise and readable e.g. do not change line indents to mess up code review!

View File

@ -14,6 +14,7 @@ func EmitPartyMemberJoined(party *person.Party, joiningMember *person.PartyMembe
continue
}
joiningMember.IncreaseRevision()
s.JabberSendMessageToPerson(aid.JSON{
"account_id": joiningMember.Person.ID,
"account_dn": joiningMember.Person.DisplayName,
@ -24,7 +25,7 @@ func EmitPartyMemberJoined(party *person.Party, joiningMember *person.PartyMembe
"ns": "Fortnite",
"party_id": party.ID,
"sent": time.Now().Format(time.RFC3339),
"revision": 0,
"revision": joiningMember.Revision,
"type": "com.epicgames.social.party.notification.v0.MEMBER_JOINED",
})
@ -47,20 +48,21 @@ func EmitPartyMemberJoined(party *person.Party, joiningMember *person.PartyMembe
}
}
func EmitPartyMemberLeft(party *person.Party, member *person.PartyMember) {
func EmitPartyMemberLeft(party *person.Party, leavingMember *person.PartyMember) {
for _, m := range party.Members {
s, ok := JabberSockets.Get(m.Person.ID)
if !ok {
continue
}
leavingMember.IncreaseRevision()
s.JabberSendMessageToPerson(aid.JSON{
"account_id": member.Person.ID,
"account_id": leavingMember.Person.ID,
"member_state_updated": aid.JSON{},
"ns": "Fortnite",
"party_id": party.ID,
"sent": time.Now().Format(time.RFC3339),
"revision": 0,
"revision": leavingMember.Revision,
"type": "com.epicgames.social.party.notification.v0.MEMBER_LEFT",
})
}
@ -73,6 +75,7 @@ func EmitPartyMemberMetaUpdated(party *person.Party, member *person.PartyMember,
continue
}
member.IncreaseRevision()
s.JabberSendMessageToPerson(aid.JSON{
"account_id": member.Person.ID,
"account_dn": member.Person.DisplayName,
@ -84,7 +87,7 @@ func EmitPartyMemberMetaUpdated(party *person.Party, member *person.PartyMember,
"ns": "Fortnite",
"party_id": party.ID,
"sent": time.Now().Format(time.RFC3339),
"revision": 0,
"revision": member.Revision,
"type": "com.epicgames.social.party.notification.v0.MEMBER_STATE_UPDATED",
})
}
@ -97,6 +100,7 @@ func EmitPartyMetaUpdated(party *person.Party, override map[string]interface{},
continue
}
party.IncreaseRevision()
s.JabberSendMessageToPerson(aid.JSON{
"captain_id": party.Captain.Person.ID,
"party_state_updated": update,
@ -113,11 +117,9 @@ func EmitPartyMetaUpdated(party *person.Party, override map[string]interface{},
"ns": "Fortnite",
"party_id": party.ID,
"sent": time.Now().Format(time.RFC3339),
"revision": 0,
"revision": party.Revision,
"type": "com.epicgames.social.party.notification.v0.PARTY_UPDATED",
})
aid.Print("EmitPartyMetaUpdated party", party.ID, "to", m.Person.DisplayName)
}
}
@ -128,13 +130,14 @@ func EmitPartyNewCaptain(party *person.Party) {
continue
}
party.IncreaseRevision()
s.JabberSendMessageToPerson(aid.JSON{
"account_id": party.Captain.Person.ID,
"account_dn": party.Captain.Person.DisplayName,
"ns": "Fortnite",
"party_id": party.ID,
"sent": time.Now().Format(time.RFC3339),
"revision": 0,
"revision": party.Revision,
"type": "com.epicgames.social.party.notification.v0.MEMBER_NEW_CAPTAIN",
})
}
@ -154,7 +157,7 @@ func EmitPartyInvite(invite *person.PartyInvite) {
"sent_at": invite.CreatedAt.Format(time.RFC3339),
"updated_at": invite.UpdatedAt.Format(time.RFC3339),
"friends_ids": []string{},
"members_count": 0,
"members_count": len(invite.Party.Members),
"party_id": invite.Party.ID,
"ns": "Fortnite",
"sent": time.Now().Format(time.RFC3339),

View File

@ -3,7 +3,6 @@ package socket
import (
"fmt"
"reflect"
"strings"
"github.com/beevik/etree"
"github.com/ectrc/snow/aid"
@ -172,23 +171,37 @@ func jabberPresenceJoinGroupchat(socket *Socket[JabberData], parsed *etree.Docum
}
func jabberMessageHandler(socket *Socket[JabberData], parsed *etree.Document) error {
if parsed.FindElement("/message/body") == nil {
return nil
}
message := parsed.FindElement("/message")
target := message.SelectAttr("to").Value
parts := strings.Split(target, "@")
if len(parts) != 2 {
if message.FindElement("/body") == nil {
return nil
}
if reciever, ok := JabberSockets.Get(parts[0]); ok {
reciever.Write([]byte(`<message xmlns="jabber:client" from="`+ socket.Data.JabberID +`" to="`+ target +`" id="`+ message.SelectAttr("id").Value +`">
<body>`+ message.FindElement("/message/body").Text() +`</body>
</message>`))
towards := message.SelectAttr("to")
if towards == nil {
return nil
}
redirect := map[string]func(*Socket[JabberData], *etree.Document) error {
"chat": jabberMessageChatHandler,
"groupchat": jabberMessageGroupchatHandler,
}
if handler, ok := redirect[towards.Value]; ok {
if err := handler(socket, parsed); err != nil {
return err
}
}
return nil
}
// TODO: IMPLEMENT WHISPERING
func jabberMessageChatHandler(socket *Socket[JabberData], parsed *etree.Document) error {
return nil
}
func jabberMessageGroupchatHandler(socket *Socket[JabberData], parsed *etree.Document) error {
return nil
}