Merge pull request #29 from ZeruLight/feature/warehouse

feature/warehouse
This commit is contained in:
wish
2022-08-16 01:58:23 +10:00
committed by GitHub
5 changed files with 336 additions and 22 deletions

View File

@@ -1,15 +1,19 @@
package mhfpacket
import (
"errors"
import (
"errors"
"erupe-ce/network/clientctx"
"erupe-ce/network"
"erupe-ce/common/byteframe"
"erupe-ce/network"
"erupe-ce/network/clientctx"
)
// MsgMhfEnumerateWarehouse represents the MSG_MHF_ENUMERATE_WAREHOUSE
type MsgMhfEnumerateWarehouse struct{}
type MsgMhfEnumerateWarehouse struct {
AckHandle uint32
BoxType string
BoxIndex uint8
}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfEnumerateWarehouse) Opcode() network.PacketID {
@@ -18,7 +22,17 @@ func (m *MsgMhfEnumerateWarehouse) Opcode() network.PacketID {
// Parse parses the packet from binary
func (m *MsgMhfEnumerateWarehouse) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
m.AckHandle = bf.ReadUint32()
boxType := bf.ReadUint8()
switch boxType {
case 0:
m.BoxType = "item"
case 1:
m.BoxType = "equip"
}
m.BoxIndex = bf.ReadUint8()
_ = bf.ReadUint16()
return nil
}
// Build builds a binary packet from the current data.

View File

@@ -1,15 +1,22 @@
package mhfpacket
import (
"errors"
import (
"errors"
"erupe-ce/common/stringsupport"
"erupe-ce/network/clientctx"
"erupe-ce/network"
"erupe-ce/common/byteframe"
"erupe-ce/network"
"erupe-ce/network/clientctx"
)
// MsgMhfOperateWarehouse represents the MSG_MHF_OPERATE_WAREHOUSE
type MsgMhfOperateWarehouse struct{}
type MsgMhfOperateWarehouse struct {
AckHandle uint32
Operation uint8
BoxType string
BoxIndex uint8
Name string
}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfOperateWarehouse) Opcode() network.PacketID {
@@ -18,7 +25,20 @@ func (m *MsgMhfOperateWarehouse) Opcode() network.PacketID {
// Parse parses the packet from binary
func (m *MsgMhfOperateWarehouse) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
m.AckHandle = bf.ReadUint32()
m.Operation = bf.ReadUint8()
boxType := bf.ReadUint8()
switch boxType {
case 0:
m.BoxType = "item"
case 1:
m.BoxType = "equip"
}
m.BoxIndex = bf.ReadUint8()
_ = bf.ReadUint8() // lenName
_ = bf.ReadUint16() // Unk
m.Name = stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes())
return nil
}
// Build builds a binary packet from the current data.

View File

@@ -1,15 +1,28 @@
package mhfpacket
import (
"errors"
"erupe-ce/network/clientctx"
"erupe-ce/network"
import (
"errors"
"erupe-ce/common/byteframe"
"erupe-ce/network"
"erupe-ce/network/clientctx"
)
type WarehouseStack struct {
ID uint32
Index uint16
EquipType uint16
ItemID uint16
Quantity uint16
Data []byte
}
// MsgMhfUpdateWarehouse represents the MSG_MHF_UPDATE_WAREHOUSE
type MsgMhfUpdateWarehouse struct{}
type MsgMhfUpdateWarehouse struct {
AckHandle uint32
BoxType string
BoxIndex uint8
Updates []WarehouseStack
}
// Opcode returns the ID associated with this packet type.
func (m *MsgMhfUpdateWarehouse) Opcode() network.PacketID {
@@ -18,7 +31,37 @@ func (m *MsgMhfUpdateWarehouse) Opcode() network.PacketID {
// Parse parses the packet from binary
func (m *MsgMhfUpdateWarehouse) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
return errors.New("NOT IMPLEMENTED")
m.AckHandle = bf.ReadUint32()
boxType := bf.ReadUint8()
switch boxType {
case 0:
m.BoxType = "item"
case 1:
m.BoxType = "equip"
}
m.BoxIndex = bf.ReadUint8()
changes := int(bf.ReadUint16())
var stackUpdate WarehouseStack
for i := 0; i < changes; i++ {
switch boxType {
case 0:
stackUpdate.ID = bf.ReadUint32()
stackUpdate.Index = bf.ReadUint16()
stackUpdate.ItemID = bf.ReadUint16()
stackUpdate.Quantity = bf.ReadUint16()
_ = bf.ReadUint16() // Unk
m.Updates = append(m.Updates, stackUpdate)
case 1:
stackUpdate.ID = bf.ReadUint32()
stackUpdate.Index = bf.ReadUint16()
stackUpdate.EquipType = bf.ReadUint16()
stackUpdate.ItemID = bf.ReadUint16()
stackUpdate.Data = bf.ReadBytes(56)
m.Updates = append(m.Updates, stackUpdate)
}
}
_ = bf.ReadUint16()
return nil
}
// Build builds a binary packet from the current data.

View File

@@ -0,0 +1,49 @@
BEGIN;
CREATE TABLE IF NOT EXISTS public.warehouse (
character_id integer PRIMARY KEY,
item0 bytea,
item1 bytea,
item2 bytea,
item3 bytea,
item4 bytea,
item5 bytea,
item6 bytea,
item7 bytea,
item8 bytea,
item9 bytea,
item10 bytea,
item0name text,
item1name text,
item2name text,
item3name text,
item4name text,
item5name text,
item6name text,
item7name text,
item8name text,
item9name text,
equip0 bytea,
equip1 bytea,
equip2 bytea,
equip3 bytea,
equip4 bytea,
equip5 bytea,
equip6 bytea,
equip7 bytea,
equip8 bytea,
equip9 bytea,
equip10 bytea,
equip0name text,
equip1name text,
equip2name text,
equip3name text,
equip4name text,
equip5name text,
equip6name text,
equip7name text,
equip8name text,
equip9name text
);
END;

View File

@@ -5,11 +5,37 @@ import (
ps "erupe-ce/common/pascalstring"
"erupe-ce/common/stringsupport"
"erupe-ce/network/mhfpacket"
"fmt"
"go.uber.org/zap"
"io"
"time"
)
const warehouseNamesQuery = `
SELECT
COALESCE(item0name, ''),
COALESCE(item1name, ''),
COALESCE(item2name, ''),
COALESCE(item3name, ''),
COALESCE(item4name, ''),
COALESCE(item5name, ''),
COALESCE(item6name, ''),
COALESCE(item7name, ''),
COALESCE(item8name, ''),
COALESCE(item9name, ''),
COALESCE(equip0name, ''),
COALESCE(equip1name, ''),
COALESCE(equip2name, ''),
COALESCE(equip3name, ''),
COALESCE(equip4name, ''),
COALESCE(equip5name, ''),
COALESCE(equip6name, ''),
COALESCE(equip7name, ''),
COALESCE(equip8name, ''),
COALESCE(equip9name, '')
FROM warehouse
`
func handleMsgMhfUpdateInterior(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUpdateInterior)
_, err := s.server.db.Exec("UPDATE characters SET house=$1 WHERE id=$2", pkt.InteriorData, s.charID)
@@ -341,8 +367,170 @@ func handleMsgMhfAcquireTitle(s *Session, p mhfpacket.MHFPacket) {
func handleMsgMhfResetTitle(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfOperateWarehouse(s *Session, p mhfpacket.MHFPacket) {}
func handleMsgMhfOperateWarehouse(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfOperateWarehouse)
var t int
err := s.server.db.QueryRow("SELECT character_id FROM warehouse WHERE character_id=$1", s.charID).Scan(&t)
if err != nil {
s.server.db.Exec("INSERT INTO warehouse (character_id) VALUES ($1)", s.charID)
}
bf := byteframe.NewByteFrame()
bf.WriteUint8(pkt.Operation)
switch pkt.Operation {
case 0:
var count uint8
itemNames := make([]string, 10)
equipNames := make([]string, 10)
s.server.db.QueryRow(fmt.Sprintf("%s WHERE character_id=$1", warehouseNamesQuery), s.charID).Scan(&itemNames[0],
&itemNames[1], &itemNames[2], &itemNames[3], &itemNames[4], &itemNames[5], &itemNames[6], &itemNames[7], &itemNames[8], &itemNames[9], &equipNames[0],
&equipNames[1], &equipNames[2], &equipNames[3], &equipNames[4], &equipNames[5], &equipNames[6], &equipNames[7], &equipNames[8], &equipNames[9])
bf.WriteUint32(0)
bf.WriteUint16(10000) // Usages
temp := byteframe.NewByteFrame()
for i, name := range itemNames {
if len(name) > 0 {
count++
temp.WriteUint8(0)
temp.WriteUint8(uint8(i))
ps.Uint8(temp, name, true)
}
}
for i, name := range equipNames {
if len(name) > 0 {
count++
temp.WriteUint8(1)
temp.WriteUint8(uint8(i))
ps.Uint8(temp, name, true)
}
}
bf.WriteUint8(count)
bf.WriteBytes(temp.Data())
case 1:
bf.WriteUint8(0)
case 2:
s.server.db.Exec(fmt.Sprintf("UPDATE warehouse SET %s%dname=$1 WHERE character_id=$2", pkt.BoxType, pkt.BoxIndex), pkt.Name, s.charID)
case 3:
bf.WriteUint32(0) // Usage renewal time, >1 = disabled
bf.WriteUint16(10000) // Usages
case 4:
bf.WriteUint32(0)
bf.WriteUint16(10000) // Usages
bf.WriteUint8(0)
}
// Opcodes
// 0 = Get box names
// 1 = Commit usage
// 2 = Rename
// 3 = Get usage limit
// 4 = Get gift box names (doesn't do anything?)
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
}
func handleMsgMhfEnumerateWarehouse(s *Session, p mhfpacket.MHFPacket) {}
func getWarehouseBox(s *Session, boxType string, boxIndex uint8) []mhfpacket.WarehouseStack {
var data []byte
s.server.db.QueryRow(fmt.Sprintf("SELECT %s%d FROM warehouse WHERE character_id=$1", boxType, boxIndex), s.charID).Scan(&data)
if len(data) > 0 {
box := byteframe.NewByteFrameFromBytes(data)
numStacks := box.ReadUint16()
stacks := make([]mhfpacket.WarehouseStack, numStacks)
for i := 0; i < int(numStacks); i++ {
if boxType == "item" {
stacks[i].ID = box.ReadUint32()
stacks[i].Index = box.ReadUint16()
stacks[i].ItemID = box.ReadUint16()
stacks[i].Quantity = box.ReadUint16()
box.ReadUint16()
} else {
stacks[i].ID = box.ReadUint32()
stacks[i].Index = box.ReadUint16()
stacks[i].EquipType = box.ReadUint16()
stacks[i].ItemID = box.ReadUint16()
stacks[i].Data = box.ReadBytes(56)
}
}
return stacks
} else {
return make([]mhfpacket.WarehouseStack, 0)
}
}
func handleMsgMhfUpdateWarehouse(s *Session, p mhfpacket.MHFPacket) {}
func boxToBytes(stacks []mhfpacket.WarehouseStack, boxType string) []byte {
bf := byteframe.NewByteFrame()
bf.WriteUint16(uint16(len(stacks)))
for i, stack := range stacks {
if boxType == "item" {
bf.WriteUint32(stack.ID)
bf.WriteUint16(uint16(i + 1))
bf.WriteUint16(stack.ItemID)
bf.WriteUint16(stack.Quantity)
bf.WriteUint16(0)
} else {
bf.WriteUint32(stack.ID)
bf.WriteUint16(uint16(i + 1))
bf.WriteUint16(stack.EquipType)
bf.WriteUint16(stack.ItemID)
bf.WriteBytes(stack.Data)
}
}
bf.WriteUint16(0)
return bf.Data()
}
func handleMsgMhfEnumerateWarehouse(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfEnumerateWarehouse)
box := getWarehouseBox(s, pkt.BoxType, pkt.BoxIndex)
if len(box) > 0 {
doAckBufSucceed(s, pkt.AckHandle, boxToBytes(box, pkt.BoxType))
} else {
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 4))
}
}
func handleMsgMhfUpdateWarehouse(s *Session, p mhfpacket.MHFPacket) {
pkt := p.(*mhfpacket.MsgMhfUpdateWarehouse)
box := getWarehouseBox(s, pkt.BoxType, pkt.BoxIndex)
// Update existing stacks
var newStacks []mhfpacket.WarehouseStack
for _, update := range pkt.Updates {
exists := false
if pkt.BoxType == "item" {
for i, stack := range box {
if stack.Index == update.Index {
exists = true
box[i].Quantity = update.Quantity
break
}
}
} else {
for i, stack := range box {
if stack.Index == update.Index {
exists = true
box[i].ItemID = update.ItemID
break
}
}
}
if exists == false {
newStacks = append(newStacks, update)
}
}
// Append new stacks
for _, stack := range newStacks {
box = append(box, stack)
}
// Slice empty stacks
var cleanedBox []mhfpacket.WarehouseStack
for _, stack := range box {
if pkt.BoxType == "item" {
if stack.Quantity > 0 {
cleanedBox = append(cleanedBox, stack)
}
} else {
if stack.ItemID != 0 {
cleanedBox = append(cleanedBox, stack)
}
}
}
s.server.db.Exec(fmt.Sprintf("UPDATE warehouse SET %s%d=$1 WHERE character_id=$2", pkt.BoxType, pkt.BoxIndex), boxToBytes(cleanedBox, pkt.BoxType), s.charID)
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
}