Skip to content
This repository has been archived by the owner on Jan 29, 2023. It is now read-only.

Feature: Cafepoints #69

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
4 changes: 3 additions & 1 deletion migrations/000002_alter_characters.up.sql
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ BEGIN;
ALTER TABLE characters
ADD COLUMN exp uint16,
ADD COLUMN weapon uint16,
ADD COLUMN last_login integer;
ADD COLUMN last_login integer,
ADD COLUMN favoritequests bytea,
ADD COLUMN cafepoints integer default 0 not null;

END;
18 changes: 9 additions & 9 deletions network/mhfpacket/msg_mhf_acquire_cafe_item.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ type MsgMhfAcquireCafeItem struct {
AckHandle uint32

// Valid sizes, not sure if [un]signed.
Unk0 uint16
Unk1 uint16
Unk2 uint16
Unk3 uint32
Unk4 uint16
Unk0 uint16
Unk1 uint16
Quantity uint16
NPointCost uint32
Unk4 uint16
}

// Opcode returns the ID associated with this packet type.
Expand All @@ -28,8 +28,8 @@ func (m *MsgMhfAcquireCafeItem) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Cl
m.AckHandle = bf.ReadUint32()
m.Unk0 = bf.ReadUint16()
m.Unk1 = bf.ReadUint16()
m.Unk2 = bf.ReadUint16()
m.Unk3 = bf.ReadUint32()
m.Quantity = bf.ReadUint16()
m.NPointCost = bf.ReadUint32()
m.Unk4 = bf.ReadUint16()
return nil
}
Expand All @@ -39,8 +39,8 @@ func (m *MsgMhfAcquireCafeItem) Build(bf *byteframe.ByteFrame, ctx *clientctx.Cl
bf.WriteUint32(m.AckHandle)
bf.WriteUint16(m.Unk0)
bf.WriteUint16(m.Unk1)
bf.WriteUint16(m.Unk2)
bf.WriteUint32(m.Unk3)
bf.WriteUint16(m.Quantity)
bf.WriteUint32(m.NPointCost)
bf.WriteUint16(m.Unk4)
return nil
}
29 changes: 29 additions & 0 deletions network/mhfpacket/msg_unknown.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package mhfpacket

import (
"errors"

"github.com/Andoryuuta/Erupe/network"
"github.com/Andoryuuta/Erupe/network/clientctx"
"github.com/Andoryuuta/byteframe"
)

// MsgSysPing represents the MSG_SYS_PING
type MsgUnknown struct {
AckHandle uint32
}

// Opcode returns the ID associated with this packet type.
func (m *MsgUnknown) Opcode() network.PacketID {
return network.MSG_UNKNOWN
}

// Parse parses the packet from binary
func (m *MsgUnknown) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("Not implemented")
}

// Build builds a binary packet from the current data.
func (m *MsgUnknown) Build(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("Not implemented")
}
1 change: 1 addition & 0 deletions network/packetid.go
Original file line number Diff line number Diff line change
Expand Up @@ -438,5 +438,6 @@ const (
MSG_SYS_reserve20D
MSG_SYS_reserve20E
MSG_SYS_reserve20F
MSG_UNKNOWN = 12651
//revive:enable
)
16 changes: 16 additions & 0 deletions server/channelserver/channel_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ func (s *Server) Start() error {
}
s.listener = l

remote, _ := net.Listen("tcp", fmt.Sprintf(":%d", s.erupeConfig.Channel.Port+1))

go s.rpcAccept(remote)
go s.acceptClients()
go s.manageSessions()

Expand Down Expand Up @@ -128,6 +131,19 @@ func (s *Server) Shutdown() {
}
}

func (s *Server) rpcAccept(rpc net.Listener) {
for {
s.logger.Info("Listening on RPC")
conn, _ := rpc.Accept()

bf := byteframe.NewByteFrame()
bf.WriteInt8(int8(len(s.sessions)))

conn.Write(bf.Data())
conn.Close()
}
}

