Add guards for edge cases:
- Empty entries with rolls > 0
- Zero or negative rolls
- Zero total weight in non-box mode
- Box mode with more rolls than available entries
Previously these cases caused infinite loops or panics.
Add comprehensive tests for pure logic functions:
- GuildMember.CanRecruit() and IsSubLeader() methods
- getRandomEntries() for gacha weighted/box selection
All targeted functions now have 100% coverage.
- Add multi-stage build to Dockerfile for smaller production image
- Move docker-compose.yml to project root for easier usage
- Flatten docker/init/setup.sh to docker/setup.sh
- Expand .dockerignore to exclude unnecessary files
- Remove deprecated version field from compose files
Add GitHub Actions workflow that triggers on version tags (v*) to
automatically build release artifacts and create GitHub releases.
- Build matrix for Linux and Windows (amd64)
- Create proper archives (.tar.gz and .zip)
- Inject version via ldflags at build time
- Extract release notes from CHANGELOG.md
- Detect pre-release tags (-alpha, -beta, -rc)
- Add Version variable to main.go for runtime version display
- Add network/packetid_test.go with tests for PacketID type, constants,
String() method, ranges, uniqueness, and sequential verification
- Add network/mhfpacket/msg_sys_core_test.go with round-trip tests for
MsgSysAck (including large payloads), MsgSysNop, and MsgSysEnd
- Expand common/stringstack/stringstack_test.go with Lock/Unlock tests
achieving 100% coverage
Cherry-picked from main (7d760bd) with conflict resolution.
Uses the last entry in ClanMemberLimits config array to determine
the maximum clan member count sent to clients.
Cherry-picked from main (8c219be) with conflict resolution.
Pre-G10 clients don't have the GR field in the applicant list,
so only write it when RealClientMode >= G10.
Also optimizes two consecutive uint16(0) writes to single uint32(0).
Add client version mode support to enable version-specific behavior:
- Add Mode type with constants for all game versions (S1.0 through ZZ)
- Add ClientMode (string) and RealClientMode (Mode) to Config
- Add ClanMemberLimits to GameplayOptions for configurable clan sizes
- Add MaximumFP to GameplayOptions for festa points cap
- Parse ClientMode string to RealClientMode enum in LoadConfig
- Set sensible defaults (ZZ for mode, standard limits for clans)
- Update config.example.json with new fields
This enables cherry-picking version-specific fixes from main branch.
Cherry-picked from main (5028355) with conflict resolution.
Changes condition from && to || to properly handle the case where
a player has a guild but also has a prevGuildID set.
Cherry-picked from main (c539905).
Prevents infinite loop when stage binary data never arrives by
limiting to 10 iterations (10 seconds) before returning empty response.
Cherry-picked from main (7459ded) with conflict resolution.
The original fix changed the poogie outfit unlock from incorrect
math.Pow calculation to direct value assignment.
Also removes unused math import (531b3d2).
Add comprehensive tests documenting current behavior before applying
fixes from main branch. Tests cover:
- Cafe item PointCost parsing (uint32 vs uint16 for different client modes)
- Guild poogie outfit unlock calculation bug (math.Pow issue)
- Guild manage right nil pointer condition (&& vs || logic)
- InfoGuild applicant GR field size for <G10 clients
- Stage binary wait infinite loop risk (no timeout)
- Entrance server hardcoded clan member limit
- Renamed config key from GuildMealDuration to ClanMealDuration
- Changed unit from minutes to seconds (matching upstream convention)
- Updated handler to use seconds-based calculation
- Updated documentation and examples
This fixes the bug where clan meals were not being shared between
guild members when using a config.json with the upstream naming.
Distributions now read items from the distribution_items table instead of
requiring a pre-built binary data blob. This enables creating distributions
via simple SQL inserts rather than generating binary data manually.
Changes:
- Add getDistributionItems() to fetch items from distribution_items table
- Update handleMsgMhfApplyDistItem to build response from table data
- Move server-side rewards (points, RP) to handleMsgMhfAcquireDistItem
- Support G8+ item format (13 bytes per item)