Workflow and rules - SocketSVC Docs
SocketSVC Docs

Workflow and rules

Daily development workflow, development rules, and long-term maintenance of versions, dependencies and docs

這一頁還沒有翻譯,以下顯示英文原文。

Daily workflow

Confirm the working directory and branch first, and understand the requirement, the affected modules and an observable completion condition. When fixing a bug, find the reproduction conditions and cause before changing code.

Work on a feature branch, e.g. feat/client-device-ui, fix/voice-reconnect. Keep each change focused on one requirement, and preserve other uncommitted work.

Look for existing implementations and tests first, and decide whether the change belongs in shared code, version adaptation, server or shared; avoid copying the same fix into every version.

Run the tests relevant to the change. If it touches the shared client, versions, Mixins or resources, run the full client matrix before committing; if it touches server/shared, also run the server build. See common builds and tests for commands.

Check the diff, the generated artifacts and the test evidence; accept behaviour that can only be confirmed in-game separately, and record anything left unfinished.

Update the related docs, tidy up commits/PR, and merge or release only after the checks and review pass (see commit and review).

Development rules

Code and state management

  • Java follows the existing naming style with four-space indentation; files are UTF-8. Do not mix unrelated whole-file reformatting into feature fixes.
  • Prefer changing the layer that actually owns the behaviour and reuse existing flows; new abstractions, dependencies or background threads need a concrete purpose.
  • Minecraft UI/game state operations go back to the client game thread; Paper state operations respect the existing main-thread/cache boundaries. Never block an audio worker or WebSocket callback waiting for the game thread.
  • Audio and network queues stay bounded; slow receivers, malformed packets and failing devices must not cause unbounded buildup, unbounded retries or resource leaks.
  • Connections, devices and native codecs need an explicit lifecycle. After going offline/switching servers, old callbacks, token responses or workers must not modify the new session.
  • Keep the existing constraints for mute, deafen, first-time setup and stopping speech; audio changes must verify local and remote speaking, stopping, resuming and device switching together.

Network protocol and config compatibility

  • common/core is the protocol definition shared by both sides; after changing it, verify both client and server, not just that one side compiles.
  • New capabilities need explicit negotiation and a fallback for older versions. Never send un-negotiated new control messages to an old server.
  • Keep one-time tokens, player binding, and packet size/sequence/rate checks; logs and commits must not contain real tokens or full URLs that include a token.
  • When changing the wire format, update the voice protocol docs in the same change, covering mixed old/new sides, invalid data, reconnects and rollback behaviour.
  • New config fields need a safe default, old-file reading and invalid-value handling; keep the existing corrupt-file backup and atomic-write behaviour so player settings are not destroyed.
  • Do not change the voice protocol or config format just because Minecraft is being upgraded; feature versions, game versions and the wire protocol are separate maintenance items.

Mixins and rendering

  • Compare against the target version's actual methods and bytecode; renaming without checking the call path can make icons disappear or shift.
  • Nametags keep vanilla's visibility conditions, scoreboard offset and special-name offsets, and must never expose player names that were hidden.
  • Changing a hook requires updating the corresponding bytecode contract test and running mixinTest; never lower required/defaultRequire or skip tests to hide an incompatibility.
  • In-game visuals, occlusion, fonts, GUI scale and interaction flows still need in-game acceptance; successful compilation and Mixin loading do not mean the visuals are correct.