func (s *Server) acceptClients() {
for {
conn, err := s.listener.Accept()
Expand Down
1 change: 1 addition & 0 deletions server/channelserver/handler_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -443,4 +443,5 @@ func init() {
handlerTable[network.MSG_SYS_reserve20D] = handleMsgSysReserve20D
handlerTable[network.MSG_SYS_reserve20E] = handleMsgSysReserve20E
handlerTable[network.MSG_SYS_reserve20F] = handleMsgSysReserve20F
handlerTable[network.MSG_UNKNOWN] = handleMsgUnknown
}
150 changes: 119 additions & 31 deletions server/channelserver/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -1229,15 +1229,28 @@ func handleMsgMhfOprtMail(s *Session, p mhfpacket.MHFPacket) {}

func handleMsgMhfLoadFavoriteQuest(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfLoadFavoriteQuest)
// TODO(Andoryuuta): Save data from MsgMhfSaveFavoriteQuest and resend it here.
// Fist: Using a no favourites placeholder to avoid an in game error message
// being sent every time you use a counter when it fails to load
doAckBufSucceed(s, pkt.AckHandle, []byte{0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
// Get character from database, increment (necessary for scan)
rows, _ := s.server.db.Query("SELECT favoritequests FROM characters WHERE id=$1", s.charID)
rows.Next()

// Create buffer and scan into buffer
var favoriteQuests *[]byte
rows.Scan(&favoriteQuests)

// Handle nil instance
if favoriteQuests == nil {
favoriteQuests = &[]byte{0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
return
}

// Return buffer
doAckBufSucceed(s, pkt.AckHandle, *favoriteQuests)
}

func handleMsgMhfSaveFavoriteQuest(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfSaveFavoriteQuest)

s.server.db.Exec("UPDATE characters SET favoritequests=$1 WHERE id=$2", pkt.Data, s.charID)
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
}

Expand Down Expand Up @@ -1521,12 +1534,47 @@ func handleMsgMhfEnumerateFestaMember(s *Session, p mhfpacket.MHFPacket) {}

func handleMsgMhfVoteFesta(s *Session, p mhfpacket.MHFPacket) {}

func handleMsgMhfAcquireCafeItem(s *Session, p mhfpacket.MHFPacket) {}
// This is fired when a player buys something
// Not the prettiest solution but can fixed up
// Matthe815(TODO)
func handleMsgMhfAcquireCafeItem(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfAcquireCafeItem)

// Acquire packet example: 00 c0 01 fd 00 16 00 07 0d ec 00 02 00 00 00 08
// 02 represents quantity
// 08 represents cost
rows := s.server.db.QueryRow("SELECT cafepoints FROM characters WHERE id=$1", s.charID)

// take cafe points from database
var cafePoints *uint32
rows.Scan(&cafePoints)

var after = *cafePoints - pkt.NPointCost

// Create a new byte array for databasing
bf := byteframe.NewByteFrame()
bf.WriteUint32(after)

// Return a basic sucgcess to prevent softlock. The value here will set the player's current value on client.
s.server.db.Exec("UPDATE characters SET cafepoints=$1 WHERE id=$2", after, s.charID)
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
}

// This updates the value of N-points within the player client.
func handleMsgMhfUpdateCafepoint(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUpdateCafepoint)
// not sized
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x04, 0x8b})
row := s.server.db.QueryRow("SELECT cafepoints FROM characters WHERE id=$1", s.charID)

// take cafe points from database into a byte array
var cafePoints *uint32
row.Scan(&cafePoints)

// Create a new byte array for databasing
bf := byteframe.NewByteFrame()
bf.WriteUint32(*cafePoints)

// This is the current amount of 'cafe points' the player holds, send it to the player
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
}

