Skip to content

Commit

Permalink
Partially Implement Papel Shop (#2)
Browse files Browse the repository at this point in the history
* Partially Implement Papel Shop

* Apply suggestions from code review

Co-authored-by: jchv <john@jchw.io>

* Update game/packet/server.go

Co-authored-by: jchv <john@jchw.io>

---------

Co-authored-by: jchv <john@jchw.io>
  • Loading branch information
JMC47 and jchv committed Jul 3, 2023
1 parent b7d9af0 commit 7dd3426
Show file tree
Hide file tree
Showing 7 changed files with 345 additions and 1 deletion.
23 changes: 23 additions & 0 deletions game/packet/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ var ClientMessageTable = common.NewMessageTable(map[uint16]ClientMessage{
0x0082: &ClientMultiplayerLeave{},
0x0088: &Client0088{},
0x008B: &ClientRequestMessengerList{},
0x0098: &ClientRareShopOpen{},
0x009C: &ClientRequestPlayerHistory{},
0x00AE: &ClientTutorialClear{},
0x00B5: &ClientEnterMyRoom{},
Expand All @@ -81,10 +82,13 @@ var ClientMessageTable = common.NewMessageTable(map[uint16]ClientMessage{
0x0140: &ClientShopJoin{},
0x0143: &ClientRequestInboxList{},
0x0144: &ClientRequestInboxMessage{},
0x014B: &ClientBlackPapelPlay{},
0x0157: &ClientAchievementStatusRequest{},
0x016E: &ClientRequestDailyReward{},
0x0176: &ClientEventLobbyJoin{},
0x0177: &ClientEventLobbyLeave{},
0x0184: &ClientAssistModeToggle{},
0x0186: &ClientBigPapelPlay{},
})

// ClientAuth is a message sent to authenticate a session.
Expand Down Expand Up @@ -112,6 +116,11 @@ type ClientGetUserOnlineStatus struct {
Username common.PString
}

// ClientRareShopOpen notifies the server if a user opens the rare shop menu.
type ClientRareShopOpen struct {
ClientMessage_
}

// ClientRoomEdit is sent when the client changes room settings.
type ClientRoomEdit struct {
ClientMessage_
Expand Down Expand Up @@ -383,6 +392,12 @@ type ClientRequestMessengerList struct {
ClientMessage_
}

// ClientAchievementStatusRequest requests Achievement Status for a user.
type ClientAchievementStatusRequest struct {
ClientMessage_
UserID uint32
}

// ClientGetUserData is a message sent by the client to request
// the client state.
type ClientGetUserData struct {
Expand Down Expand Up @@ -517,3 +532,11 @@ type ClientLockerInventoryRequest struct {
type Client00FE struct {
ClientMessage_
}

type ClientBlackPapelPlay struct {
ClientMessage_
}

type ClientBigPapelPlay struct {
ClientMessage_
}
75 changes: 74 additions & 1 deletion game/packet/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ var ServerMessageTable = common.NewMessageTable(map[uint16]ServerMessage{
0x00F1: &ServerMessageConnect{},
0x00F5: &ServerMultiplayerJoined{},
0x00F6: &ServerMultiplayerLeft{},
0x00FB: &ServerBlackPapelResponse{},
0x010B: &ServerRareShopOpen{},
0x010E: &ServerPlayerHistory{},
0x011F: &ServerTutorialStatus{},
0x012B: &ServerMyRoomEntered{},
Expand All @@ -89,13 +91,17 @@ var ServerMessageTable = common.NewMessageTable(map[uint16]ServerMessage{
0x0211: &ServerInboxList{},
0x0212: &ServerMailMessage{},
0x0216: &ServerUserStatusUpdate{},
0x021B: &ServerBlackPapelWinnings{},
0x021D: &ServerAchievementProgress{},
0x022C: &ServerAchievementUnknownResponse{},
0x022D: &ServerAchievementStatusResponse{},
0x0230: &Server0230{},
0x0231: &Server0231{},
0x0248: &ServerLoginBonusStatus{},
0x0250: &ServerEventLobbyJoined{},
0x0251: &ServerEventLobbyLeft{},
0x026A: &ServerAssistModeToggled{},
0x026C: &ServerBigPapelWinnings{},
})

// ConnectMessage is the message sent upon connecting.
Expand Down Expand Up @@ -250,6 +256,39 @@ type GamePlayer struct {
NumCards uint8
}

type ServerRareShopOpen struct {
ServerMessage_
UnknownA int32
UnknownB int32
UnknownC uint32
}

type Achievement struct {
ID uint32
Value uint32
Timestamp uint32
}

type AchievementGroup struct {
GroupID uint32
ID uint32
Count uint32 `struct:"sizeof=Achievements"`
Achievements []Achievement
}

type ServerAchievementStatusResponse struct {
ServerMessage_
Status uint32
Remaining uint32
Count uint32 `struct:"sizeof=Groups"`
Groups []AchievementGroup
}

type ServerAchievementUnknownResponse struct {
ServerMessage_
UnknownA [4]byte
}

type GameInitFull struct {
NumPlayers byte `struct:"sizeof=Players"`
Players []GamePlayer
Expand Down Expand Up @@ -299,7 +338,7 @@ type ServerRoomAction struct {
gamemodel.RoomAction
}

// ServerPangBalanceData is sent after a pang purchase succeeds.
// ServerPangBalanceData is sent after a pang purchase succeeds. Sometimes Pang Spent is not set like on Black Papel Transactions.
type ServerPangBalanceData struct {
ServerMessage_
PangsRemaining uint64
Expand Down Expand Up @@ -878,3 +917,37 @@ type ServerAssistModeToggled struct {
ServerMessage_
Unknown uint32
}

type ServerBlackPapelWinnings struct {
ServerMessage_
Status uint32
BlackPapelInvTicketSlot uint32
UniqueItemsWon uint32 `struct:"sizeof=Items"`
Items []ServerBlackPapelItems
PangsRemaining uint64
CookiesRemaining uint64 // not filled in but seems correct
}

type ServerBlackPapelResponse struct {
ServerMessage_
RemainingTurns int32
UnknownA int32
}

type ServerBlackPapelItems struct {
DolfiniBallColor uint32
ItemTypeID uint32
InventorySlot uint32
Quantity uint32
Rarity uint32
}

type ServerBigPapelWinnings struct {
ServerMessage_
Status uint32
BlackPapelInvTicketSlot uint32
UniqueItemsWon uint32 `struct:"sizeof=Items"`
Items []ServerBlackPapelItems
PangsRemaining uint64
CookiesRemaining uint64
}
119 changes: 119 additions & 0 deletions game/server/conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import (
"context"
"errors"
"fmt"
"math/rand"
"time"

"github.com/pangbox/server/common"
"github.com/pangbox/server/database/accounts"
Expand Down Expand Up @@ -416,6 +418,123 @@ func (c *Conn) Handle(ctx context.Context) error {
})
case *gamepacket.Client0088:
// Unknown tutorial-related message.
case *gamepacket.ClientRareShopOpen:
c.SendMessage(ctx, &gamepacket.ServerRareShopOpen{
UnknownA: 50, // Prevents "No Draws Left" bug with Big Papel Shop
})

case *gamepacket.ClientAchievementStatusRequest:
c.SendMessage(ctx, &gamepacket.ServerAchievementStatusResponse{
// TODO: Actually support achievements. This is the bare minimum not to hang/crash the game.
Remaining: 1,
Count: 1,
Groups: []gamepacket.AchievementGroup{
{
GroupID: 0x4c80002d,
ID: 248388034,
Count: 5,
Achievements: []gamepacket.Achievement{
{
ID: 0x7480087c,
Value: 1,
Timestamp: uint32(time.Date(2018, 11, 3, 0, 25, 10, 0, time.UTC).Unix()),
},
{
ID: 0x7480087d,
Value: 3,
Timestamp: uint32(time.Date(2018, 11, 7, 2, 5, 26, 0, time.UTC).Unix()),
},
{
ID: 0x7480087e,
Value: 5,
Timestamp: uint32(time.Date(2018, 11, 7, 3, 3, 45, 0, time.UTC).Unix()),
},
{
ID: 0x7480087f,
Value: 7,
Timestamp: uint32(time.Date(2018, 11, 8, 23, 27, 19, 0, time.UTC).Unix()),
},
{
ID: 0x74800880,
Value: 10,
Timestamp: uint32(time.Date(2019, 8, 25, 19, 39, 45, 0, time.UTC).Unix()),
},
},
},
},
})
c.SendMessage(ctx, &gamepacket.ServerAchievementUnknownResponse{
UnknownA: [4]byte{0x00, 0x00, 0x00, 0x00},
})
case *gamepacket.ClientBigPapelPlay:
c.SendMessage(ctx, &gamepacket.ServerBlackPapelResponse{
RemainingTurns: 50, // Displays as remaining turns in the box.
UnknownA: -1,
})
// TODO: make Pang interaction transactional
// TODO: make items show up in inventory
// TODO: make sure not to subtract pang if a ticket is used.
// TODO: Fix pang able to go negative.
c.player.Pang, err = c.s.accountsService.AddPang(ctx, c.player.PlayerID, -10000)
if err != nil {
return err
}
packet := &gamepacket.ServerBigPapelWinnings{}
const BigPapelItems = 10 // Unknown if this is actually how the number of items are actually chosen.
itemQuantities := make(map[uint32]int)
for i := 0; i < BigPapelItems; i++ {
typeID := c.s.papelShop.Choose()
rarity := c.s.papelRarity[typeID]
if rarity == 2 {
itemQuantities[typeID] = 1 // Technically should be possible to get multiple of the same rare item here.
} else {
itemQuantities[typeID] += 1 + rand.Intn(2)
}
}
for typeID, quantity := range itemQuantities {
item := gamepacket.ServerBlackPapelItems{}
item.ItemTypeID = typeID
item.Quantity = uint32(quantity)
packet.Items = append(packet.Items, item)
}
packet.PangsRemaining = uint64(c.player.Pang) // This should be calculated by player data
packet.CookiesRemaining = uint64(c.player.Points) // Cookies remaining even if the action doesn't cost cookies
c.SendMessage(ctx, packet)
case *gamepacket.ClientBlackPapelPlay:
// TODO: make Pang interaction transactional.
// TODO: make items show up in inventory.
// TODO: make sure not to subtract pang if a ticket is used.
c.player.Pang, err = c.s.accountsService.AddPang(ctx, c.player.PlayerID, -500)
if err != nil {
return err
}
packet := &gamepacket.ServerBlackPapelWinnings{}
drawnItemsSet := make(map[uint32]struct{})
for i := rand.Intn(4) + 1; i > 0; {
item := gamepacket.ServerBlackPapelItems{}
var typeID uint32
for {
typeID = c.s.papelShop.Choose()
if _, ok := drawnItemsSet[typeID]; !ok {
drawnItemsSet[typeID] = struct{}{}
break
}
}
item.ItemTypeID = typeID
item.DolfiniBallColor = uint32(rand.Intn(3))
item.Rarity = c.s.papelRarity[typeID]
if item.Rarity == 2 {
item.Quantity = 1
} else {
item.Quantity = uint32(rand.Intn(3) + 1)
}
packet.UniqueItemsWon += 1
packet.Items = append(packet.Items, item)
i--
}
packet.PangsRemaining = uint64(c.player.Pang)
packet.CookiesRemaining = uint64(c.player.Points)
c.SendMessage(ctx, packet)
case *gamepacket.ClientRoomUserEquipmentChange:
// TODO
case *gamepacket.ClientTutorialStart:
Expand Down
10 changes: 10 additions & 0 deletions game/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,19 @@ type Server struct {
configProvider gameconfig.Provider
lobby *room.Lobby
logger *log.Entry
papelShop *WeightedRand
papelRarity map[uint32]uint32
}

// New creates a new instance of the game server.
func New(opts Options) *Server {
logger := log.WithField("server", "GameServer")
papelShop := NewWeightedRand()
papelRarity := make(map[uint32]uint32)
for _, item := range opts.ConfigProvider.GetPapelShopOdds() {
papelShop.Add(item.TypeID, item.Weight)
papelRarity[item.TypeID] = uint32(item.Rarity)
}
return &Server{
baseServer: &common.BaseServer{},
topologyClient: opts.TopologyClient,
Expand All @@ -66,6 +74,8 @@ func New(opts Options) *Server {
channelName: opts.ChannelName,
configProvider: opts.ConfigProvider,
logger: logger,
papelShop: papelShop,
papelRarity: papelRarity,
}
}

Expand Down
Loading

0 comments on commit 7dd3426

Please sign in to comment.