Browse Source

game player logic

master
tangmingyou 4 years ago
parent
commit
b3ec5db737
  1. 11
      api/operation.go
  2. 683
      api/poker.pb.go
  3. 11
      api/poker.proto
  4. 2061
      api/proto.js
  5. 5
      etc/config.toml
  6. 5
      internal/conf/conf.go
  7. 2
      internal/dao/dao.go
  8. 16
      internal/dao/user_dao.go
  9. 9
      internal/game/player.go
  10. 37
      internal/game/table.go
  11. 7
      internal/letter/proto_writer.go
  12. 1
      internal/model/entity/user.go
  13. 6
      internal/server/route.go
  14. 30
      internal/server/wsroute.go
  15. 30
      internal/service/auth.go
  16. 40
      internal/service/store/store.go
  17. 92
      internal/service/table.go
  18. 38
      internal/session/net_account.go
  19. 13
      internal/session/player.go

11
api/operation.go

@ -29,7 +29,16 @@ var protoInstances = []proto.Message{
&ResCreateTable{},
&ReqJoinTable{},
&ResJoinTable{},
&ReqLeaveTable{},
&ReqGameAction{},
&ResGameAction{},
&ReqGameStatus{},
&ResGameStatus{},
&ReqReadyStart{},
&ReqKickOutTable{},
}
var (

683
api/poker.pb.go

@ -720,6 +720,8 @@ type ReqJoinTable struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
TableNo int32 `protobuf:"varint,1,opt,name=tableNo,proto3" json:"tableNo,omitempty"`
}
func (x *ReqJoinTable) Reset() {
@ -754,14 +756,22 @@ func (*ReqJoinTable) Descriptor() ([]byte, []int) {
return file_poker_proto_rawDescGZIP(), []int{13}
}
type ResJoinTable struct {
func (x *ReqJoinTable) GetTableNo() int32 {
if x != nil {
return x.TableNo
}
return 0
}
// 离开房间
type ReqLeaveTable struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ResJoinTable) Reset() {
*x = ResJoinTable{}
func (x *ReqLeaveTable) Reset() {
*x = ReqLeaveTable{}
if protoimpl.UnsafeEnabled {
mi := &file_poker_proto_msgTypes[14]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@ -769,13 +779,13 @@ func (x *ResJoinTable) Reset() {
}
}
func (x *ResJoinTable) String() string {
func (x *ReqLeaveTable) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ResJoinTable) ProtoMessage() {}
func (*ReqLeaveTable) ProtoMessage() {}
func (x *ResJoinTable) ProtoReflect() protoreflect.Message {
func (x *ReqLeaveTable) ProtoReflect() protoreflect.Message {
mi := &file_poker_proto_msgTypes[14]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@ -787,11 +797,467 @@ func (x *ResJoinTable) ProtoReflect() protoreflect.Message {
return mi.MessageOf(x)
}
// Deprecated: Use ResJoinTable.ProtoReflect.Descriptor instead.
func (*ResJoinTable) Descriptor() ([]byte, []int) {
// Deprecated: Use ReqLeaveTable.ProtoReflect.Descriptor instead.
func (*ReqLeaveTable) Descriptor() ([]byte, []int) {
return file_poker_proto_rawDescGZIP(), []int{14}
}
// 玩家准备开始
type ReqReadyStart struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ReqReadyStart) Reset() {
*x = ReqReadyStart{}
if protoimpl.UnsafeEnabled {
mi := &file_poker_proto_msgTypes[15]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ReqReadyStart) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReqReadyStart) ProtoMessage() {}
func (x *ReqReadyStart) ProtoReflect() protoreflect.Message {
mi := &file_poker_proto_msgTypes[15]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReqReadyStart.ProtoReflect.Descriptor instead.
func (*ReqReadyStart) Descriptor() ([]byte, []int) {
return file_poker_proto_rawDescGZIP(), []int{15}
}
// 房主踢人
type ReqKickOutTable struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
PlayerId int32 `protobuf:"varint,1,opt,name=playerId,proto3" json:"playerId,omitempty"`
}
func (x *ReqKickOutTable) Reset() {
*x = ReqKickOutTable{}
if protoimpl.UnsafeEnabled {
mi := &file_poker_proto_msgTypes[16]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ReqKickOutTable) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReqKickOutTable) ProtoMessage() {}
func (x *ReqKickOutTable) ProtoReflect() protoreflect.Message {
mi := &file_poker_proto_msgTypes[16]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReqKickOutTable.ProtoReflect.Descriptor instead.
func (*ReqKickOutTable) Descriptor() ([]byte, []int) {
return file_poker_proto_rawDescGZIP(), []int{16}
}
func (x *ReqKickOutTable) GetPlayerId() int32 {
if x != nil {
return x.PlayerId
}
return 0
}
type ReqGameAction struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Action int32 `protobuf:"varint,1,opt,name=action,proto3" json:"action,omitempty"` // 4下大盲注,5下小盲注,6跟注,7弃牌
Chip int32 `protobuf:"varint,2,opt,name=chip,proto3" json:"chip,omitempty"` // 押注金额
}
func (x *ReqGameAction) Reset() {
*x = ReqGameAction{}
if protoimpl.UnsafeEnabled {
mi := &file_poker_proto_msgTypes[17]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ReqGameAction) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReqGameAction) ProtoMessage() {}
func (x *ReqGameAction) ProtoReflect() protoreflect.Message {
mi := &file_poker_proto_msgTypes[17]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReqGameAction.ProtoReflect.Descriptor instead.
func (*ReqGameAction) Descriptor() ([]byte, []int) {
return file_poker_proto_rawDescGZIP(), []int{17}
}
func (x *ReqGameAction) GetAction() int32 {
if x != nil {
return x.Action
}
return 0
}
func (x *ReqGameAction) GetChip() int32 {
if x != nil {
return x.Chip
}
return 0
}
type ResGameAction struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ResGameAction) Reset() {
*x = ResGameAction{}
if protoimpl.UnsafeEnabled {
mi := &file_poker_proto_msgTypes[18]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ResGameAction) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ResGameAction) ProtoMessage() {}
func (x *ResGameAction) ProtoReflect() protoreflect.Message {
mi := &file_poker_proto_msgTypes[18]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ResGameAction.ProtoReflect.Descriptor instead.
func (*ResGameAction) Descriptor() ([]byte, []int) {
return file_poker_proto_rawDescGZIP(), []int{18}
}
// 查询玩家当前游戏状态
type ReqGameStatus struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ReqGameStatus) Reset() {
*x = ReqGameStatus{}
if protoimpl.UnsafeEnabled {
mi := &file_poker_proto_msgTypes[19]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ReqGameStatus) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReqGameStatus) ProtoMessage() {}
func (x *ReqGameStatus) ProtoReflect() protoreflect.Message {
mi := &file_poker_proto_msgTypes[19]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReqGameStatus.ProtoReflect.Descriptor instead.
func (*ReqGameStatus) Descriptor() ([]byte, []int) {
return file_poker_proto_rawDescGZIP(), []int{19}
}
type ResGameStatus struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
InGame bool `protobuf:"varint,1,opt,name=inGame,proto3" json:"inGame,omitempty"` // 是否在游戏中
TableNo int32 `protobuf:"varint,2,opt,name=tableNo,proto3" json:"tableNo,omitempty"` // 所在桌面编号
GameStage int32 `protobuf:"varint,3,opt,name=gameStage,proto3" json:"gameStage,omitempty"` // 游戏阶段?
Players []*TablePlayer `protobuf:"bytes,10,rep,name=players,proto3" json:"players,omitempty"`
}
func (x *ResGameStatus) Reset() {
*x = ResGameStatus{}
if protoimpl.UnsafeEnabled {
mi := &file_poker_proto_msgTypes[20]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ResGameStatus) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ResGameStatus) ProtoMessage() {}
func (x *ResGameStatus) ProtoReflect() protoreflect.Message {
mi := &file_poker_proto_msgTypes[20]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ResGameStatus.ProtoReflect.Descriptor instead.
func (*ResGameStatus) Descriptor() ([]byte, []int) {
return file_poker_proto_rawDescGZIP(), []int{20}
}
func (x *ResGameStatus) GetInGame() bool {
if x != nil {
return x.InGame
}
return false
}
func (x *ResGameStatus) GetTableNo() int32 {
if x != nil {
return x.TableNo
}
return 0
}
func (x *ResGameStatus) GetGameStage() int32 {
if x != nil {
return x.GameStage
}
return 0
}
func (x *ResGameStatus) GetPlayers() []*TablePlayer {
if x != nil {
return x.Players
}
return nil
}
type TablePlayer struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Robot bool `protobuf:"varint,1,opt,name=robot,proto3" json:"robot,omitempty"` // 是否机器人
Id int64 `protobuf:"varint,2,opt,name=id,proto3" json:"id,omitempty"`
Username string `protobuf:"bytes,3,opt,name=username,proto3" json:"username,omitempty"`
Avatar string `protobuf:"bytes,4,opt,name=avatar,proto3" json:"avatar,omitempty"`
Chip int32 `protobuf:"varint,5,opt,name=chip,proto3" json:"chip,omitempty"` // 筹码
Status int32 `protobuf:"varint,6,opt,name=status,proto3" json:"status,omitempty"` // 玩家状态: 1待准备开始,2已准备开始,已开始(3等待其他玩家动作,4待大盲注,5待小盲注,6待跟注,7已弃)
Master bool `protobuf:"varint,7,opt,name=master,proto3" json:"master,omitempty"` // 是否房主`
HandCard []*Card `protobuf:"bytes,8,rep,name=handCard,proto3" json:"handCard,omitempty"` // 手牌
PublicCard []*Card `protobuf:"bytes,9,rep,name=publicCard,proto3" json:"publicCard,omitempty"` // 公共牌
}
func (x *TablePlayer) Reset() {
*x = TablePlayer{}
if protoimpl.UnsafeEnabled {
mi := &file_poker_proto_msgTypes[21]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *TablePlayer) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TablePlayer) ProtoMessage() {}
func (x *TablePlayer) ProtoReflect() protoreflect.Message {
mi := &file_poker_proto_msgTypes[21]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TablePlayer.ProtoReflect.Descriptor instead.
func (*TablePlayer) Descriptor() ([]byte, []int) {
return file_poker_proto_rawDescGZIP(), []int{21}
}
func (x *TablePlayer) GetRobot() bool {
if x != nil {
return x.Robot
}
return false
}
func (x *TablePlayer) GetId() int64 {
if x != nil {
return x.Id
}
return 0
}
func (x *TablePlayer) GetUsername() string {
if x != nil {
return x.Username
}
return ""
}
func (x *TablePlayer) GetAvatar() string {
if x != nil {
return x.Avatar
}
return ""
}
func (x *TablePlayer) GetChip() int32 {
if x != nil {
return x.Chip
}
return 0
}
func (x *TablePlayer) GetStatus() int32 {
if x != nil {
return x.Status
}
return 0
}
func (x *TablePlayer) GetMaster() bool {
if x != nil {
return x.Master
}
return false
}
func (x *TablePlayer) GetHandCard() []*Card {
if x != nil {
return x.HandCard
}
return nil
}
func (x *TablePlayer) GetPublicCard() []*Card {
if x != nil {
return x.PublicCard
}
return nil
}
type Card struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Dot int32 `protobuf:"varint,1,opt,name=dot,proto3" json:"dot,omitempty"` // 点数
Suit int32 `protobuf:"varint,2,opt,name=suit,proto3" json:"suit,omitempty"` // 花色
}
func (x *Card) Reset() {
*x = Card{}
if protoimpl.UnsafeEnabled {
mi := &file_poker_proto_msgTypes[22]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Card) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Card) ProtoMessage() {}
func (x *Card) ProtoReflect() protoreflect.Message {
mi := &file_poker_proto_msgTypes[22]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Card.ProtoReflect.Descriptor instead.
func (*Card) Descriptor() ([]byte, []int) {
return file_poker_proto_rawDescGZIP(), []int{22}
}
func (x *Card) GetDot() int32 {
if x != nil {
return x.Dot
}
return 0
}
func (x *Card) GetSuit() int32 {
if x != nil {
return x.Suit
}
return 0
}
var File_poker_proto protoreflect.FileDescriptor
var file_poker_proto_rawDesc = []byte{
@ -842,10 +1308,50 @@ var file_poker_proto_rawDesc = []byte{
0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x73, 0x22,
0x2a, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x61, 0x62, 0x6c,
0x65, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x6f, 0x18, 0x01, 0x20, 0x01,
0x28, 0x05, 0x52, 0x07, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x6f, 0x22, 0x0e, 0x0a, 0x0c, 0x52,
0x65, 0x71, 0x4a, 0x6f, 0x69, 0x6e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x0e, 0x0a, 0x0c, 0x52,
0x65, 0x73, 0x4a, 0x6f, 0x69, 0x6e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x0b, 0x5a, 0x09, 0x2e,
0x2f, 0x61, 0x70, 0x69, 0x3b, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x28, 0x05, 0x52, 0x07, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x6f, 0x22, 0x28, 0x0a, 0x0c, 0x52,
0x65, 0x71, 0x4a, 0x6f, 0x69, 0x6e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x74,
0x61, 0x62, 0x6c, 0x65, 0x4e, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x74, 0x61,
0x62, 0x6c, 0x65, 0x4e, 0x6f, 0x22, 0x0f, 0x0a, 0x0d, 0x52, 0x65, 0x71, 0x4c, 0x65, 0x61, 0x76,
0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x0f, 0x0a, 0x0d, 0x52, 0x65, 0x71, 0x52, 0x65, 0x61,
0x64, 0x79, 0x53, 0x74, 0x61, 0x72, 0x74, 0x22, 0x2d, 0x0a, 0x0f, 0x52, 0x65, 0x71, 0x4b, 0x69,
0x63, 0x6b, 0x4f, 0x75, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c,
0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x6c,
0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x22, 0x3b, 0x0a, 0x0d, 0x52, 0x65, 0x71, 0x47, 0x61, 0x6d,
0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12,
0x12, 0x0a, 0x04, 0x63, 0x68, 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x63,
0x68, 0x69, 0x70, 0x22, 0x0f, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x47, 0x61, 0x6d, 0x65, 0x41, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x22, 0x0f, 0x0a, 0x0d, 0x52, 0x65, 0x71, 0x47, 0x61, 0x6d, 0x65, 0x53,
0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x8b, 0x01, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x47, 0x61, 0x6d,
0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x6e, 0x47, 0x61, 0x6d,
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, 0x6e, 0x47, 0x61, 0x6d, 0x65, 0x12,
0x18, 0x0a, 0x07, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05,
0x52, 0x07, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4e, 0x6f, 0x12, 0x1c, 0x0a, 0x09, 0x67, 0x61, 0x6d,
0x65, 0x53, 0x74, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x67, 0x61,
0x6d, 0x65, 0x53, 0x74, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x07, 0x70, 0x6c, 0x61, 0x79, 0x65,
0x72, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x54,
0x61, 0x62, 0x6c, 0x65, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x52, 0x07, 0x70, 0x6c, 0x61, 0x79,
0x65, 0x72, 0x73, 0x22, 0xfd, 0x01, 0x0a, 0x0b, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x50, 0x6c, 0x61,
0x79, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01,
0x28, 0x08, 0x52, 0x05, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65,
0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65,
0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18,
0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x12, 0x0a,
0x04, 0x63, 0x68, 0x69, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x63, 0x68, 0x69,
0x70, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28,
0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x61, 0x73,
0x74, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x6d, 0x61, 0x73, 0x74, 0x65,
0x72, 0x12, 0x25, 0x0a, 0x08, 0x68, 0x61, 0x6e, 0x64, 0x43, 0x61, 0x72, 0x64, 0x18, 0x08, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x61, 0x72, 0x64, 0x52, 0x08,
0x68, 0x61, 0x6e, 0x64, 0x43, 0x61, 0x72, 0x64, 0x12, 0x29, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c,
0x69, 0x63, 0x43, 0x61, 0x72, 0x64, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x61,
0x70, 0x69, 0x2e, 0x43, 0x61, 0x72, 0x64, 0x52, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x43,
0x61, 0x72, 0x64, 0x22, 0x2c, 0x0a, 0x04, 0x43, 0x61, 0x72, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x64,
0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x64, 0x6f, 0x74, 0x12, 0x12, 0x0a,
0x04, 0x73, 0x75, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x73, 0x75, 0x69,
0x74, 0x42, 0x0b, 0x5a, 0x09, 0x2e, 0x2f, 0x61, 0x70, 0x69, 0x3b, 0x61, 0x70, 0x69, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@ -860,32 +1366,43 @@ func file_poker_proto_rawDescGZIP() []byte {
return file_poker_proto_rawDescData
}
var file_poker_proto_msgTypes = make([]protoimpl.MessageInfo, 15)
var file_poker_proto_msgTypes = make([]protoimpl.MessageInfo, 23)
var file_poker_proto_goTypes = []interface{}{
(*ProtoWrap)(nil), // 0: api.ProtoWrap
(*Ping)(nil), // 1: api.Ping
(*Pong)(nil), // 2: api.Pong
(*ResSuccess)(nil), // 3: api.ResSuccess
(*ResFail)(nil), // 4: api.ResFail
(*ReqIdentity)(nil), // 5: api.ReqIdentity
(*ResIdentity)(nil), // 6: api.ResIdentity
(*ReqLobbyView)(nil), // 7: api.ReqLobbyView
(*ResLobbyView)(nil), // 8: api.ResLobbyView
(*LobbyTable)(nil), // 9: api.LobbyTable
(*LobbyPlayer)(nil), // 10: api.LobbyPlayer
(*ReqCreateTable)(nil), // 11: api.ReqCreateTable
(*ResCreateTable)(nil), // 12: api.ResCreateTable
(*ReqJoinTable)(nil), // 13: api.ReqJoinTable
(*ResJoinTable)(nil), // 14: api.ResJoinTable
(*ProtoWrap)(nil), // 0: api.ProtoWrap
(*Ping)(nil), // 1: api.Ping
(*Pong)(nil), // 2: api.Pong
(*ResSuccess)(nil), // 3: api.ResSuccess
(*ResFail)(nil), // 4: api.ResFail
(*ReqIdentity)(nil), // 5: api.ReqIdentity
(*ResIdentity)(nil), // 6: api.ResIdentity
(*ReqLobbyView)(nil), // 7: api.ReqLobbyView
(*ResLobbyView)(nil), // 8: api.ResLobbyView
(*LobbyTable)(nil), // 9: api.LobbyTable
(*LobbyPlayer)(nil), // 10: api.LobbyPlayer
(*ReqCreateTable)(nil), // 11: api.ReqCreateTable
(*ResCreateTable)(nil), // 12: api.ResCreateTable
(*ReqJoinTable)(nil), // 13: api.ReqJoinTable
(*ReqLeaveTable)(nil), // 14: api.ReqLeaveTable
(*ReqReadyStart)(nil), // 15: api.ReqReadyStart
(*ReqKickOutTable)(nil), // 16: api.ReqKickOutTable
(*ReqGameAction)(nil), // 17: api.ReqGameAction
(*ResGameAction)(nil), // 18: api.ResGameAction
(*ReqGameStatus)(nil), // 19: api.ReqGameStatus
(*ResGameStatus)(nil), // 20: api.ResGameStatus
(*TablePlayer)(nil), // 21: api.TablePlayer
(*Card)(nil), // 22: api.Card
}
var file_poker_proto_depIdxs = []int32{
9, // 0: api.ResLobbyView.tables:type_name -> api.LobbyTable
10, // 1: api.LobbyTable.players:type_name -> api.LobbyPlayer
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
21, // 2: api.ResGameStatus.players:type_name -> api.TablePlayer
22, // 3: api.TablePlayer.handCard:type_name -> api.Card
22, // 4: api.TablePlayer.publicCard:type_name -> api.Card
5, // [5:5] is the sub-list for method output_type
5, // [5:5] is the sub-list for method input_type
5, // [5:5] is the sub-list for extension type_name
5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
}
func init() { file_poker_proto_init() }
@ -1063,7 +1580,103 @@ func file_poker_proto_init() {
}
}
file_poker_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ResJoinTable); i {
switch v := v.(*ReqLeaveTable); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_poker_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ReqReadyStart); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_poker_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ReqKickOutTable); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_poker_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ReqGameAction); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_poker_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ResGameAction); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_poker_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ReqGameStatus); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_poker_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ResGameStatus); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_poker_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*TablePlayer); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_poker_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Card); i {
case 0:
return &v.state
case 1:
@ -1081,7 +1694,7 @@ func file_poker_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_poker_proto_rawDesc,
NumEnums: 0,
NumMessages: 15,
NumMessages: 23,
NumExtensions: 0,
NumServices: 0,
},