func handleMsgMhfCheckDailyCafepoint(s *Session, p mhfpacket.MHFPacket) {
Expand Down Expand Up @@ -1771,37 +1819,68 @@ func handleMsgMhfUpdateMyhouseInfo(s *Session, p mhfpacket.MHFPacket) {
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
}

func handleMsgMhfGetWeeklySchedule(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetWeeklySchedule)
// Determined which weapons are featured
func determineFeatured() uint32 {
return makeFeatureSet()
}

type EventSchedule struct {
StartTime time.Time
ActiveFeatures uint32
Unk1 uint16
}

// The list of features
var features []EventSchedule

func makeFeatured() []EventSchedule {
//japanese timestamps as client needs to be in japanese locale
var t = time.Now().In(time.FixedZone("UTC+9", 9*60*60))
year, month, day := t.Date()
midnight := time.Date(year, month, day, 0, 0, 0, 0, t.Location()).Add(time.Hour)
// ActiveFeatures is a bit field, 0x3FFF is all 14 active features.
// Long term it should probably be made persistent and simply cycle a couple daily
// Times seem to need to be midnight which is likely why matching timezone was required originally
eventSchedules := []struct {
StartTime time.Time
ActiveFeatures uint32
Unk1 uint16
}{
{
StartTime: midnight.Add(-24 * time.Hour), // midnight of previous day.
ActiveFeatures: 0x3FFF,
Unk1: 0,
},
{

// Make initial list if not exists
if len(features) == 0 {
// ActiveFeatures is a bit field, 0x3FFF is all 14 active features.
// Long term it should probably be made persistent and simply cycle a couple daily
// Times seem to need to be midnight which is likely why matching timezone was required originally
features = []EventSchedule{
{
StartTime: midnight.Add(-24 * time.Hour), // midnight of previous day.
ActiveFeatures: determineFeatured(),
Unk1: 0,
},
{
StartTime: midnight, // midnight of this day.
ActiveFeatures: determineFeatured(),
Unk1: 0,
},
{
StartTime: midnight.Add(24 * time.Hour), // midnight of following day.
ActiveFeatures: determineFeatured(),
Unk1: 0,
},
}
}

// If it's time for the next to start, start it and append a new one.
if time.Now().After(features[1].StartTime) {
_, features = features[0], features[1:]
features = append(features, EventSchedule{
StartTime: midnight, // midnight of this day.
ActiveFeatures: 0x3FFF,
Unk1: 0,
},
{
StartTime: midnight.Add(24 * time.Hour), // midnight of following day.
ActiveFeatures: 0x3FFF,
ActiveFeatures: determineFeatured(),
Unk1: 0,
},
})
}

return features
}

func handleMsgMhfGetWeeklySchedule(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetWeeklySchedule)
eventSchedules := makeFeatured()
var t = time.Now().In(time.FixedZone("UTC+9", 9*60*60))

resp := byteframe.NewByteFrame()
resp.WriteUint8(uint8(len(eventSchedules))) // Entry count, client only parses the first 7 or 8.
resp.WriteUint32(uint32(t.Add(-5 * time.Minute).Unix())) // 5 minutes ago server time
Expand Down Expand Up @@ -2489,7 +2568,10 @@ func handleMsgMhfAcquireFestaPersonalPrize(s *Session, p mhfpacket.MHFPacket) {}

func handleMsgMhfGetRandFromTable(s *Session, p mhfpacket.MHFPacket) {}

func handleMsgMhfGetCafeDuration(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfGetCafeDuration(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfGetCafeDuration)
doAckBufSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00}) // Return succeed to stop softlock
}

func handleMsgMhfGetCafeDurationBonusInfo(s *Session, p mhfpacket.MHFPacket) {}