Icons and translations

  • Voice status icon source art lives in images/; replace the files with the same names in client/common/src/main/resources/assets/socketsvc/textures/gui/ too. Updating only the source art does not change the game artifact.
  • The status icons are currently 128×128 PNGs with transparency; their on-screen size is controlled by the UI and font settings, not the source image size.
  • The HUD and settings buttons currently render at 24×24 GUI units, and the nametag font has height 12 and ascent 9; enlarging the source images does not enlarge these display sizes.
  • When changing sizes, paths or what an icon is used for, check ModernButton, VoiceHud, font/voice_icons.json and the existing resource tests; inspect the images inside the final JAR.
  • User-visible client text is maintained through VoiceTranslations and assets/socketsvc/lang/; every bundled catalog must keep the same keys and format arguments as en_us.json. Player names and device names are not translated.
  • A new Screen that overrides render must be added to the void render( rule's files list in gradle/compat/modern.json. That rename is file-scoped, unlike the global ones around it, so a screen left out of the list compiles on the default (legacy) Minecraft version and fails only on 26.x with "method does not override or implement a method from a supertype". Build one modern version before assuming a UI change is done.
  • When adding a language, drop a new <locale>.json next to the others — TranslationRegressionTest discovers it from the directory and checks its keys, its %s arguments and its English fallback with no test change needed. Then check small windows, long text and keyboard operation.

For what each status icon means, see settings.

Future changes and long-term maintenance

Sources of truth

Avoid keeping version information separately in docs, scripts and workflows. The settings below are the primary sources for the corresponding facts; version tables and example commands in the docs are readable summaries and should be checked whenever the settings change.

InformationPrimary sourceAlso check when it changes
Supported versions, loaders, dependencies and feature versions of the three sidesgradle/socketsvc.propertiesValidation in settings.gradle.kts, the matrix script, the Modrinth script, development setup and versions and loaders
Gradle versiongradle/wrapper/gradle-wrapper.propertiesWrapper files, Loom/Shadow compatibility, CI
Gradle daemon Javagradle/gradle-daemon-jvm.propertiesThe updateDaemonJvm setup in the root build.gradle.kts, IDE, CI JDK installation
Client Java per version<MC>.java in the version tableMixin level, bytecode, test JVM, native libraries
Paper dependencyserver/paper/build.gradle.ktsAPI declaration in plugin.yml, server tests, install instructions
Wire protocol and negotiationcommon/core/src/main/java, both sides' connection codeVoice protocol, mixed-version and malicious-input tests
Client config defaults/compatibilitySocketSvcConfigUI, translations, old-config tests
Server default configserver/paper/src/main/resources/config.yml and server/common/src/main/resources/socketsvc-server.yml (must be identical, checked by ServerModConfigTest); reading logic in VoiceServerSettingsreload/restart boundaries, admin commands, docs
Modrinth publishing configscripts/modrinth.jsonLoader tags, dependencies, modrinth_release.py
Validation and publishingscripts/build_matrix.py, scripts/publish_release.pyRequired JDKs, local environment, report/artifact paths, release notes

The version catalog does not currently manage the Gradle Wrapper or all shared libraries (see gradle/client-libraries.gradle, gradle/server-libraries.gradle), so changing it alone does not complete a toolchain upgrade. If the docs disagree with the code, find out the actual behaviour and fix the discrepancy; do not assume the docs or old comments are correct.

Handling common upgrades

Change typeImplementation and verificationRollback considerations
New Minecraft release or patchConfirm the actual API/dependencies first and add the version row explicitly; compile, Mixins, resources, full matrix and in-game testing (see adding a release version)A single target version can be withdrawn while keeping other versions' artifacts
Snapshot/pre-release/RCExperiment on a separate development branch; do not add it to the supported list just because it compilesNot published as officially supported without passing acceptance
Java/Gradle/Loom upgradeDistinguish daemon Java from each version's runtime Java; update the Wrapper, daemon task config and CI together; verify the oldest and newest target versionsKeep old bytecode requirements; a tool upgrade must not accidentally raise the Java floor for all players
Fabric API/Loader/Mod Menu upgradeEach affected version uses dependencies that actually exist and are compatible; make sure the optional Mod Menu does not become a required runtime dependencyKeep verified dependency combinations; adapt separately when there are binary differences
Paper/server upgradeConfirm the API, actual runtime Java and plugin declaration; run server tests and test together with the clientThe client version table does not guarantee server rollback or Paper compatibility
Opus/RNNoise/other native updatesCheck the JNI Java API, resources for all six platforms and JAR packaging; run the native regression and test on every OS/architecture claimedPackaged files existing does not mean they load; passing on one platform does not justify claiming all
WebSocket/protocol feature extensionsEnable only after capability negotiation; spell out new client + old server, old client + new server, new + new, and reconnect scenariosDocs must describe the fallback when not negotiated; incompatible changes must not ship silently
Config/stored data migrationDefine old-file reading, new defaults, invalid-value handling, backups and any needed schema detection; add old-file fixture testsState whether old code can read it back; if not, provide backup restore steps
New language, icon size or fontSync source art/packaged resources/references/tests; verify small screens, long text, transparency and nametagsKeep the path contract, or update every consumer in the same change
New platform, loader or feature moduleLocate existing reusable boundaries first, then split platform implementations, dependencies and test matrix only for actual differencesDo not build a speculative plugin framework up front; label each artifact's support scope clearly
CI runner/action/release process updateConfirm permissions, toolchains, native runtime environment, artifact selection and failure reports; verify on a branch firstKeep automated builds and automated publishing separate; failed or unverified matrix entries must not count as a successful release

Split upgrade work into units whose failures can be pinned down: keep the existing target versions buildable first, then introduce the new tool or API, and only then add the support claim. If upstream constraints make the steps inseparable, the PR must explain why they are bundled and what is affected.

Evolving features and support scope

General feature fixes go into the shared client first; as platform differences grow, consider extracting concrete boundaries (e.g. screens, keybinds, network registration) into small interfaces. Keep transformation rules for pure name differences, and use Java implementations when behaviour or call timing differs; do not hide conditional logic in large text replacements.

If a source set, module or another loader is added in future, also confirm whether it needs version adaptation, whether it ends up in the release JAR, which tests run, and whether CI actually includes it; do not assume the generation flow, which currently only handles main/test, will cover new directories automatically.

Evaluation rules, not commitments

When adding groups, recording, permissions or other voice features, first define the user flow, state owner, protocol requirements, resource limits and completion conditions, then decide whether to extend the architecture. These are rules for evaluating future work; they do not mean the features are implemented or promised.

Version retirement and release records

The version table currently only has supported, with no status fields such as experimental or deprecated. To retire a version, first describe the scope and the replacement version in the release notes; only after support has formally ended remove the version, update default, the docs and validation rules, and confirm the matrix still has valid entries (see withdrawing a version or loader).

If a machine-readable version lifecycle is needed in future, update the version table schema, Gradle validation, Python parsing, CI and tests together; adding a field alone does not mean the process supports it.

Every release records at least: commit/tag, client/server feature versions, Minecraft range, toolchain, verified OS/devices and mixed-version scenarios, known limitations, config/protocol compatibility and rollback method. Release notes can be compiled from PRs; nothing currently generates these records or publishes automatically.

Documentation done criteria

Any change to installation, commands, config, dependencies, artifact paths, support scope or verification should update the corresponding docs and examples in the same PR. Before finishing, confirm:

  • Newly documented versions/tasks/files exist in the actual configuration, and documented commands work in the shell described.
  • The automation the docs describe actually exists; unfinished designs, tests and in-game acceptance are clearly marked.
  • Old data, mixed-version deployment and rollback are explained, without asking users to blindly delete config or caches.
  • No second copy of a CI list that can be generated from the version table; intentionally kept version summaries are in sync.
  • Outdated entry points have become historical notes or point to the latest docs, so newcomers do not follow wrong paths.