diff --git a/answer/commander_collection.go b/answer/commander_collection.go new file mode 100644 index 0000000..d585f6d --- /dev/null +++ b/answer/commander_collection.go @@ -0,0 +1,43 @@ +package answer + +import ( + "github.com/ggmolly/belfast/connection" + "github.com/ggmolly/belfast/orm" + + "github.com/ggmolly/belfast/protobuf" + "google.golang.org/protobuf/proto" +) + +type MaxShipStat struct { + GroupID uint32 `gorm:"column:group_id"` + MaxStar uint32 `gorm:"column:max_star"` + MaxIntimacy uint32 `gorm:"column:max_intimacy"` + MaxLevel uint32 `gorm:"column:max_level"` +} + +func CommanderCollection(buffer *[]byte, client *connection.Client) (int, int, error) { + // Out of all commander's OwnedShips, return the max star, max intimacy, and max level + // of each ship group (= TemplateID divided by 10) + + stats := []*protobuf.SHIP_STATISTICS_INFO{} + orm.GormDB.Raw(` + SELECT + ship_id / 10 AS group_id, + MAX(ships.star) AS max_star, + MAX(intimacy) AS max_intimacy, + MAX(level) AS max_level, + MAX(propose::int) AS marry_flag, + (SELECT COUNT(*) FROM likes WHERE group_id = owned_ships.ship_id / 10 AND liker_id = ?) AS heart_flag, + (SELECT COUNT(*) FROM likes WHERE group_id = owned_ships.ship_id / 10) AS heart_count + FROM owned_ships + INNER JOIN ships ON owned_ships.ship_id = ships.template_id + WHERE owner_id = ? + GROUP BY group_id, owned_ships.ship_id + `, client.Commander.CommanderID, client.Commander.CommanderID).Scan(&stats) + + response := protobuf.SC_17001{ + DailyDiscuss: proto.Uint32(0), + ShipInfoList: stats, + } + return client.SendMessage(17001, &response) +} diff --git a/answer/commander_fleet_a.go b/answer/commander_fleet_a.go index 0f3daaf..74e4620 100644 --- a/answer/commander_fleet_a.go +++ b/answer/commander_fleet_a.go @@ -7,7 +7,7 @@ import ( ) func CommanderFleetA(buffer *[]byte, client *connection.Client) (int, int, error) { - response := &protobuf.SC_12010{} + response := protobuf.SC_12010{} // Send ships 100: var shipList []*protobuf.SHIPINFO if len(client.Commander.Ships) > 100 { diff --git a/answer/get_ship_discuss.go b/answer/get_ship_discuss.go new file mode 100644 index 0000000..3f22a15 --- /dev/null +++ b/answer/get_ship_discuss.go @@ -0,0 +1,24 @@ +package answer + +import ( + "github.com/ggmolly/belfast/connection" + "github.com/ggmolly/belfast/protobuf" + "google.golang.org/protobuf/proto" +) + +func GetShipDiscuss(buffer *[]byte, client *connection.Client) (int, int, error) { + var payload protobuf.CS_17101 + if err := proto.Unmarshal(*buffer, &payload); err != nil { + return 0, 17102, err + } + var response protobuf.SC_17102 + + response.ShipDiscuss = &protobuf.SHIP_DISCUSS_INFO{ + ShipGroupId: payload.ShipGroupId, + DiscussCount: proto.Uint32(0), + HeartCount: proto.Uint32(0), + DailyDiscussCount: proto.Uint32(0), + } + + return client.SendMessage(17102, &response) +} diff --git a/answer/unk_17001.go b/answer/unk_17001.go deleted file mode 100644 index 014121c..0000000 --- a/answer/unk_17001.go +++ /dev/null @@ -1,15 +0,0 @@ -package answer - -import ( - "github.com/ggmolly/belfast/connection" - - "github.com/ggmolly/belfast/protobuf" - "google.golang.org/protobuf/proto" -) - -func UNK_17001(buffer *[]byte, client *connection.Client) (int, int, error) { - response := protobuf.SC_17001{ - DailyDiscuss: proto.Uint32(0), - } - return client.SendMessage(17001, &response) -} diff --git a/answer/update_ship_like.go b/answer/update_ship_like.go new file mode 100644 index 0000000..88f2dc2 --- /dev/null +++ b/answer/update_ship_like.go @@ -0,0 +1,18 @@ +package answer + +import ( + "github.com/ggmolly/belfast/connection" + "github.com/ggmolly/belfast/protobuf" + "google.golang.org/protobuf/proto" +) + +func UpdateShipLike(buffer *[]byte, client *connection.Client) (int, int, error) { + var payload protobuf.CS_17107 + if err := proto.Unmarshal(*buffer, &payload); err != nil { + return 0, 17108, err + } + response := protobuf.SC_17108{ + Result: proto.Uint32(boolToUint32(client.Commander.Like(*payload.ShipGroupId) != nil)), + } + return client.SendMessage(17108, &response) +} diff --git a/main.go b/main.go index a468560..cbb5701 100644 --- a/main.go +++ b/main.go @@ -82,19 +82,19 @@ func init() { }) packets.RegisterPacketHandler(10022, []packets.PacketHandler{answer.JoinServer}) packets.RegisterPacketHandler(11001, []packets.PacketHandler{ - answer.LastLogin, // SC_11000 - answer.PlayerInfo, // SC_11003 - answer.PlayerBuffs, // SC_11015 - answer.GetMetaProgress, // SC_63315 - answer.LastOnlineInfo, // SC_11752 - answer.ResourcesInfo, // SC_22001 - answer.EventData, // SC_26120 - answer.Meowfficers, // SC_25001 - answer.UNK_17001, // SC_17001 - answer.OngoingBuilds, // SC_12024 - answer.PlayerDock, // SC_12001 - answer.CommanderFleetA, // SC_12010 - answer.UNK_12101, // SC_12101 + answer.LastLogin, // SC_11000 + answer.PlayerInfo, // SC_11003 + answer.PlayerBuffs, // SC_11015 + answer.GetMetaProgress, // SC_63315 + answer.LastOnlineInfo, // SC_11752 + answer.ResourcesInfo, // SC_22001 + answer.EventData, // SC_26120 + answer.Meowfficers, // SC_25001 + answer.CommanderCollection, // SC_17001 + answer.OngoingBuilds, // SC_12024 + answer.PlayerDock, // SC_12001 + answer.CommanderFleetA, // SC_12010 + // answer.UNK_12101, // SC_12101 answer.CommanderOwnedSkins, // SC_12201 answer.UNK_63000, // SC_63000 answer.ShipyardData, // SC_63100 @@ -221,4 +221,8 @@ func init() { // UpdateCommonFlagCommand, unknown what it does packets.RegisterPacketHandler(11019, []packets.PacketHandler{answer.UpdateCommonFlagCommand}) + + // Ship comments tab + packets.RegisterPacketHandler(17101, []packets.PacketHandler{answer.GetShipDiscuss}) // Ship discussion (placeholder) + packets.RegisterPacketHandler(17107, []packets.PacketHandler{answer.UpdateShipLike}) } diff --git a/orm/commander.go b/orm/commander.go index d13bae0..3a9b479 100644 --- a/orm/commander.go +++ b/orm/commander.go @@ -572,3 +572,12 @@ func (c *Commander) IncrementExchangeCount(n uint32) error { } return GormDB.Save(c).Error } + +// Likes a ship, inserts a row into the likes table with the ship's group_id +func (c *Commander) Like(groupId uint32) error { + like := Like{ + GroupID: groupId, + LikerID: c.CommanderID, + } + return GormDB.Create(&like).Error +} diff --git a/orm/database.go b/orm/database.go index cc2f0d0..dbf16f6 100644 --- a/orm/database.go +++ b/orm/database.go @@ -78,6 +78,7 @@ func InitDatabase() bool { // &CommanderLimitItem{}, &CommanderMiscItem{}, &OwnedResource{}, + &Like{}, ) if err != nil { panic("failed to migrate database " + err.Error()) diff --git a/orm/likes.go b/orm/likes.go new file mode 100644 index 0000000..90d660c --- /dev/null +++ b/orm/likes.go @@ -0,0 +1,11 @@ +package orm + +import "time" + +type Like struct { + GroupID uint32 `gorm:"primary_key;index:idx_likes_group_id_liker_id"` + LikerID uint32 `gorm:"not_null;primary_key;index:idx_likes_group_id_liker_id"` + CreatedAt time.Time + + Liker Commander `gorm:"foreignkey:LikerID;references:CommanderID"` +} diff --git a/orm/owned_ship.go b/orm/owned_ship.go index ecf2519..6a94dab 100644 --- a/orm/owned_ship.go +++ b/orm/owned_ship.go @@ -3,28 +3,31 @@ package orm import ( "errors" "time" + + "gorm.io/gorm" ) type OwnedShip struct { - OwnerID uint32 `gorm:"type:int;not_null"` - ShipID uint32 `gorm:"not_null"` - ID uint32 `gorm:"primary_key"` - Level uint32 `gorm:"default:1;not_null"` - MaxLevel uint32 `gorm:"default:50;not_null"` - Intimacy uint32 `gorm:"default:5000;not_null"` - IsLocked bool `gorm:"default:false;not_null"` - Propose bool `gorm:"default:false;not_null"` - CommonFlag bool `gorm:"default:false;not_null"` - BlueprintFlag bool `gorm:"default:false;not_null"` - Proficiency bool `gorm:"default:false;not_null"` - ActivityNPC uint32 `gorm:"default:0;not_null"` - CustomName string `gorm:"size:30;default:'';not_null"` - ChangeNameTimestamp time.Time `gorm:"type:timestamp;default:'1970-01-01 01:00:00';not_null"` - CreateTime time.Time `gorm:"type:timestamp;default:CURRENT_TIMESTAMP;not_null"` - Energy uint32 `gorm:"default:150;not_null"` - SkinID uint32 `gorm:"default:0;not_null"` - IsSecretary bool `gorm:"default:false;not_null"` - SecretaryPosition *uint32 `gorm:"default:999;not_null"` + OwnerID uint32 `gorm:"type:int;not_null"` + ShipID uint32 `gorm:"not_null"` + ID uint32 `gorm:"primary_key"` + Level uint32 `gorm:"default:1;not_null"` + MaxLevel uint32 `gorm:"default:50;not_null"` + Intimacy uint32 `gorm:"default:5000;not_null"` + IsLocked bool `gorm:"default:false;not_null"` + Propose bool `gorm:"default:false;not_null"` + CommonFlag bool `gorm:"default:false;not_null"` + BlueprintFlag bool `gorm:"default:false;not_null"` + Proficiency bool `gorm:"default:false;not_null"` + ActivityNPC uint32 `gorm:"default:0;not_null"` + CustomName string `gorm:"size:30;default:'';not_null"` + ChangeNameTimestamp time.Time `gorm:"type:timestamp;default:'1970-01-01 01:00:00';not_null"` + CreateTime time.Time `gorm:"type:timestamp;default:CURRENT_TIMESTAMP;not_null"` + Energy uint32 `gorm:"default:150;not_null"` + SkinID uint32 `gorm:"default:0;not_null"` + IsSecretary bool `gorm:"default:false;not_null"` + SecretaryPosition *uint32 `gorm:"default:999;not_null"` + DeletedAt gorm.DeletedAt `gorm:"index"` // Soft delete Ship Ship `gorm:"foreignKey:ShipID;references:TemplateID;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"` Commander Commander `gorm:"foreignKey:OwnerID;references:CommanderID;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"` diff --git a/protobuf/SHIP_STATISTICS_INFO.pb.go b/protobuf/SHIP_STATISTICS_INFO.pb.go index 0a2542a..98b5dbb 100644 --- a/protobuf/SHIP_STATISTICS_INFO.pb.go +++ b/protobuf/SHIP_STATISTICS_INFO.pb.go @@ -25,13 +25,13 @@ type SHIP_STATISTICS_INFO struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id *uint32 `protobuf:"varint,1,req,name=id" json:"id,omitempty"` - Star *uint32 `protobuf:"varint,2,req,name=star" json:"star,omitempty"` - HeartFlag *uint32 `protobuf:"varint,3,req,name=heart_flag,json=heartFlag" json:"heart_flag,omitempty"` - HeartCount *uint32 `protobuf:"varint,4,req,name=heart_count,json=heartCount" json:"heart_count,omitempty"` - MarryFlag *uint32 `protobuf:"varint,5,req,name=marry_flag,json=marryFlag" json:"marry_flag,omitempty"` - IntimacyMax *uint32 `protobuf:"varint,6,req,name=intimacy_max,json=intimacyMax" json:"intimacy_max,omitempty"` - LvMax *uint32 `protobuf:"varint,7,req,name=lv_max,json=lvMax" json:"lv_max,omitempty"` + Id *uint32 `protobuf:"varint,1,req,name=id" json:"id,omitempty" gorm:"column:group_id"` + Star *uint32 `protobuf:"varint,2,req,name=star" json:"star,omitempty" gorm:"column:max_star"` + HeartFlag *uint32 `protobuf:"varint,3,req,name=heart_flag,json=heartFlag" json:"heart_flag,omitempty" gorm:"column:heart_flag"` + HeartCount *uint32 `protobuf:"varint,4,req,name=heart_count,json=heartCount" json:"heart_count,omitempty" gorm:"column:heart_count"` + MarryFlag *uint32 `protobuf:"varint,5,req,name=marry_flag,json=marryFlag" json:"marry_flag,omitempty" gorm:"column:marry_flag"` + IntimacyMax *uint32 `protobuf:"varint,6,req,name=intimacy_max,json=intimacyMax" json:"intimacy_max,omitempty" gorm:"column:max_intimacy"` + LvMax *uint32 `protobuf:"varint,7,req,name=lv_max,json=lvMax" json:"lv_max,omitempty" gorm:"column:max_level"` } func (x *SHIP_STATISTICS_INFO) Reset() {