Expand Down Expand Up @@ -2977,6 +3059,7 @@ func handleMsgMhfGetUdTacticsRanking(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfGetUdTacticsRewardList(s *Session, p mhfpacket.MHFPacket) {
// Diva defense interception
pkt := p.(*mhfpacket.MsgMhfGetUdTacticsRewardList)

// Temporary canned response
data, _ := hex.DecodeString("000094000000010732DD00010000000000010732DD00010100000000C8071F2800050100000000C80705C000050000000001901A000001F40000000001901A000001F40100000002580705C00005000000000258071F2800050100000003201A000003E80100000003201A000003E80000000003E81A000004B00100000003E81A000004B00000000004B01A000005DC0100000004B01A000005DC0000000005781A000008FC0100000005781A000008FC0000000006401A000009C40000000006401A000009C40100000007081A00000BB80100000007081A00000BB80000000007D00725FA00010000000007D01A00000CE40000000007D00725FC00010100000007D00725FB00010100000007D00725FA00010100000007D01A00000CE40100000007D00725FC00010000000007D00725FB0001000000000BB80705C00005000000000BB8071F280005010000000FA01A00000DAC000000000FA01A00000DAC0100000013880705C00005000000001388071F2800050100000017700725FE00010100000017700725FD00010100000017700725FF00010100000017700725FD00010000000017700725FE00010000000017700725FF0001000000001B581A00000E74000000001B581A00000E74010000001F400727D00005010000001F400727D000050000000023281A00000FA00000000023281A00000FA00100000027100736EF000100000000271007369600010100000027100736EF00010100000027100736EF0001000000002EE00727D10005010000002EE00727D100050000000036B01D000000010100000036B01D00000001000000003A980737DB0001010000003A980736EF00010000000046500725E600010100000046500725E60001000000004E200738C90001010000004E200736EF00010000000055F01A000010680100000055F01A000010680000000061A80736EF00010000000061A80739A600010100000065900727D200050000000065900727D20005010000007530073A0600010100000075300736EF00010000000075300736EF00010000000075300736EF00010100000084D01D000000020000000084D01D00000002010000009C400727D30005010000009C400727D3000500000000B3B01A0000119400000000B3B01A0000119401000000C3500727D4000500000000C3500727D4000501000000D2F01D0000000300000000D2F01D0000000301000000EA600736EF000100000000EA600736EF000101000000F6181A0000125C00000000F6181A0000125C0100000111700727D500050000000111700727D500050100000119400727D600050100000119400727D600050000000121101D000000040000000121101D000000040100000130B01A000013880000000130B01A000013880100000140500727D700050000000140500727D700050100000148201D000000050000000148201D00000005010000014FF01A000014B4000000014FF01A000014B4010000015F900736EF0001000000015F900736EF00010100000167600729EA00050000000167600729EA0005010000016F301D00000006010000016F301D00000006000000017ED00729EB0005000000017ED00729EB0005010000018E701A0000157C010000018E701A0000157C0000000196401D000000070000000196401D00000007010000019E100729EC0005000000019E100729EC000501000001ADB00727CD000100000001ADB00727CD000101000001BD501D0000000800000001BD501D0000000801000001CCF01A0000164401000001CCF01A0000164400000001E4601D0000000901000001E4601D0000000900000001EC300727CC000101000001EC300727CC0001000000020B701D0000000A000000020B701D0000000A010000023A501A0000170C010000023A501A0000170C0000000249F00736EF00010100000249F00736EF00010000000271001A000017D40100000271001A000017D400000002A7B01A0000189C01000002A7B01A0000189C00000002BF200736EF000100000002BF200736EF000101000002D6901A0000196401000002D6901A00001964000000030D400727CB0001000000030D400727CB00010100000343F01A00001A2C0100000343F01A00001A2C0000000372D0072CB0000F0000000372D0072CB0000F01000003A9801A00001BBC00000003A9801A00001BBC01000003F7A01A000003E800010003F7A01A000003E80101000445C01A000003E80101000445C01A000003E80001005E000000020704020005010000000002070402000500000000000307040200140000000000030704020014010000000005071D200003010000000005071D20000300000000000607040200140100000000060704020014000000000008071D210003010000000008071D21000300000000000A070402001401000000000A070402001400000000000C0722EC000501000000000C0722ED000500000000000C0722F2000500000000000C0722EC000500000000000C0722EF000500000000000C0722ED000501000000000C0722F2000501000000000C0722EF000501000000000D1A000003E801000000000D1A000003E800000000000F07357C000501000000000F07357D000501000000000F07357C000500000000000F07357D00050000000000111A000007D00000000000111A000007D00100000000141C00000001000000000014071D2200030000000000141C00000001010000000014071D22000301000000001607357D000701000000001607357C00070000000000160704020028000000000016070402002801000000001607357C000701000000001607357D0007000000000018071D270003000000000018071D27000301000000001A1A00000BB800000000001A1A00000BB801000000001C07357D000701000000001C070402002801000000001C07357D000700000000001C07357C000700000000001C070402002800000000001C07357C000701000000001E070402003C01000000001E070402003C000000000020071D26000301000000002007357C000700000000002007357D000700000000002007357C000701000000002007357D0007010000000020071D260003000000000023071D280003010000000023071D28000300000000002A070402003C00000000002A070402003C01000000002C0725EE000100000000002C0725EE000101000000002E070402005001000000002E07357D000A01000000002E070402005000000000002E07357C000A00000000002E07357D000A00000000002E07357C000A0100000000300725ED00010000000000300725ED0001010000000032071D200003010000000032071D200003000000000034072C7B0001000000000034072C7B0001010000000037071D210003000000000037071D21000301000000003C0722F1000A00000000003C0722F1000A01000000004107040200500000000000410704020050010000000046071D220003010000000046071D22000300000000004B071D27000301000000004B071D2700030000000000500722F1000F0100000000500722F1000F0000000000550704020050010000000055070402005000000000005A071D26000301000000005A071D26000300000000005F071D28000300000000005F071D2800030100000000641A0000C3500100000000641A0000C3500000002607000E00C8000000010000000307000F0032000000010000000307001000320000000100000003070011003200000001000000030700120032000000010000000307000E0096000000040000000A07000F0028000000040000000A0700100028000000040000000A0700110028000000040000000A0700120028000000040000000A07000E00640000000B0000001907000F001E0000000B00000019070010001E0000000B00000019070011001E0000000B00000019070012001E0000000B0000001907000E00320000001A0000002807000F00140000001A0000002807001000140000001A0000002807001100140000001A0000002807001200140000001A0000002807000E001E000000290000004607000F000A0000002900000046070010000A000000290000004607001100010000002900000046070012000A000000290000004607000E0019000000470000006407000F0008000000470000006407001000080000004700000064070011000100000047000000640700120008000000470000006407000E000F000000650000009607000F0006000000650000009607001000010000006500000096070011000600000065000000960700120006000000650000009607000E000500000097000001F407000F000500000097000001F4070010000500000097000001F4")
doAckBufSucceed(s, pkt.AckHandle, data)
Expand Down Expand Up @@ -3283,3 +3366,8 @@ func handleMsgSysReserve20D(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgSysReserve20E(s *Session, p mhfpacket.MHFPacket) {}

func handleMsgSysReserve20F(s *Session, p mhfpacket.MHFPacket) {}

func handleMsgUnknown(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgUnknown)
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
}
27 changes: 27 additions & 0 deletions server/channelserver/makefeature.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package channelserver

import (
"math/rand"
"time"
)

func makeFeatureSet() uint32 {
bits := []int{0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000}
bit := 0x0

n := 0
rand.Seed(time.Now().UnixNano())

// Loop through the bits
for n < len(bits) {

// Add bit to it
if rand.Intn(2) == 1 {
bit = bit | bits[n]
}

n += 1
}

return uint32(bit) // Return the bit
}
7 changes: 6 additions & 1 deletion server/entranceserver/make_resp.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package entranceserver
import (
"encoding/binary"
"net"
"strconv"

"github.com/Andoryuuta/Erupe/common/stringsupport"

Expand Down Expand Up @@ -41,10 +42,14 @@ func encodeServerInfo(serverInfos []config.EntranceServerInfo) []byte {
bf.WriteUint32(si.AllowedClientFlags)

for channelIdx, ci := range si.Channels {
conn, _ := net.Dial("tcp", "localhost:"+strconv.FormatInt(int64(ci.Port)+1, 10))
bytes := make([]byte, 16)
conn.Read(bytes)

bf.WriteUint16(ci.Port)
bf.WriteUint16(16 + uint16(channelIdx))
bf.WriteUint16(ci.MaxPlayers)
bf.WriteUint16(ci.CurrentPlayers)
bf.WriteUint16(uint16(byteframe.NewByteFrameFromBytes(bytes).ReadInt8()))
bf.WriteUint16(ci.Unk4)
bf.WriteUint16(ci.Unk5)
bf.WriteUint16(ci.Unk6)
Expand Down