Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Partially Implement Papel Shop #2

Merged
merged 3 commits into from
Jul 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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{
jchv marked this conversation as resolved.
Show resolved Hide resolved
// 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