11
api/poker.proto

@ -85,6 +85,11 @@ message ReqJoinTable {
int32 tableNo = 1;
}
//
message ReqLeaveTable {
}
//
message ReqReadyStart {
}
@ -94,12 +99,12 @@ message ReqKickOutTable {
int32 playerId = 1;
}
message ReqAction {
message ReqGameAction {
int32 action = 1; // 4,5,6,7
int32 chip = 2; //
}
message ResAction {
message ResGameAction {
}
@ -121,7 +126,7 @@ message TablePlayer {
string avatar = 4;
int32 chip = 5; //
int32 status = 6; // : 1,2,(3,4,5,6,7)
bool master = 7; //
bool master = 7; // `
repeated Card handCard = 8; //
repeated Card publicCard = 9; //
}

2061
api/proto.js

File diff suppressed because it is too large Load Diff

5
etc/config.toml

@ -15,5 +15,10 @@ ignoreUrl = [
captchaUrl = [
"/auth/authorize"
]
[sqlite]
dbPath = "etc/texas-poker.db"
[game]
# 新用户赠送筹码
GiftChip = 10000

5
internal/conf/conf.go

@ -34,6 +34,7 @@ type Config struct {
Auth *Auth
Http *Http
Sqlite *Sqlite
Game *Game
}
type Auth struct {
@ -48,3 +49,7 @@ type Http struct {
type Sqlite struct {
DbPath string
}
type Game struct {
GiftChip int32
}

2
internal/dao/dao.go

@ -16,6 +16,8 @@ func init() {
Dao = &Persistent{
Sqlite: newSqlite(),
}
initUserDao()
}
func newSqlite() (db *gorm.DB) {

16
internal/service/user.go → internal/dao/user_dao.go

@ -1,30 +1,30 @@
package service
package dao
import (
"fmt"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
"net/http"
"texas-poker-bk/internal/dao"
"texas-poker-bk/internal/model/entity"
)
var userDao *User = &User{dao: dao.Dao.Sqlite}
var UserDao *User
func init() {
err := dao.Dao.Sqlite.AutoMigrate(&entity.User{})
func initUserDao() {
UserDao = &User{DB: Dao.Sqlite}
err := Dao.Sqlite.AutoMigrate(&entity.User{})
if err != nil {
fmt.Println("user table", err)
}
}
type User struct {
dao *gorm.DB
DB *gorm.DB
}
func FindUserByName(ctx *gin.Context) {
username := ctx.Param("username")
user := userDao.FindUserByName(username)
user := UserDao.FindUserByName(username)
if user == nil {
ctx.JSON(http.StatusOK, gin.H{
"msg": "not found",
@ -39,7 +39,7 @@ func FindUserByName(ctx *gin.Context) {
func (u *User) FindUserByName(username string) *entity.User {
user := &entity.User{}
tx := u.dao.Model(user).Where("username=?", username).Limit(1).Scan(user)
tx := u.DB.Model(user).Where("username=?", username).Limit(1).Scan(user)
// 查询出结果时 tx.RowsAffected 固定=1
if tx.RowsAffected == 0 {
return nil

9
internal/game/player.go

@ -1,13 +1,20 @@
package game
import (
"texas-poker-bk/internal/letter"
)
// Player 游戏玩家
type Player struct {
Id int64
Username string
Avatar string
Cards [2]*Card // 手牌
Chip int // 玩家筹码
Chip int32 // 玩家筹码
Status int32 // 状态: 1待准备开始,2已准备开始,3等待其他玩家动作,4待大盲注,5待小盲注,6待跟注,7已弃
GameTable *Table // 当前牌桌
ProtoWriter *letter.ProtoWriter
}
func NewPlayer() *Player {

37
internal/game/table.go

@ -1,12 +1,18 @@
package game
import (
"errors"
"sync"
"texas-poker-bk/api"
)
type Table struct {
TableNo int32 // 牌桌编号
roundTimes int // 回合次数
stage Stage // 游戏阶段
RoundTimes int32 // 回合次数
Stage int32 // 游戏阶段: 1等待玩家准备;2下大盲注;3下小盲注;4发公共牌;5发第四张公共牌,轮流下注;6发第五张公共牌,轮流下注
chip int // 牌桌当前筹码
robotChip int // 牌桌当前机器人下注筹码
chip int32 // 牌桌当前筹码
robotChip int32 // 牌桌当前机器人下注筹码
dealer *Dealer // 发牌员
publicCards [5]*Dealer // 公共牌
@ -14,11 +20,32 @@ type Table struct {
RobotNum int32 // 机器人数
Players []*Player // 玩家
Robots []*Robot
bigBlindsPos int // 大盲注位
BigBlindsPos int32 // 大盲注位
PlayerJoinLock *sync.Mutex
ChipLock *sync.Mutex // 桌面筹码更新锁
// TODO game logs7
}
func (t *Table) JoinPlayer(player *Player) error {
t.PlayerJoinLock.Lock()
defer t.PlayerJoinLock.Unlock()
for i := range t.Players {
// 找个空位坐下
if t.Players[i] == nil {
t.Players[i] = player
return nil
}
}
return errors.New("牌桌玩家已满")
}
func (t *Table) NoticeGameStatus() {
gameStatus := &api.ResGameStatus{}
gameStatus.TableNo = t.TableNo
}
type Stage int
func (s *Stage) String() string {

7
internal/letter/proto_writer.go

@ -0,0 +1,7 @@
package letter
import "github.com/golang/protobuf/proto"
type ProtoWriter interface {
Write(message proto.Message)
}

1
internal/model/entity/user.go

@ -6,6 +6,7 @@ type User struct {
Username string `gorm:"column:username" json:"username"` // comment:用户名
Password string `gorm:"column:password" json:"password"` // comment:密码
Nickname string `gorm:"column:nickname" json:"nickname"` // comment:昵称
Balance int32 `gorm:"column:balance" json:"balance"` // comment:余额
Version int64 `gorm:"column:version" json:"version"` // comment:更新版本锁
}

6
internal/server/route.go

@ -4,6 +4,7 @@ import (
"github.com/gin-gonic/gin"
"net/http"
"texas-poker-bk/api"
"texas-poker-bk/internal/dao"
"texas-poker-bk/internal/service"
)
@ -29,10 +30,9 @@ func NewServer() *gin.Engine {
auth.POST("/authorize", service.Authorize) // 登录或注册认证
user := base.Group("/user")
user.GET("/findByName", service.FindUserByName)
user.GET("/findByName", dao.FindUserByName)
game := base.Group("/game")
game.GET("/lobby", service.GetLobbyView) // 游戏大厅
_ = base.Group("/game")
return server
}

30
internal/server/wsroute.go

@ -4,33 +4,25 @@ import (
"github.com/golang/protobuf/proto"
"reflect"
"texas-poker-bk/api"
"texas-poker-bk/internal/game"
"texas-poker-bk/internal/service"
"texas-poker-bk/internal/session"
)
var NetClientHandlers = make(map[int32]func(*session.NetClient, proto.Message) (proto.Message, error))
var NetAccountHandlers = make(map[int32]func(session.NetAccount, proto.Message) (proto.Message, error))
var PlayerHandlers = make(map[int32]func(*session.Player, proto.Message) (proto.Message, error))
var PlayerHandlers = make(map[int32]func(*game.Player, proto.Message) (proto.Message, error))
func init() {
// 连接token认证
HandleNetClientMsg(&api.ReqIdentity{}, func(client *session.NetClient, msg *api.ReqIdentity) (proto.Message, error) {
subject, err := service.DecodeSubject(msg.Token)
if err != nil {
// client.Close("authorize failed!")
return nil, err
}
account := &session.NetAccount{Id: subject.Id, UserName: subject.Name, Avatar: subject.Avatar, Client: client}
client.Account = account
HandleNetClientMsg(&api.ReqIdentity{}, service.HandleReqIdentity)
// 创建桌面
HandleNetAccountMsg(&api.ReqCreateTable{}, service.HandleReqCreateTable)
// 查询所有游戏桌面
HandleNetAccountMsg(&api.ReqLobbyView{}, service.HandleReqLobbyView)
// 加入桌面
HandleNetAccountMsg(&api.ReqJoinTable{}, service.HandleJoinTable)
// response
res := &api.ResIdentity{Status: 200, Msg: "ok"}
// client.Write(res)
return res, nil
})
HandleNetAccountMsg(&api.ReqCreateTable{}, service.CreateNewTable) // 创建桌面
HandleNetAccountMsg(&api.ReqLobbyView{}, service.GetLobbyView2) // 查询所有游戏桌面
}
func checkExistsTypeHandler(op int32, err error) {
@ -59,10 +51,10 @@ func HandleNetAccountMsg[T proto.Message](msg T, f func(session.NetAccount, T) (
}
}
func HandleNetPlayerMsg[T proto.Message](msg T, f func(*session.Player, T) (proto.Message, error)) {
func HandleNetPlayerMsg[T proto.Message](msg T, f func(*game.Player, T) (proto.Message, error)) {
op, err := api.GetProtoOp(msg)
checkExistsTypeHandler(op, err)
PlayerHandlers[op] = func(player *session.Player, msg proto.Message) (proto.Message, error) {
PlayerHandlers[op] = func(player *game.Player, msg proto.Message) (proto.Message, error) {
return f(player, msg.(T))
}
}

30
internal/service/auth.go

@ -5,8 +5,11 @@ import (
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"github.com/golang/protobuf/proto"
"net/http"
"texas-poker-bk/api"
"texas-poker-bk/internal/conf"
"texas-poker-bk/internal/dao"
"texas-poker-bk/internal/model/entity"
"texas-poker-bk/internal/session"
"texas-poker-bk/tool/collect"
@ -41,7 +44,7 @@ func Authorize(ctx *gin.Context) {
ctx.JSON(http.StatusBadRequest, gin.H{"msg": "用户名或密码不能为空"})
return
}
user := userDao.FindUserByName(username)
user := dao.UserDao.FindUserByName(username)
if user == nil {
// 注册
user = registerUser(username, password)
@ -68,9 +71,10 @@ func registerUser(username string, password string) *entity.User {
Username: username,
Password: password,
Nickname: username,
Balance: conf.Conf.Game.GiftChip,
}
// TODO error
userDao.dao.Save(user)
dao.UserDao.DB.Save(user)
return user
}
@ -152,3 +156,25 @@ func GetSubject(ctx *gin.Context) *session.Subject {
}
return subject.(*session.Subject)
}
func HandleReqIdentity(client *session.NetClient, msg *api.ReqIdentity) (proto.Message, error) {
subject, err := DecodeSubject(msg.Token)
if err != nil {
// client.Close("authorize failed!")
return nil, err
}
account := &session.NetAccount{
Id: subject.Id,
UserName: subject.Name,
Avatar: subject.Avatar,
Client: client,
Balance: 0,
}
client.Account = account
// response
res := &api.ResIdentity{Status: 200, Msg: "ok"}
// client.Write(res)
return res, nil
}

40
internal/service/store/store.go

@ -3,12 +3,9 @@ package store
import (
"errors"
"fmt"
"sort"
"sync"
"sync/atomic"
"texas-poker-bk/internal/game"
"texas-poker-bk/internal/model/vo"
"texas-poker-bk/tool/collect"
)
var (
@ -32,40 +29,3 @@ func SaveNewTable(table *game.Table) error {
LobbyTables[table.TableNo] = table
return nil
}
func GetLobbyTablesView() []*vo.TableVO {
if LobbyTables == nil || len(LobbyTables) == 0 {
return make([]*vo.TableVO, 0)
}
tables := make([]*vo.TableVO, len(LobbyTables))
idx := 0
for _, t := range LobbyTables {
tVO := &vo.TableVO{}
tVO.TableNo = t.TableNo
if collect.IsNotEmptySlice(t.Players) {
tVO.Players = make([]*vo.PlayerVO, len(t.Players))
for i, player := range t.Players {
if player == nil {
continue
}
pVO := &vo.PlayerVO{Id: player.Id, Username: player.Username, Avatar: player.Avatar}
tVO.Players[i] = pVO
}
}
if collect.IsNotEmptySlice(t.Robots) {
tVO.Robots = make([]*vo.RobotVO, len(t.Robots))
for i, _ := range t.Robots {
rVO := &vo.RobotVO{}
tVO.Robots[i] = rVO
}
}
tables[idx] = tVO
idx++
}
// 牌桌号降序
sort.Slice(tables, func(i, j int) bool {
return tables[i].TableNo > tables[j].TableNo
})
return tables
}

92
internal/service/table.go

@ -1,9 +1,9 @@
package service
import (
"github.com/gin-gonic/gin"
"fmt"
"github.com/golang/protobuf/proto"
"net/http"
"sort"
"texas-poker-bk/api"
"texas-poker-bk/internal/game"
"texas-poker-bk/internal/service/store"
@ -11,8 +11,8 @@ import (
"texas-poker-bk/tool/collect"
)
// CreateNewTable 创建桌面 TODO 当前在房间则不可创建房间了
func CreateNewTable(account session.NetAccount, msg *api.ReqCreateTable) (proto.Message, error) {
// HandleReqCreateTable 创建桌面 TODO 当前在房间则不可创建房间了
func HandleReqCreateTable(account session.NetAccount, msg *api.ReqCreateTable) (proto.Message, error) {
// 人数,机器人数
playerNum := msg.Players
robotNum := msg.Robots
@ -31,7 +31,12 @@ func CreateNewTable(account session.NetAccount, msg *api.ReqCreateTable) (proto.
Id: account.Id,
Username: account.UserName,
Avatar: account.Avatar,
Status: 1,
Chip: 500,
}
// 扣除DB账户余额 TODO 账户金额限制
account.DecrementBalance(500)
table.Players[0] = owner
for i := 0; i < int(robotNum); i++ {
table.Robots[i] = &game.Robot{}
@ -43,13 +48,8 @@ func CreateNewTable(account session.NetAccount, msg *api.ReqCreateTable) (proto.
return &api.ResCreateTable{TableNo: table.TableNo}, nil
}
func GetLobbyView(ctx *gin.Context) {
lobby := store.GetLobbyTablesView()
ctx.JSON(http.StatusOK, gin.H{"data": lobby})
}
// GetLobbyView2 返回当前所有桌面和玩家数量
func GetLobbyView2(account session.NetAccount, msg *api.ReqLobbyView) (proto.Message, error) {
// HandleReqLobbyView 返回当前所有桌面和玩家数量
func HandleReqLobbyView(account session.NetAccount, msg *api.ReqLobbyView) (proto.Message, error) {
res := &api.ResLobbyView{}
if store.LobbyTables == nil || len(store.LobbyTables) == 0 {
return res, nil
@ -85,10 +85,76 @@ func GetLobbyView2(account session.NetAccount, msg *api.ReqLobbyView) (proto.Mes
tables[idx] = table
idx++
}
// 牌桌号降序
sort.Slice(tables, func(i, j int) bool {
return tables[i].TableNo > tables[j].TableNo
})
return res, nil
}
// JoinTable 加入牌桌
func JoinTable(ctx *gin.Context) {
// HandleJoinTable 加入牌桌
func HandleJoinTable(account session.NetAccount, msg *api.ReqJoinTable) (proto.Message, error) {
account.Lock.Lock()
defer account.Lock.Unlock()
if account.Player != nil {
return &api.ResFail{Msg: fmt.Sprintf("用户当前已加入#%d牌桌", account.Player.GameTable.TableNo)}, nil
}
// account -> player
// TODO 账户余额限制
table := store.LobbyTables[msg.TableNo]
if table == nil {
return &api.ResFail{Msg: "牌桌不存在"}, nil
}
player := &game.Player{
Id: account.Id,
Username: account.UserName,
Avatar: account.Avatar,
Status: 1,
Chip: 500,
GameTable: table,
}
err := table.JoinPlayer(player)
if err != nil {
return nil, err
}
// 从账户扣除进入牌桌的金额
account.DecrementBalance(500)
account.Player = player
return &api.ResSuccess{}, nil
}
// HandleLeaveTable 离开牌桌
func HandleLeaveTable(account session.NetAccount, msg *api.ReqCreateTable) (proto.Message, error) {
account.Lock.Lock()
defer account.Lock.Unlock()
// 结算, player -> nil
if account.Player == nil {
return &api.ResFail{Msg: "当前未加入牌桌"}, nil
}
// 根据玩家游戏状态判断可否退出
switch account.Player.Status {
case 1, 2, 7: // 未在游戏中 可退出
// 结算金额
account.IncrementBalance(account.Player.Chip)
gameTable := account.Player.GameTable
// table player remove
for i := range gameTable.Players {
if gameTable.Players[i] == account.Player {
gameTable.Players[i] = nil
}
}
account.Player = nil
// TODO notice 牌桌其他玩家 gameTable.notice(ResGameStatus)
return &api.ResSuccess{}, nil
default:
return &api.ResFail{Msg: "游戏进行中,不能退出"}, nil
}
}
// HandleReqReadyStart 准备开始游戏
func HandleReqReadyStart(player game.Player, msg *api.ReqReadyStart) (proto.Message, error) {
return nil, nil
}

38
internal/session/net_account.go

@ -1,13 +1,43 @@
package session
import (
"sync"
"texas-poker-bk/internal/game"
)
// NetAccount 已认证的长连接用户
type NetAccount struct {
Id int64
UserName string
Avatar string
Client *NetClient
Id int64
UserName string
Avatar string
Client *NetClient
Balance int32 // 余额
Player *game.Player
BalanceLock *sync.RWMutex
Lock *sync.Mutex
}
func NewNetAccount() {
}
func (account *NetAccount) DecrementBalance(amount int32) int32 {
account.BalanceLock.Lock()
defer account.BalanceLock.Unlock()
account.Balance -= amount
// TODO 同步到 DB
return account.Balance
}
func (account *NetAccount) IncrementBalance(amount int32) int32 {
account.BalanceLock.Lock()
defer account.BalanceLock.Unlock()
account.Balance += amount
return account.Balance
}
func (account *NetAccount) GetBalance() int32 {
account.BalanceLock.RLock()
defer account.BalanceLock.RUnlock()
return account.Balance
}

13
internal/session/player.go

@ -1,6 +1,19 @@
package session
import (
"sync"
"texas-poker-bk/internal/game"
)
// Player 玩家: table,balance,(hand card)
type Player struct {
Account *NetAccount
Id int64
Username string
Avatar string
Cards [2]*game.Card // 手牌
Chip int // 玩家筹码
Status int32 // 状态: 1待准备开始,2已准备开始,3等待其他玩家动作,4待大盲注,5待小盲注,6待跟注,7已弃
StatusLock *sync.Mutex
}

Loading…
Cancel
Save