mirror of
https://github.com/Mezeporta/Erupe.git
synced 2025-12-13 23:44:52 +01:00
Compare commits
6 Commits
v9.2.0
...
feature/re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf86424541 | ||
|
|
23138b2d5b | ||
|
|
3be014ba7f | ||
|
|
4ffb176049 | ||
|
|
b0d53431c0 | ||
|
|
13522ef2c9 |
@@ -2,62 +2,14 @@ package stringsupport
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/text/encoding"
|
||||
"golang.org/x/text/encoding/japanese"
|
||||
"golang.org/x/text/transform"
|
||||
)
|
||||
|
||||
// StringConverter is a small helper for encoding/decoding strings.
|
||||
type StringConverter struct {
|
||||
Encoding encoding.Encoding
|
||||
}
|
||||
|
||||
// Decode decodes the given bytes as the set encoding.
|
||||
func (sc *StringConverter) Decode(data []byte) (string, error) {
|
||||
decoded, err := ioutil.ReadAll(transform.NewReader(bytes.NewBuffer(data), sc.Encoding.NewDecoder()))
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(decoded), nil
|
||||
}
|
||||
|
||||
// MustDecode decodes the given bytes as the set encoding. Panics on decode failure.
|
||||
func (sc *StringConverter) MustDecode(data []byte) string {
|
||||
decoded, err := sc.Decode(data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return decoded
|
||||
}
|
||||
|
||||
// Encode encodes the given string as the set encoding.
|
||||
func (sc *StringConverter) Encode(data string) ([]byte, error) {
|
||||
encoded, err := ioutil.ReadAll(transform.NewReader(bytes.NewBuffer([]byte(data)), sc.Encoding.NewEncoder()))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return encoded, nil
|
||||
}
|
||||
|
||||
// MustEncode encodes the given string as the set encoding. Panics on encode failure.
|
||||
func (sc *StringConverter) MustEncode(data string) []byte {
|
||||
encoded, err := sc.Encode(data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return encoded
|
||||
}
|
||||
|
||||
func UTF8ToSJIS(x string) []byte {
|
||||
e := japanese.ShiftJIS.NewEncoder()
|
||||
xt, _, err := transform.String(e, x)
|
||||
@@ -69,7 +21,7 @@ func UTF8ToSJIS(x string) []byte {
|
||||
|
||||
func SJISToUTF8(b []byte) string {
|
||||
d := japanese.ShiftJIS.NewDecoder()
|
||||
result, err := ioutil.ReadAll(transform.NewReader(bytes.NewReader(b), d))
|
||||
result, err := io.ReadAll(transform.NewReader(bytes.NewReader(b), d))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"DisableSoftCrash": false,
|
||||
"HideLoginNotice": true,
|
||||
"LoginNotices": [
|
||||
"<BODY><CENTER><SIZE_3><C_4>Welcome to Erupe SU9.2!<BR><BODY><LEFT><SIZE_2><C_5>Erupe is experimental software<C_7>, we are not liable for any<BR><BODY>issues caused by installing the software!<BR><BODY><BR><BODY><C_4>■Report bugs on Discord!<C_7><BR><BODY><BR><BODY><C_4>■Test everything!<C_7><BR><BODY><BR><BODY><C_4>■Don't talk to softlocking NPCs!<C_7><BR><BODY><BR><BODY><C_4>■Fork the code on GitHub!<C_7><BR><BODY><BR><BODY>Thank you to all of the contributors,<BR><BODY><BR><BODY>this wouldn't exist without you."
|
||||
"<BODY><CENTER><SIZE_3><C_4>Welcome to Erupe SU9.3!<BR><BODY><LEFT><SIZE_2><C_5>Erupe is experimental software<C_7>, we are not liable for any<BR><BODY>issues caused by installing the software!<BR><BODY><BR><BODY><C_4>■Report bugs on Discord!<C_7><BR><BODY><BR><BODY><C_4>■Test everything!<C_7><BR><BODY><BR><BODY><C_4>■Don't talk to softlocking NPCs!<C_7><BR><BODY><BR><BODY><C_4>■Fork the code on GitHub!<C_7><BR><BODY><BR><BODY>Thank you to all of the contributors,<BR><BODY><BR><BODY>this wouldn't exist without you."
|
||||
],
|
||||
"PatchServerManifest": "",
|
||||
"PatchServerFile": "",
|
||||
|
||||
2
main.go
2
main.go
@@ -54,7 +54,7 @@ func main() {
|
||||
defer zapLogger.Sync()
|
||||
logger := zapLogger.Named("main")
|
||||
|
||||
logger.Info(fmt.Sprintf("Starting Erupe (9.2-%s)", Commit()))
|
||||
logger.Info(fmt.Sprintf("Starting Erupe (9.3b-%s)", Commit()))
|
||||
|
||||
if config.ErupeConfig.Database.Password == "" {
|
||||
preventClose("Database password is blank")
|
||||
|
||||
@@ -2,6 +2,7 @@ package mhfpacket
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"erupe-ce/common/stringsupport"
|
||||
|
||||
"erupe-ce/common/byteframe"
|
||||
"erupe-ce/network"
|
||||
@@ -10,9 +11,16 @@ import (
|
||||
|
||||
// MsgMhfUpdateGuildMessageBoard represents the MSG_MHF_UPDATE_GUILD_MESSAGE_BOARD
|
||||
type MsgMhfUpdateGuildMessageBoard struct {
|
||||
AckHandle uint32
|
||||
MessageOp uint32
|
||||
Request []byte
|
||||
AckHandle uint32
|
||||
MessageOp uint32
|
||||
PostType uint32
|
||||
StampID uint32
|
||||
TitleLength uint32
|
||||
BodyLength uint32
|
||||
Title string
|
||||
Body string
|
||||
PostID uint32
|
||||
LikeState bool
|
||||
}
|
||||
|
||||
// Opcode returns the ID associated with this packet type.
|
||||
@@ -24,9 +32,31 @@ func (m *MsgMhfUpdateGuildMessageBoard) Opcode() network.PacketID {
|
||||
func (m *MsgMhfUpdateGuildMessageBoard) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||
m.AckHandle = bf.ReadUint32()
|
||||
m.MessageOp = bf.ReadUint32()
|
||||
if m.MessageOp != 5 {
|
||||
m.Request = bf.DataFromCurrent()
|
||||
bf.Seek(int64(len(bf.Data())-2), 0)
|
||||
switch m.MessageOp {
|
||||
case 0:
|
||||
m.PostType = bf.ReadUint32()
|
||||
m.StampID = bf.ReadUint32()
|
||||
m.TitleLength = bf.ReadUint32()
|
||||
m.BodyLength = bf.ReadUint32()
|
||||
m.Title = stringsupport.SJISToUTF8(bf.ReadBytes(uint(m.TitleLength)))
|
||||
m.Body = stringsupport.SJISToUTF8(bf.ReadBytes(uint(m.BodyLength)))
|
||||
case 1:
|
||||
m.PostID = bf.ReadUint32()
|
||||
case 2:
|
||||
m.PostID = bf.ReadUint32()
|
||||
bf.ReadBytes(8)
|
||||
m.TitleLength = bf.ReadUint32()
|
||||
m.BodyLength = bf.ReadUint32()
|
||||
m.Title = stringsupport.SJISToUTF8(bf.ReadBytes(uint(m.TitleLength)))
|
||||
m.Body = stringsupport.SJISToUTF8(bf.ReadBytes(uint(m.BodyLength)))
|
||||
case 3:
|
||||
m.PostID = bf.ReadUint32()
|
||||
bf.ReadBytes(8)
|
||||
m.StampID = bf.ReadUint32()
|
||||
case 4:
|
||||
m.PostID = bf.ReadUint32()
|
||||
bf.ReadBytes(8)
|
||||
m.LikeState = bf.ReadBool()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
5
patch-schema/return-guild.sql
Normal file
5
patch-schema/return-guild.sql
Normal file
@@ -0,0 +1,5 @@
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE public.guilds ADD COLUMN IF NOT EXISTS return_type INTEGER DEFAULT 0;
|
||||
|
||||
END;
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
pointerGender = 0x81 // +1
|
||||
pointerGender = 0x51 // +1
|
||||
pointerRP = 0x22D16 // +2
|
||||
pointerHouseTier = 0x1FB6C // +5
|
||||
pointerHouseData = 0x1FE01 // +195
|
||||
|
||||
@@ -52,6 +52,7 @@ type Guild struct {
|
||||
RankRP uint32 `db:"rank_rp"`
|
||||
EventRP uint32 `db:"event_rp"`
|
||||
Comment string `db:"comment"`
|
||||
ReturnType uint8 `db:"return_type"`
|
||||
PugiName1 string `db:"pugi_name_1"`
|
||||
PugiName2 string `db:"pugi_name_2"`
|
||||
PugiName3 string `db:"pugi_name_3"`
|
||||
@@ -127,6 +128,7 @@ SELECT
|
||||
leader_id,
|
||||
lc.name as leader_name,
|
||||
comment,
|
||||
return_type,
|
||||
COALESCE(pugi_name_1, '') AS pugi_name_1,
|
||||
COALESCE(pugi_name_2, '') AS pugi_name_2,
|
||||
COALESCE(pugi_name_3, '') AS pugi_name_3,
|
||||
@@ -445,7 +447,7 @@ func (guild *Guild) HasApplicationForCharID(s *Session, charID uint32) (bool, er
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func CreateGuild(s *Session, guildName string) (int32, error) {
|
||||
func CreateGuild(s *Session, guildName string) (uint32, error) {
|
||||
transaction, err := s.server.db.Begin()
|
||||
|
||||
if err != nil {
|
||||
@@ -468,7 +470,7 @@ func CreateGuild(s *Session, guildName string) (int32, error) {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
var guildId int32
|
||||
var guildId uint32
|
||||
|
||||
guildResult.Next()
|
||||
|
||||
@@ -606,7 +608,7 @@ func handleMsgMhfCreateGuild(s *Session, p mhfpacket.MHFPacket) {
|
||||
|
||||
bf := byteframe.NewByteFrame()
|
||||
|
||||
bf.WriteUint32(uint32(guildId))
|
||||
bf.WriteUint32(guildId)
|
||||
|
||||
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
|
||||
}
|
||||
@@ -933,12 +935,16 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
|
||||
|
||||
bf.WriteBool(!guild.Recruiting)
|
||||
|
||||
if characterGuildData == nil || characterGuildData.IsApplicant {
|
||||
bf.WriteUint16(0x00)
|
||||
} else if guild.LeaderCharID == s.charID {
|
||||
bf.WriteUint16(0x01)
|
||||
if guild.ReturnType > 0 {
|
||||
bf.WriteUint16(0x0F)
|
||||
} else {
|
||||
bf.WriteUint16(0x02)
|
||||
if characterGuildData == nil || characterGuildData.IsApplicant {
|
||||
bf.WriteUint16(0x00)
|
||||
} else if guild.LeaderCharID == s.charID {
|
||||
bf.WriteUint16(0x01)
|
||||
} else {
|
||||
bf.WriteUint16(0x02)
|
||||
}
|
||||
}
|
||||
|
||||
bf.WriteUint32(uint32(guild.CreatedAt.Unix()))
|
||||
@@ -953,9 +959,9 @@ func handleMsgMhfInfoGuild(s *Session, p mhfpacket.MHFPacket) {
|
||||
bf.WriteUint32(guild.RankRP)
|
||||
bf.WriteBytes(guildLeaderName)
|
||||
bf.WriteBytes([]byte{0x00, 0x00, 0x00, 0x00}) // Unk
|
||||
bf.WriteBool(false) // isReturnGuild
|
||||
bf.WriteBool(false) // earnedSpecialHall
|
||||
bf.WriteBytes([]byte{0x02, 0x02}) // Unk
|
||||
bf.WriteUint8(guild.ReturnType)
|
||||
bf.WriteBool(false) // earnedSpecialHall
|
||||
bf.WriteBytes([]byte{0x02, 0x02}) // Unk
|
||||
bf.WriteUint32(guild.EventRP)
|
||||
ps.Uint8(bf, guild.PugiName1, true)
|
||||
ps.Uint8(bf, guild.PugiName2, true)
|
||||
@@ -1867,7 +1873,6 @@ func handleMsgMhfEnumerateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
|
||||
|
||||
func handleMsgMhfUpdateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfUpdateGuildMessageBoard)
|
||||
bf := byteframe.NewByteFrameFromBytes(pkt.Request)
|
||||
guild, err := GetGuildInfoByCharacterId(s, s.charID)
|
||||
applicant := false
|
||||
if guild != nil {
|
||||
@@ -1879,45 +1884,26 @@ func handleMsgMhfUpdateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
|
||||
}
|
||||
switch pkt.MessageOp {
|
||||
case 0: // Create message
|
||||
postType := bf.ReadUint32() // 0 = message, 1 = news
|
||||
stampID := bf.ReadUint32()
|
||||
titleLength := bf.ReadUint32()
|
||||
bodyLength := bf.ReadUint32()
|
||||
title := stringsupport.SJISToUTF8(bf.ReadBytes(uint(titleLength)))
|
||||
body := stringsupport.SJISToUTF8(bf.ReadBytes(uint(bodyLength)))
|
||||
s.server.db.Exec("INSERT INTO guild_posts (guild_id, author_id, stamp_id, post_type, title, body) VALUES ($1, $2, $3, $4, $5, $6)", guild.ID, s.charID, stampID, postType, title, body)
|
||||
s.server.db.Exec("INSERT INTO guild_posts (guild_id, author_id, stamp_id, post_type, title, body) VALUES ($1, $2, $3, $4, $5, $6)", guild.ID, s.charID, pkt.StampID, pkt.PostType, pkt.Title, pkt.Body)
|
||||
// TODO: if there are too many messages, purge excess
|
||||
case 1: // Delete message
|
||||
postID := bf.ReadUint32()
|
||||
s.server.db.Exec("DELETE FROM guild_posts WHERE id = $1", postID)
|
||||
s.server.db.Exec("DELETE FROM guild_posts WHERE id = $1", pkt.PostID)
|
||||
case 2: // Update message
|
||||
postID := bf.ReadUint32()
|
||||
bf.ReadBytes(8)
|
||||
titleLength := bf.ReadUint32()
|
||||
bodyLength := bf.ReadUint32()
|
||||
title := stringsupport.SJISToUTF8(bf.ReadBytes(uint(titleLength)))
|
||||
body := stringsupport.SJISToUTF8(bf.ReadBytes(uint(bodyLength)))
|
||||
s.server.db.Exec("UPDATE guild_posts SET title = $1, body = $2 WHERE id = $3", title, body, postID)
|
||||
s.server.db.Exec("UPDATE guild_posts SET title = $1, body = $2 WHERE id = $3", pkt.Title, pkt.Body, pkt.PostID)
|
||||
case 3: // Update stamp
|
||||
postID := bf.ReadUint32()
|
||||
bf.ReadBytes(8)
|
||||
stampID := bf.ReadUint32()
|
||||
s.server.db.Exec("UPDATE guild_posts SET stamp_id = $1 WHERE id = $2", stampID, postID)
|
||||
s.server.db.Exec("UPDATE guild_posts SET stamp_id = $1 WHERE id = $2", pkt.StampID, pkt.PostID)
|
||||
case 4: // Like message
|
||||
postID := bf.ReadUint32()
|
||||
bf.ReadBytes(8)
|
||||
likeState := bf.ReadBool()
|
||||
var likedBy string
|
||||
err := s.server.db.QueryRow("SELECT liked_by FROM guild_posts WHERE id = $1", postID).Scan(&likedBy)
|
||||
err := s.server.db.QueryRow("SELECT liked_by FROM guild_posts WHERE id = $1", pkt.PostID).Scan(&likedBy)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to get guild message like data from db", zap.Error(err))
|
||||
} else {
|
||||
if likeState {
|
||||
if pkt.LikeState {
|
||||
likedBy = stringsupport.CSVAdd(likedBy, int(s.charID))
|
||||
s.server.db.Exec("UPDATE guild_posts SET liked_by = $1 WHERE id = $2", likedBy, postID)
|
||||
s.server.db.Exec("UPDATE guild_posts SET liked_by = $1 WHERE id = $2", likedBy, pkt.PostID)
|
||||
} else {
|
||||
likedBy = stringsupport.CSVRemove(likedBy, int(s.charID))
|
||||
s.server.db.Exec("UPDATE guild_posts SET liked_by = $1 WHERE id = $2", likedBy, postID)
|
||||
s.server.db.Exec("UPDATE guild_posts SET liked_by = $1 WHERE id = $2", likedBy, pkt.PostID)
|
||||
}
|
||||
}
|
||||
case 5: // Check for new messages
|
||||
@@ -1937,7 +1923,33 @@ func handleMsgMhfUpdateGuildMessageBoard(s *Session, p mhfpacket.MHFPacket) {
|
||||
|
||||
func handleMsgMhfEntryRookieGuild(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfEntryRookieGuild)
|
||||
doAckSimpleFail(s, pkt.AckHandle, make([]byte, 4))
|
||||
var guilds []*Guild
|
||||
var guildID uint32
|
||||
rows, err := s.server.db.Queryx(fmt.Sprintf(`%s WHERE return_type = 2`, guildInfoSelectQuery))
|
||||
if err == nil {
|
||||
for rows.Next() {
|
||||
guild, _ := buildGuildObjectFromDbResult(rows, err, s)
|
||||
guilds = append(guilds, guild)
|
||||
}
|
||||
}
|
||||
for i := range guilds {
|
||||
if guilds[i].MemberCount < 60 {
|
||||
guildID = guilds[i].ID
|
||||
break
|
||||
}
|
||||
}
|
||||
if guildID == 0 {
|
||||
guildID, _ = CreateGuild(s, fmt.Sprintf(s.server.dict["returnGuild"], len(guilds)+1))
|
||||
s.server.db.Exec(`UPDATE guilds SET is_return = 2, rank_rp = 1200 WHERE id = $1`, guildID)
|
||||
} else {
|
||||
s.server.db.Exec(`
|
||||
INSERT INTO guild_characters (guild_id, character_id, order_index)
|
||||
VALUES ($1, $2, (SELECT MAX(order_index) + 1 FROM guild_characters WHERE guild_id = $1))
|
||||
`, guildID, s.charID)
|
||||
}
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(guildID)
|
||||
doAckSimpleSucceed(s, pkt.AckHandle, bf.Data())
|
||||
}
|
||||
|
||||
func handleMsgMhfUpdateForceGuildRank(s *Session, p mhfpacket.MHFPacket) {}
|
||||
|
||||
@@ -51,6 +51,8 @@ func getLangStrings(s *Server) map[string]string {
|
||||
|
||||
strings["guildInviteDeclinedName"] = "辞退しました"
|
||||
strings["guildInviteDeclined"] = "招待した狩人が「%s」への招待を辞退しました。"
|
||||
|
||||
strings["returnGuild"] = "復帰猟団%d"
|
||||
default:
|
||||
strings["language"] = "English"
|
||||
strings["cafeReset"] = "Resets on %d/%d"
|
||||
@@ -99,6 +101,8 @@ func getLangStrings(s *Server) map[string]string {
|
||||
|
||||
strings["guildInviteDeclinedName"] = "Declined"
|
||||
strings["guildInviteDeclined"] = "The recipient declined your invitation to join\n「%s」."
|
||||
|
||||
strings["returnGuild"] = "Return Clan %d"
|
||||
}
|
||||
return strings
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user