mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-21 23:22:34 +01:00
docs: add doc.go files and godoc comments to all packages
Add package-level documentation (doc.go) to all 22 first-party packages and godoc comments to ~150 previously undocumented exported symbols across common/, network/, and server/.
This commit is contained in:
3
common/bfutil/doc.go
Normal file
3
common/bfutil/doc.go
Normal file
@@ -0,0 +1,3 @@
|
||||
// Package bfutil provides byte-slice utility functions for working with
|
||||
// null-terminated binary data commonly found in MHF network packets.
|
||||
package bfutil
|
||||
@@ -135,6 +135,7 @@ func (b *ByteFrame) DataFromCurrent() []byte {
|
||||
return b.buf[b.index:b.usedSize]
|
||||
}
|
||||
|
||||
// Index returns the current read/write position in the buffer.
|
||||
func (b *ByteFrame) Index() uint {
|
||||
return b.index
|
||||
}
|
||||
|
||||
4
common/byteframe/doc.go
Normal file
4
common/byteframe/doc.go
Normal file
@@ -0,0 +1,4 @@
|
||||
// Package byteframe provides a seekable, growable byte buffer for reading and
|
||||
// writing binary data in big-endian or little-endian byte order. It is the
|
||||
// primary serialization primitive used throughout the Erupe network layer.
|
||||
package byteframe
|
||||
4
common/decryption/doc.go
Normal file
4
common/decryption/doc.go
Normal file
@@ -0,0 +1,4 @@
|
||||
// Package decryption implements the JPK decompression algorithm used by
|
||||
// Monster Hunter Frontier to compress game data files. The format is
|
||||
// identified by the magic bytes 0x1A524B4A ("JKR").
|
||||
package decryption
|
||||
@@ -13,6 +13,8 @@ import (
|
||||
var mShiftIndex = 0
|
||||
var mFlag = byte(0)
|
||||
|
||||
// UnpackSimple decompresses a JPK type-3 compressed byte slice. If the data
|
||||
// does not start with the JKR magic header it is returned unchanged.
|
||||
func UnpackSimple(data []byte) []byte {
|
||||
mShiftIndex = 0
|
||||
mFlag = byte(0)
|
||||
@@ -40,6 +42,8 @@ func UnpackSimple(data []byte) []byte {
|
||||
return data
|
||||
}
|
||||
|
||||
// ProcessDecode runs the JPK LZ-style decompression loop, reading compressed
|
||||
// tokens from data and writing decompressed bytes into outBuffer.
|
||||
func ProcessDecode(data *byteframe.ByteFrame, outBuffer []byte) {
|
||||
outIndex := 0
|
||||
|
||||
@@ -85,6 +89,8 @@ func ProcessDecode(data *byteframe.ByteFrame, outBuffer []byte) {
|
||||
}
|
||||
}
|
||||
|
||||
// JPKBitShift reads one bit from the compressed stream's flag byte, refilling
|
||||
// the flag from the next byte in data when all 8 bits have been consumed.
|
||||
func JPKBitShift(data *byteframe.ByteFrame) byte {
|
||||
mShiftIndex--
|
||||
|
||||
@@ -96,6 +102,8 @@ func JPKBitShift(data *byteframe.ByteFrame) byte {
|
||||
return (byte)((mFlag >> mShiftIndex) & 1)
|
||||
}
|
||||
|
||||
// JPKCopy copies length bytes from a previous position in outBuffer (determined
|
||||
// by offset back from the current index) to implement LZ back-references.
|
||||
func JPKCopy(outBuffer []byte, offset int, length int, index *int) {
|
||||
for i := 0; i < length; i++ {
|
||||
outBuffer[*index] = outBuffer[*index-offset-1]
|
||||
@@ -103,6 +111,7 @@ func JPKCopy(outBuffer []byte, offset int, length int, index *int) {
|
||||
}
|
||||
}
|
||||
|
||||
// ReadByte reads a single byte from the ByteFrame.
|
||||
func ReadByte(bf *byteframe.ByteFrame) byte {
|
||||
value := bf.ReadUint8()
|
||||
return value
|
||||
|
||||
4
common/gametime/doc.go
Normal file
4
common/gametime/doc.go
Normal file
@@ -0,0 +1,4 @@
|
||||
// Package gametime provides time helpers anchored to the JST (UTC+9) timezone
|
||||
// used by Monster Hunter Frontier's game clock, including weekly reset
|
||||
// boundaries and the in-game absolute time cycle.
|
||||
package gametime
|
||||
@@ -4,16 +4,19 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Adjusted returns the current time in JST (UTC+9), the timezone used by MHF.
|
||||
func Adjusted() time.Time {
|
||||
baseTime := time.Now().In(time.FixedZone("UTC+9", 9*60*60))
|
||||
return time.Date(baseTime.Year(), baseTime.Month(), baseTime.Day(), baseTime.Hour(), baseTime.Minute(), baseTime.Second(), baseTime.Nanosecond(), baseTime.Location())
|
||||
}
|
||||
|
||||
// Midnight returns today's midnight (00:00) in JST.
|
||||
func Midnight() time.Time {
|
||||
baseTime := time.Now().In(time.FixedZone("UTC+9", 9*60*60))
|
||||
return time.Date(baseTime.Year(), baseTime.Month(), baseTime.Day(), 0, 0, 0, 0, baseTime.Location())
|
||||
}
|
||||
|
||||
// WeekStart returns the most recent Monday at midnight in JST.
|
||||
func WeekStart() time.Time {
|
||||
midnight := Midnight()
|
||||
offset := int(midnight.Weekday()) - int(time.Monday)
|
||||
@@ -23,10 +26,13 @@ func WeekStart() time.Time {
|
||||
return midnight.Add(-time.Duration(offset) * 24 * time.Hour)
|
||||
}
|
||||
|
||||
// WeekNext returns the next Monday at midnight in JST.
|
||||
func WeekNext() time.Time {
|
||||
return WeekStart().Add(time.Hour * 24 * 7)
|
||||
}
|
||||
|
||||
// GameAbsolute returns the current position within the 5760-second (96-minute)
|
||||
// in-game day/night cycle, offset by 2160 seconds.
|
||||
func GameAbsolute() uint32 {
|
||||
return uint32((Adjusted().Unix() - 2160) % 5760)
|
||||
}
|
||||
|
||||
3
common/mhfcid/doc.go
Normal file
3
common/mhfcid/doc.go
Normal file
@@ -0,0 +1,3 @@
|
||||
// Package mhfcid converts MHF Character ID strings (a base-32 encoding that
|
||||
// omits the ambiguous characters 0, I, O, and S) to their numeric equivalents.
|
||||
package mhfcid
|
||||
5
common/mhfcourse/doc.go
Normal file
5
common/mhfcourse/doc.go
Normal file
@@ -0,0 +1,5 @@
|
||||
// Package mhfcourse models the subscription course system used by Monster
|
||||
// Hunter Frontier. Courses (Trial, HunterLife, Extra, Premium, etc.) are
|
||||
// represented as bit flags in a uint32 rights field and control which game
|
||||
// features a player can access.
|
||||
package mhfcourse
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Course represents an active subscription course with its ID and expiry time.
|
||||
type Course struct {
|
||||
ID uint16
|
||||
Expiry time.Time
|
||||
@@ -39,10 +40,12 @@ var aliases = map[uint16][]string{
|
||||
// 30 = Real NetCafe course
|
||||
}
|
||||
|
||||
// Aliases returns the human-readable names for this course (e.g. "HunterLife", "HL").
|
||||
func (c Course) Aliases() []string {
|
||||
return aliases[c.ID]
|
||||
}
|
||||
|
||||
// Courses returns all 32 possible course slots with zero-value expiry times.
|
||||
func Courses() []Course {
|
||||
courses := make([]Course, 32)
|
||||
for i := range courses {
|
||||
@@ -51,6 +54,7 @@ func Courses() []Course {
|
||||
return courses
|
||||
}
|
||||
|
||||
// Value returns the bitmask value for this course (2^ID).
|
||||
func (c Course) Value() uint32 {
|
||||
return uint32(math.Pow(2, float64(c.ID)))
|
||||
}
|
||||
|
||||
4
common/mhfitem/doc.go
Normal file
4
common/mhfitem/doc.go
Normal file
@@ -0,0 +1,4 @@
|
||||
// Package mhfitem defines item, equipment, and sigil data structures as they
|
||||
// appear in the MHF binary protocol, and provides serialization helpers for
|
||||
// warehouse (box/storage) operations.
|
||||
package mhfitem
|
||||
@@ -6,15 +6,18 @@ import (
|
||||
_config "erupe-ce/config"
|
||||
)
|
||||
|
||||
// MHFItem represents a single item identified by its in-game item ID.
|
||||
type MHFItem struct {
|
||||
ItemID uint16
|
||||
}
|
||||
|
||||
// MHFSigilEffect represents a single effect slot on a sigil with an ID and level.
|
||||
type MHFSigilEffect struct {
|
||||
ID uint16
|
||||
Level uint16
|
||||
}
|
||||
|
||||
// MHFSigil represents a weapon sigil containing up to three effects.
|
||||
type MHFSigil struct {
|
||||
Effects []MHFSigilEffect
|
||||
Unk0 uint8
|
||||
@@ -23,6 +26,8 @@ type MHFSigil struct {
|
||||
Unk3 uint8
|
||||
}
|
||||
|
||||
// MHFEquipment represents an equipment piece (weapon or armor) with its
|
||||
// decorations and sigils as stored in the player's warehouse.
|
||||
type MHFEquipment struct {
|
||||
WarehouseID uint32
|
||||
ItemType uint8
|
||||
@@ -34,6 +39,7 @@ type MHFEquipment struct {
|
||||
Unk1 uint16
|
||||
}
|
||||
|
||||
// MHFItemStack represents a stacked item slot in the warehouse with a quantity.
|
||||
type MHFItemStack struct {
|
||||
WarehouseID uint32
|
||||
Item MHFItem
|
||||
@@ -41,6 +47,8 @@ type MHFItemStack struct {
|
||||
Unk0 uint32
|
||||
}
|
||||
|
||||
// ReadWarehouseItem deserializes an MHFItemStack from a ByteFrame, assigning a
|
||||
// random warehouse ID if the encoded ID is zero.
|
||||
func ReadWarehouseItem(bf *byteframe.ByteFrame) MHFItemStack {
|
||||
var item MHFItemStack
|
||||
item.WarehouseID = bf.ReadUint32()
|
||||
@@ -53,6 +61,9 @@ func ReadWarehouseItem(bf *byteframe.ByteFrame) MHFItemStack {
|
||||
return item
|
||||
}
|
||||
|
||||
// DiffItemStacks merges an updated item stack list into an existing one,
|
||||
// matching by warehouse ID. New items receive a random ID; items with zero
|
||||
// quantity in the old list are removed.
|
||||
func DiffItemStacks(o []MHFItemStack, u []MHFItemStack) []MHFItemStack {
|
||||
// o = old, u = update, f = final
|
||||
var f []MHFItemStack
|
||||
@@ -77,6 +88,7 @@ func DiffItemStacks(o []MHFItemStack, u []MHFItemStack) []MHFItemStack {
|
||||
return f
|
||||
}
|
||||
|
||||
// ToBytes serializes the item stack to its binary protocol representation.
|
||||
func (is MHFItemStack) ToBytes() []byte {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(is.WarehouseID)
|
||||
@@ -86,6 +98,8 @@ func (is MHFItemStack) ToBytes() []byte {
|
||||
return bf.Data()
|
||||
}
|
||||
|
||||
// SerializeWarehouseItems serializes a slice of item stacks with a uint16
|
||||
// count header for transmission in warehouse response packets.
|
||||
func SerializeWarehouseItems(i []MHFItemStack) []byte {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint16(uint16(len(i)))
|
||||
@@ -96,6 +110,9 @@ func SerializeWarehouseItems(i []MHFItemStack) []byte {
|
||||
return bf.Data()
|
||||
}
|
||||
|
||||
// ReadWarehouseEquipment deserializes an MHFEquipment from a ByteFrame. The
|
||||
// binary layout varies by game version: sigils are present from G1 onward and
|
||||
// an additional field is present from Z1 onward.
|
||||
func ReadWarehouseEquipment(bf *byteframe.ByteFrame) MHFEquipment {
|
||||
var equipment MHFEquipment
|
||||
equipment.Decorations = make([]MHFItem, 3)
|
||||
@@ -134,6 +151,7 @@ func ReadWarehouseEquipment(bf *byteframe.ByteFrame) MHFEquipment {
|
||||
return equipment
|
||||
}
|
||||
|
||||
// ToBytes serializes the equipment to its binary protocol representation.
|
||||
func (e MHFEquipment) ToBytes() []byte {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint32(e.WarehouseID)
|
||||
@@ -164,6 +182,8 @@ func (e MHFEquipment) ToBytes() []byte {
|
||||
return bf.Data()
|
||||
}
|
||||
|
||||
// SerializeWarehouseEquipment serializes a slice of equipment with a uint16
|
||||
// count header for transmission in warehouse response packets.
|
||||
func SerializeWarehouseEquipment(i []MHFEquipment) []byte {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint16(uint16(len(i)))
|
||||
|
||||
4
common/mhfmon/doc.go
Normal file
4
common/mhfmon/doc.go
Normal file
@@ -0,0 +1,4 @@
|
||||
// Package mhfmon enumerates every monster in Monster Hunter Frontier by its
|
||||
// internal enemy ID (em001–em176) and provides metadata such as display name
|
||||
// and large/small classification.
|
||||
package mhfmon
|
||||
@@ -180,11 +180,13 @@ const (
|
||||
KingShakalaka
|
||||
)
|
||||
|
||||
// Monster holds display metadata for a single monster species.
|
||||
type Monster struct {
|
||||
Name string
|
||||
Large bool
|
||||
}
|
||||
|
||||
// Monsters is an ordered table of all MHF monsters, indexed by enemy ID.
|
||||
var Monsters = []Monster{
|
||||
{"Mon0", false},
|
||||
{"Rathian", true},
|
||||
|
||||
4
common/pascalstring/doc.go
Normal file
4
common/pascalstring/doc.go
Normal file
@@ -0,0 +1,4 @@
|
||||
// Package pascalstring writes length-prefixed, null-terminated strings into a
|
||||
// ByteFrame. The prefix width is selectable (uint8, uint16, or uint32) and
|
||||
// strings are optionally encoded to Shift-JIS before writing.
|
||||
package pascalstring
|
||||
@@ -6,6 +6,8 @@ import (
|
||||
"golang.org/x/text/transform"
|
||||
)
|
||||
|
||||
// Uint8 writes x as a null-terminated string with a uint8 length prefix. If t
|
||||
// is true the string is first encoded to Shift-JIS.
|
||||
func Uint8(bf *byteframe.ByteFrame, x string, t bool) {
|
||||
if t {
|
||||
e := japanese.ShiftJIS.NewEncoder()
|
||||
@@ -20,6 +22,8 @@ func Uint8(bf *byteframe.ByteFrame, x string, t bool) {
|
||||
bf.WriteNullTerminatedBytes([]byte(x))
|
||||
}
|
||||
|
||||
// Uint16 writes x as a null-terminated string with a uint16 length prefix. If
|
||||
// t is true the string is first encoded to Shift-JIS.
|
||||
func Uint16(bf *byteframe.ByteFrame, x string, t bool) {
|
||||
if t {
|
||||
e := japanese.ShiftJIS.NewEncoder()
|
||||
@@ -34,6 +38,8 @@ func Uint16(bf *byteframe.ByteFrame, x string, t bool) {
|
||||
bf.WriteNullTerminatedBytes([]byte(x))
|
||||
}
|
||||
|
||||
// Uint32 writes x as a null-terminated string with a uint32 length prefix. If
|
||||
// t is true the string is first encoded to Shift-JIS.
|
||||
func Uint32(bf *byteframe.ByteFrame, x string, t bool) {
|
||||
if t {
|
||||
e := japanese.ShiftJIS.NewEncoder()
|
||||
|
||||
3
common/stringstack/doc.go
Normal file
3
common/stringstack/doc.go
Normal file
@@ -0,0 +1,3 @@
|
||||
// Package stringstack provides a minimal LIFO stack for strings, used
|
||||
// internally to track hierarchical state such as nested stage paths.
|
||||
package stringstack
|
||||
5
common/stringsupport/doc.go
Normal file
5
common/stringsupport/doc.go
Normal file
@@ -0,0 +1,5 @@
|
||||
// Package stringsupport provides string conversion utilities for the MHF
|
||||
// protocol, including UTF-8 ↔ Shift-JIS transcoding, padded fixed-width
|
||||
// string encoding, NG-word conversion, and comma-separated integer list
|
||||
// manipulation used for database storage.
|
||||
package stringsupport
|
||||
@@ -11,6 +11,8 @@ import (
|
||||
"golang.org/x/text/transform"
|
||||
)
|
||||
|
||||
// UTF8ToSJIS encodes a UTF-8 string to Shift-JIS bytes, silently dropping any
|
||||
// runes that cannot be represented in Shift-JIS.
|
||||
func UTF8ToSJIS(x string) []byte {
|
||||
e := japanese.ShiftJIS.NewEncoder()
|
||||
xt, _, err := transform.String(e, x)
|
||||
@@ -28,6 +30,7 @@ func UTF8ToSJIS(x string) []byte {
|
||||
return []byte(xt)
|
||||
}
|
||||
|
||||
// SJISToUTF8 decodes Shift-JIS bytes to a UTF-8 string.
|
||||
func SJISToUTF8(b []byte) string {
|
||||
d := japanese.ShiftJIS.NewDecoder()
|
||||
result, err := io.ReadAll(transform.NewReader(bytes.NewReader(b), d))
|
||||
@@ -37,6 +40,8 @@ func SJISToUTF8(b []byte) string {
|
||||
return string(result)
|
||||
}
|
||||
|
||||
// ToNGWord converts a UTF-8 string into a slice of uint16 values in the
|
||||
// Shift-JIS byte-swapped format used by the MHF NG-word (chat filter) system.
|
||||
func ToNGWord(x string) []uint16 {
|
||||
var w []uint16
|
||||
for _, r := range x {
|
||||
@@ -55,6 +60,8 @@ func ToNGWord(x string) []uint16 {
|
||||
return w
|
||||
}
|
||||
|
||||
// PaddedString returns a fixed-width null-terminated byte slice of the given
|
||||
// size. If t is true the string is first encoded to Shift-JIS.
|
||||
func PaddedString(x string, size uint, t bool) []byte {
|
||||
if t {
|
||||
e := japanese.ShiftJIS.NewEncoder()
|
||||
@@ -70,6 +77,7 @@ func PaddedString(x string, size uint, t bool) []byte {
|
||||
return out
|
||||
}
|
||||
|
||||
// CSVAdd appends v to the comma-separated integer list if not already present.
|
||||
func CSVAdd(csv string, v int) string {
|
||||
if len(csv) == 0 {
|
||||
return strconv.Itoa(v)
|
||||
@@ -81,6 +89,7 @@ func CSVAdd(csv string, v int) string {
|
||||
}
|
||||
}
|
||||
|
||||
// CSVRemove removes v from the comma-separated integer list.
|
||||
func CSVRemove(csv string, v int) string {
|
||||
s := strings.Split(csv, ",")
|
||||
for i, e := range s {
|
||||
@@ -92,6 +101,7 @@ func CSVRemove(csv string, v int) string {
|
||||
return strings.Join(s, ",")
|
||||
}
|
||||
|
||||
// CSVContains reports whether v is present in the comma-separated integer list.
|
||||
func CSVContains(csv string, v int) bool {
|
||||
s := strings.Split(csv, ",")
|
||||
for i := 0; i < len(s); i++ {
|
||||
@@ -103,6 +113,7 @@ func CSVContains(csv string, v int) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// CSVLength returns the number of elements in the comma-separated list.
|
||||
func CSVLength(csv string) int {
|
||||
if csv == "" {
|
||||
return 0
|
||||
@@ -111,6 +122,7 @@ func CSVLength(csv string) int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
// CSVElems parses the comma-separated integer list into an int slice.
|
||||
func CSVElems(csv string) []int {
|
||||
var r []int
|
||||
if csv == "" {
|
||||
@@ -124,6 +136,8 @@ func CSVElems(csv string) []int {
|
||||
return r
|
||||
}
|
||||
|
||||
// CSVGetIndex returns the integer at position i in the comma-separated list,
|
||||
// or 0 if i is out of range.
|
||||
func CSVGetIndex(csv string, i int) int {
|
||||
s := CSVElems(csv)
|
||||
if i < len(s) {
|
||||
@@ -132,6 +146,8 @@ func CSVGetIndex(csv string, i int) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// CSVSetIndex replaces the integer at position i in the comma-separated list
|
||||
// with v. If i is out of range the list is returned unchanged.
|
||||
func CSVSetIndex(csv string, i int, v int) string {
|
||||
s := CSVElems(csv)
|
||||
if i < len(s) {
|
||||
|
||||
3
common/token/doc.go
Normal file
3
common/token/doc.go
Normal file
@@ -0,0 +1,3 @@
|
||||
// Package token provides concurrency-safe random number generation and
|
||||
// alphanumeric token generation for session tokens and warehouse IDs.
|
||||
package token
|
||||
@@ -12,12 +12,15 @@ type SafeRand struct {
|
||||
rng *rand.Rand
|
||||
}
|
||||
|
||||
// NewSafeRand creates a SafeRand seeded with the current time.
|
||||
func NewSafeRand() *SafeRand {
|
||||
return &SafeRand{
|
||||
rng: rand.New(rand.NewSource(time.Now().UnixNano())),
|
||||
}
|
||||
}
|
||||
|
||||
// Intn returns a non-negative pseudo-random int in [0,n). It is safe for
|
||||
// concurrent use.
|
||||
func (sr *SafeRand) Intn(n int) int {
|
||||
sr.mu.Lock()
|
||||
v := sr.rng.Intn(n)
|
||||
@@ -25,6 +28,7 @@ func (sr *SafeRand) Intn(n int) int {
|
||||
return v
|
||||
}
|
||||
|
||||
// Uint32 returns a pseudo-random uint32. It is safe for concurrent use.
|
||||
func (sr *SafeRand) Uint32() uint32 {
|
||||
sr.mu.Lock()
|
||||
v := sr.rng.Uint32()
|
||||
@@ -32,6 +36,8 @@ func (sr *SafeRand) Uint32() uint32 {
|
||||
return v
|
||||
}
|
||||
|
||||
// RNG is the global concurrency-safe random number generator used throughout
|
||||
// the server for generating warehouse IDs, session tokens, and other values.
|
||||
var RNG = NewSafeRand()
|
||||
|
||||
// Generate returns an alphanumeric token of specified length
|
||||
|
||||
Reference in New Issue
Block a user