Commit Graph

1564 Commits

Author SHA1 Message Date
Houmgaor
ba7ec122f8 revert: remove SQLite support
An MMO server without multiplayer defeats the purpose. PostgreSQL
is the right choice and Docker Compose already solves the setup
pain. This reverts the common/db wrapper, SQLite schema, config
Driver field, modernc.org/sqlite dependency, and all repo type
changes while keeping the dashboard, wizard, and CI improvements
from the previous commit.
2026-03-05 23:05:55 +01:00
Houmgaor
ecfe58ffb4 feat: add SQLite support, setup wizard enhancements, and live dashboard
Add zero-dependency SQLite mode so users can run Erupe without
PostgreSQL. A transparent db.DB wrapper auto-translates PostgreSQL
SQL ($N placeholders, now(), ::casts, ILIKE, public. prefix,
TRUNCATE) for SQLite at runtime — all 28 repo files use the wrapper
with no per-query changes needed.

Setup wizard gains two new steps: quest file detection with download
link, and gameplay presets (solo/small/community/rebalanced). The API
server gets a /dashboard endpoint with auto-refreshing stats.

CI release workflow now builds and pushes Docker images to GHCR
alongside binary artifacts on tag push.

Key changes:
- common/db: DB/Tx wrapper with 6 SQL translation rules
- server/migrations/sqlite: full SQLite schema (0001-0005)
- config: Database.Driver field ("postgres" or "sqlite")
- main.go: SQLite connection with WAL mode, single writer
- server/setup: quest check + preset selection steps
- server/api: /dashboard with live stats
- .github/workflows: Docker in release, deduplicate docker.yml
2026-03-05 18:00:30 +01:00
Houmgaor
03adb21e99 fix(channelserver): post-RC1 stabilization sprint
Fix rasta_id=0 overwriting NULL in SaveMercenary, which prevented
game state saving for characters without a mercenary (#163).

Also includes:
- CHANGELOG updated with all 10 post-RC1 commits
- Setup wizard fmt.Printf replaced with zap structured logging
- technical-debt.md updated with 6 newly completed items
- Scenario binary format documented (docs/scenario-format.md)
- Tests: alliance nil-guard (#171), handler dispatch table,
  migrations (sorted/SQL/baseline), setup wizard (10 tests),
  protbot protocol sign/entrance/channel (23 tests)
2026-03-05 16:39:15 +01:00
Houmgaor
10ac803a45 fix(channelserver): correct ecdMagic constant byte order (#174)
The constant used file-order bytes (0x6563641a) instead of the value
produced by binary.LittleEndian.Uint32 (0x1A646365), causing
loadRengokuBinary to reject every real ECD-encrypted rengoku_data.bin.
The unit tests masked this because they round-tripped with the same
wrong constant.
2026-03-03 18:23:45 +01:00
Houmgaor
8717fb9b55 fix(guild): add nil guards in cancel and answer scout handlers
GetByID returns (nil, nil) for deleted guilds, and AnswerScout can
return nil result on ErrApplicationMissing, both leading to nil
dereferences.
2026-03-03 18:04:33 +01:00
Houmgaor
8e79fe6834 fix(guild): fix variable shadowing causing nil panic in scout list (#171)
The else branch redeclared guildInfo with := scoping it to the block,
so the outer guildInfo remained nil when reaching ListInvitedCharacters.
Restructure the conditional to assign to the existing variable instead.
2026-03-03 18:01:20 +01:00
Houmgaor
5b631d1704 perf(channelserver): cache rengoku_data.bin at startup
Load and validate rengoku_data.bin once during server initialization
instead of reading it from disk on every client request. The file is
static ECD-encrypted config data (~4.9 KB) that never changes at
runtime. Validation checks file size and ECD magic bytes, logging a
warning if the file is missing or invalid so misconfiguration is
caught before any client connects.
2026-03-02 20:12:39 +01:00
Houmgaor
aee53534a2 fix(guild): add nil guards for alliance guild lookups (#171)
scanAllianceWithGuilds dereferences guild pointers returned by GetByID
without checking for nil. Since GetByID returns (nil, nil) when a guild
is missing, alliances referencing deleted guilds cause nil-pointer
panics. The panic is caught by session recovery but no ACK is sent,
softlocking the client.

Add nil checks in scanAllianceWithGuilds, handleMsgMhfOperateJoint,
handleMsgMhfInfoJoint, and handleMsgMhfInfoGuild so that missing
guilds or alliances produce proper error responses instead of panics.
2026-03-02 19:43:11 +01:00
Houmgaor
07a587213d fix(channelserver): remove false race in PacketDuringLogout test
The test ran handleMsgMhfSavedata and logoutPlayer concurrently on the
same session, triggering data races on s.playtime and Save(). In
production the dispatch loop processes packets sequentially per session,
so this overlap is impossible. Run the operations sequentially to match
real behavior while still validating no data loss.
2026-03-01 18:56:52 +01:00
Houmgaor
6143902f39 test(channelserver): add tests for logoutPlayer, saveAllCharacterData, and transit message
Cover the two most complex untested handlers in handlers_session.go:

- logoutPlayer (8 tests): basic logout, character save path, cafe course
  RP accrual, stage cleanup, host disconnect with MsgSysStageDestruct,
  error resilience for ReadInt/LoadSaveData failures, concurrent logout
- saveAllCharacterData (4 tests): nil save data, load error propagation,
  RP capping logic, playtime accumulation
- handleMsgMhfTransitMessage (6 tests): search by charID (found/not
  found), search by name, search by lobby (IP+port+stageID), party
  finder with stage prefix and rank filtering, localhost IP rewrite
2026-03-01 18:41:59 +01:00
Houmgaor
9da3af6087 Merge pull request #170 from sasospanner/patch-1
Update go.mod
2026-02-28 21:55:54 +01:00
sasospanner
611425da1c Update go.mod
added minor version otherwise go would throw an error similar to
go: download go1.25 for linux/amd64: toolchain not available
2026-02-28 13:45:29 -05:00
Houmgaor
9a5a8dfb36 fix(migrations): add IF NOT EXISTS guard to alliance recruiting column
Without this guard, migration 0004 fails on databases where the column
already exists, such as during the existing-DB-without-schema-version
upgrade path where 0001 baseline is auto-marked and 0002-0005 re-applied.
2026-02-28 19:26:21 +01:00
Houmgaor
5106b905de docs: update changelog for v9.3.0-rc1 release
Backfill key changes from 900 commits since 9.2.0 including
architecture rewrite, game system overhauls, client version
support, and developer tooling. Tag Unreleased as 9.3.0-rc1.
2026-02-28 19:18:11 +01:00
Houmgaor
bb16306f91 test(migrations): update expected counts after adding migrations 0004-0005
Test assertions were still expecting 3 total migrations from when only
0001-0003 existed. Updated to reflect 5 migrations (0001-0005).
v9.3.0-rc1
2026-02-28 18:02:36 +01:00
Houmgaor
fa09e4a39c fix(migrations): drop unused data column from distribution table (#169)
The distribution table had a `data bytea NOT NULL` column that was never
read by the Go code — item data is stored in distribution_items instead.
The NOT NULL constraint forced dummy values in seed data and test inserts.

Remove the column from the baseline schema, seed data, and tests, and
add migration 0005 to drop it from existing databases.
2026-02-27 18:19:57 +01:00
Houmgaor
21f9a79b62 fix(channelserver): correct session handler retail mismatches (#167)
Lobby search now returns only quest-bound players (QuestReserved) instead
of all reserved slots, matching retail behavior. The new field is
pre-collected under server lock before stage iteration to respect
Server.Mutex → Stage.RWMutex lock ordering.

Replaced three TODOs with RE documentation from Ghidra decompilation of
mhfo-hd.dll ZZ:
- Log key off-by-one: putRecord_log/putTerminal_log pass size 0 for the
  key field in ZZ, so the stored key is unused beyond issuance
- User search padding: ZZ per-entry parser confirms 40-byte block via
  memcpy(dst, src+8, 0x28); G2 DLL analysis inconclusive (stripped)
- Player count: field at entry offset 0x08 maps to struct param_1[0xe]
2026-02-27 17:29:32 +01:00
Houmgaor
649eebe67c docs: log bookshelf data pointer fix in changelog and technical debt tracker 2026-02-27 16:53:35 +01:00
Houmgaor
4c47c8e18f fix(channelserver): correct bookshelf save data pointers for non-ZZ (#164)
The pBookshelfData offsets for G1-Z2, F4-F5, and S6 were off by -14810,
placing bookshelf before houseData in the save blob and reading garbage.
All other 12 save fields have consistent inter-version deltas (36000,
32000, 48000); only bookshelf broke the pattern. Correcting by +14810
restores the gallery-bookshelf gap to 136 bytes (matching ZZ) and aligns
all field deltas across versions.

Supersedes Mezeporta/Erupe#155 (same fix, merge conflict on renamed file).
2026-02-27 16:46:32 +01:00
Houmgaor
7911d84d48 docs: log alliance application toggle fix in changelog 2026-02-27 15:02:30 +01:00
Houmgaor
d6938f2a27 fix(guild): implement alliance application toggle (#166)
Alliance applications were hardcoded to always-open. Add a `recruiting`
column to guild_alliances and handle OperateJoint actions 0x06 (Allow)
and 0x07 (Deny) confirmed via Wii U debug symbols. Only the parent
guild leader can toggle the setting, matching the existing disband guard.
2026-02-27 14:59:18 +01:00
Houmgaor
fba8c2413c docs: link remaining TODOs to GitHub issues in technical debt tracker
Filed #164-#168 for all 8 remaining TODOs. Added Tracker column
with issue links, fixed stale line numbers, added MhfAddUdPoint
stub entry, and expanded the suggested execution order.
2026-02-27 13:46:12 +01:00
Houmgaor
7f5d30e2f5 fix: resolve code scanning findings in commands and wizard
Add bounds check (0 to MaxUint32) before casting strconv.Atoi result
to uint32 in the rights command handler. Replace manual allowlist
validation with pq.QuoteIdentifier for CREATE DATABASE to eliminate
the SQL injection finding.
2026-02-27 13:45:56 +01:00
Houmgaor
7e24bbc087 ci: serialize test packages to fix shared database race condition
The migrations and channelserver packages both DROP and recreate the
public schema on the shared erupe_test database. With parallel package
execution, they destroy each other's schema mid-migration. Adding -p 1
serializes package execution while preserving t.Parallel() within each
package.
2026-02-27 13:28:45 +01:00
Houmgaor
31266fcb21 test(entranceserver): push coverage from 56.1% to 82.2%
Add 18 tests covering makeSv2Resp (ZZ, G3.2/SVR, MezFes/Return
filtering, debug logging), encodeServerInfo branches (non-local IP,
empty IP fallback, GG/G1-G5 client modes, ProxyPort, type filtering),
makeUsrResp debug logging, sanitizeAddr, and startEntranceCapture
(disabled, entrance-disabled, enabled, default output dir).
2026-02-27 13:19:33 +01:00
Houmgaor
35d920f5da docs: mark repo test coverage as complete in technical debt tracker
The 17 previously-untested repo files all have test files now.
2026-02-27 13:12:43 +01:00
Houmgaor
156b5c53f7 test(signserver): push coverage from 62.9% to 70.3%
Add handlePacket dispatch tests for all switch cases (DSGN, SIGN,
DLTSKEYSIGN, PS4SGN, PS3SGN, VITASGN, WIIUSGN, COGLNK, VITACOGLNK,
DELETE). Add makeSignResponse branch tests covering PSN client PSNID
field, CapLink key/host paths, MezFes minigame switch, non-localhost
remote addr, and PSN token registration. Add startSignCapture
enabled-path tests with temp dir and default output dir.
2026-02-27 13:07:12 +01:00
Houmgaor
3ad2836088 feat(api): add DELETE /v2/characters/{id} route, v2 test coverage, and OpenAPI spec
Add REST-idiomatic DELETE method as alias for POST .../delete.
Add 8 router-level tests exercising Bearer auth, invalid tokens,
soft delete, export body decoding, and MaxLauncherHR capping.
Create OpenAPI 3.1.0 specification covering all v2 endpoints.
2026-02-27 12:58:31 +01:00
Houmgaor
bcfdf48dad test(signserver): add session handler and utility coverage tests
Cover all previously-untested session handlers (authenticate,
handleDSGN, handleWIIUSGN, handlePSSGN, handlePSNLink, sendCode)
plus validateLogin ban/bcrypt paths, registerPsnToken, and
sanitizeAddr/startSignCapture. Uses a spyConn implementing
network.Conn to capture plaintext packets for assertion.

Raises signserver coverage from 46% to 63%.
2026-02-27 12:54:13 +01:00
Houmgaor
7ff26f4980 feat(api): add v2 routes, auth middleware, structured errors, and server status endpoint
Introduces incremental API improvements for custom launcher support
(mhf-iel, stratic-dev's Rust launcher):

- Standardize all error responses to JSON envelopes with error/message
- Add Bearer token auth middleware for v2 routes (legacy body-token preserved)
- Add `returning` (>90d inactive) and `courses` fields to auth response
- Add /v2/ route prefix with HTTP method enforcement
- Add GET /v2/server/status for MezFes, featured weapon, and event status
- Add APIEventRepo for read-only event data access

Closes #44
2026-02-27 12:46:23 +01:00
Houmgaor
9f43940a44 docs: add pre-commit checks section to CLAUDE.md
Enforce gofmt and golangci-lint before every commit to catch
formatting and lint issues locally instead of waiting for CI.
2026-02-27 12:37:48 +01:00
Houmgaor
d38fef08bb refactor(discordbot): introduce Session interface for testability
Extract a Session interface from *discordgo.Session so DiscordBot methods
can be tested with a mock — no live Discord connection required. Add
AddHandler, RegisterCommands, and UserID methods to DiscordBot so
external callers (main.go, sys_channel_server.go) no longer reach
through bot.Session directly. Rewrite tests with a mockSession,
raising discordbot coverage from 12.5% to 66.7%.
2026-02-27 11:45:20 +01:00
Houmgaor
4e8c4b4e92 fix(channelserver): handle silently discarded errors across handlers
Replace ~17 instances of '_ =' / '_ :=' with proper error checks that
log warnings or send fail ACKs. Affected handlers: cafe, distitem, data,
guild, guild_board, guild_cooking, guild_scout, house, mercenary, misc,
and rengoku. Also resolves all pre-existing lint issues: unchecked
bf.Seek in tests, unused filtered slice in svc_festa, unused mock
fields, and unused signserver test helper.
2026-02-27 11:33:25 +01:00
Houmgaor
4b24489ebe test(channelserver): add handler coverage tests for scout, house, items, rengoku, tower 2026-02-27 11:33:13 +01:00
Houmgaor
74798fc8b3 fix(channelserver): return error from Save() to prevent misleading success logs
CharacterSaveData.Save() silently returned on failure (nil decompressed
data, compression error, DB error) while the caller unconditionally
logged "Saved character data successfully". This made diagnosing save
failures difficult (ref #163).

Save() now returns an error, and all six call sites check it. The
success log in saveAllCharacterData only fires when the save actually
persisted.
2026-02-27 11:21:37 +01:00
Houmgaor
178a008e25 fix(shop): write gacha header for G1+ clients, not just GG+
The G1 client binary expects 8 uint32 fields (ID, rank restrictions,
MinGR, MinHR) before the name string in the gacha listing response.
PR #150 only wrote these for GG+, causing G1–G32 clients to misparse
the stream. Verified against Wii U G1 RPX decompilation of
import_gacha_list at 0x02C594FC.
2026-02-26 23:53:35 +01:00
Houmgaor
d0837e779c refactor(channelserver): consolidate tests into matching source test files
Move ~300 test functions from 21 catch-all files (handlers_core_test.go,
handlers_coverage*_test.go, *_coverage_test.go) into the *_test.go file
matching each handler's source file. This makes tests discoverable by
convention: tests for handlers_guild.go live in handlers_guild_test.go.

New files: handlers_guild_mission_test.go, sys_time_test.go.
No test logic changed — pure file reorganization.
2026-02-26 23:41:44 +01:00
Houmgaor
a68d76c55f test: add coverage tests to reach 65% total coverage
Add 16 test files across 4 packages covering previously untested
handler paths: guild board operations, house/warehouse management,
tower/tenrouirai progress, diva schedule, festa info, cafe duration,
API error paths, sign server responses, and byteframe boundaries.
2026-02-26 23:17:12 +01:00
Houmgaor
cdc4cd9ba3 test(channelserver): add handler coverage tests for misc, cafe, festa, event
Add four new test files covering previously-untested handler functions
to raise total coverage from 57.7% to 60.0%:

- handlers_misc_coverage_test.go: minidata, trend weapons, etc points,
  equip skin history
- handlers_cafe_coverage_test.go: cafe duration bonuses, daily cafe,
  cafe duration
- handlers_festa_coverage_test.go: mezfes data, festa voting, entry,
  charge, prizes, state queries, member enumeration
- handlers_event_coverage_test.go: weekly schedule, login boost,
  scenario data, friends/blacklist operations

Also make mockCharacterRepo.ReadEtcPoints configurable to support
etc points handler tests.
2026-02-26 22:28:32 +01:00
Houmgaor
4a1e019457 fix(shop): update early return test to use pre-G1 client version
PR #150 moved the early return threshold from G10 to G1, so the test
using G7 no longer hit the early return path and panicked on nil
gachaRepo.
2026-02-26 21:57:40 +01:00
Houmgaor
a399ba7419 fix(shop): fix syntax error and update migration tests after #150 merge
PR #150 introduced a double brace `{  {` on handlers_shop.go:109 that
broke compilation. Migration tests were also hardcoded for 1 migration
but 3 now exist (0001–0003).
2026-02-26 21:55:12 +01:00
Houmgaor
1f0ea6ac23 docs(changelog): log gacha shop fix for G1–GG clients (#150) 2026-02-26 21:51:52 +01:00
Houmgaor
ef1763952c Merge pull request #150 from Sin365/main
Resolve the issue of G1 and GG, gacha cat not being usable
2026-02-26 21:49:59 +01:00
sin365
cf3fc3fed3 gacha shop min version range:G1 2026-02-26 18:09:51 +08:00
sin365
cca84415e4 follow the latest version of the repository and modify gacha for handlers_sthop.go 2026-02-26 18:00:58 +08:00
sin365
caab0016d9 merge for delete handlers_shop_gacha.go 2026-02-26 17:57:40 +08:00
sin365
a23a9ca5c6 standardized code comments 2026-02-26 17:31:44 +08:00
Houmgaor
4e300a227c Update issue templates
More details on server/client.
2026-02-25 15:26:49 +01:00
Houmgaor
d9f90e3b46 fix(shop): resolve ambiguous column and missing unique constraint in RecordPurchase
The ON CONFLICT upsert referenced unqualified "bought" which PostgreSQL
rejected as ambiguous, and the table lacked the UNIQUE constraint needed
for ON CONFLICT. Adds a unique index on (character_id, shop_item_id) via
migration 0003 and qualifies the column as shop_items_bought.bought.
2026-02-24 17:06:38 +01:00
Houmgaor
f9d4252860 test(repos): add SQL integration tests for 17 untested repo files
Add 148 integration tests exercising actual SQL against PostgreSQL for
all previously untested repository files. Includes 6 new fixture helpers
in testhelpers_db.go and CI PostgreSQL service configuration.

Discovered and documented existing RecordPurchase SQL bug (ambiguous
column reference in ON CONFLICT clause).
2026-02-24 16:57:47 +01:00