{"id":47669445,"url":"https://github.com/yoshk4e/perlica-rs","last_synced_at":"2026-06-03T03:01:11.535Z","repository":{"id":345550869,"uuid":"1164769782","full_name":"Yoshk4e/perlica-rs","owner":"Yoshk4e","description":"A server software reimplementation for an old version of a certain anime game about factories.","archived":false,"fork":false,"pushed_at":"2026-05-25T23:58:57.000Z","size":3827,"stargazers_count":34,"open_issues_count":1,"forks_count":7,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-05-26T01:26:24.389Z","etag":null,"topics":["private-server","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Yoshk4e.png","metadata":{"files":{"readme":"README.md","changelog":"changelog.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-23T13:15:57.000Z","updated_at":"2026-05-25T13:38:44.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/Yoshk4e/perlica-rs","commit_stats":null,"previous_names":["yoshk4e/perlica-rs"],"tags_count":17,"template":false,"template_full_name":null,"purl":"pkg:github/Yoshk4e/perlica-rs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Yoshk4e%2Fperlica-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Yoshk4e%2Fperlica-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Yoshk4e%2Fperlica-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Yoshk4e%2Fperlica-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Yoshk4e","download_url":"https://codeload.github.com/Yoshk4e/perlica-rs/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Yoshk4e%2Fperlica-rs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33845770,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-03T02:00:06.370Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["private-server","rust"],"created_at":"2026-04-02T12:26:47.778Z","updated_at":"2026-06-03T03:01:11.528Z","avatar_url":"https://github.com/Yoshk4e.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Perlica RS\n\n![sleep](assets/img/sleep.png)\n![Rust](https://img.shields.io/badge/Rust-2024-000000?logo=rust\u0026logoColor=white)\n![License](https://img.shields.io/badge/License-AGPL3.0-yellow)\n![Status](https://img.shields.io/badge/Status-Playable_Core-2E8B57)\n\u003ca href=\"https://discord.gg/BE7CwcesZp\"\u003e\u003cimg alt=\"Discord - Perlica Winery\" src=\"https://img.shields.io/discord/1483939903753425056?label=Discord\u0026logo=discord\"\u003e\u003c/a\u003e\n\n## Features\n\n### Core Systems\n- Full phased login sequence (BaseData -\u003e Wallet -\u003e ItemBag -\u003e CharBag -\u003e Unlocks -\u003e Guides -\u003e Missions -\u003e CharAttrs -\u003e CharStatus -\u003e Factory -\u003e Bitsets -\u003e EnterScene)\n- Character bag with multiple teams, team switching, skill levels, attributes, and normal/ultimate skills\n- Character progression: level up via exp items, ascension / break stage, and skill level advancement.\n- Complete weapon system: exp feeding from fodder weapons and stackable items , breakthrough levels, gem socket/unsocket, equip/unequip.\n- Equipment system: head/body/ring slot equipping and unequipping, with per-character slot tracking.\n- Gem depot, instanced weapon gems with socket binding tracked on both the weapon and gem side\n\n### World \u0026 Scene\n- Scene loading and full entity synchronisation on load finish.\n- Dynamic radius-based monster spawning and despawning: enemies enter view within 80 u, leave beyond 100 u, with a 60-second respawn cooldown after being killed\n- NPC and interactive entity packing on scene load, interactives and NPCs are sent to the client with their `DynamicParameter` property maps\n- Scene teleport with intra- and inter-scene handling: inter-scene transitions send `ScEnterSceneNotify` / `ScLeaveSceneNotify`; intra-scene warps preserve level-script runtime state\n- Revival system with campfire checkpoint persistence, revival modes (default, repatriate, checkpoint), and `CsSceneRevival` that revives dead characters at 50 % HP\n\n### Mission \u0026 Guide (half broken state)\n- `MissionManager` with quest objective tracking, multi-quest progression within a mission, and mission state transitions (processing -\u003e completed)\n- Bootstrap: on first login the prologue mission (`mission_mai_e0m1`) is selected, or the first available mission if the prologue is absent from assets\n- Mission tracking.\n- All mission and guide state is persisted across sessions\n\n### Movement \u0026 Authoritative Position\n- Authoritative movement: only the team leader's position is tracked server-side; position triggers the dynamic entity visibility update each tick\n- Position and rotation synced to `WorldState` before every save so the player respawns at their last known location\n\n### Inventory \u0026 Economy\n- Item bag sync on login and after modifications, depots 1 (weapons), 2 (gems), 3 (equips), 4 (special items), 5 (mission items); factory depot pushed separately\n- Wallet: gold and diamond pushed unconditionally on every login (9,999,999 each)\n- Factory context stub pushed on login and after every scene load (required for the client factory UI to initialise)\n\n### Bitset \u0026 Unlock\n- Bitset system covering all `BitsetType` values (FoundItem, Wiki, GotItem, AreaFirstView, LevelHaveBeen, and more), full sync on login\n- All unlock systems pushed as fully unlocked on every login\n\n### Persistence\n- Bincode-based player saves (atomic write via tmp -\u003e rename) storing: `CharBag`, `WorldState`, `BitsetManager`, checkpoint, revival mode, `MissionManager`, `GuideManager`\n- Automatic data validation after load, repairs mismatched weapon references and orphaned equip entries\n\n### Administration\n- **MUIP GM bridge** (`perlica-muip-server`): HTTP admin panel on port 8080 with endpoints `/muip/gm`, `/status`, `/api/players`; forwards commands to the game server over a local TCP socket\n- **In-game GM commands** (via MUIP HTTP or the web panel):\n  - `help` — list all commands\n  - `heal [all|team]` — restore HP to full for all owned characters or the active team\n  - `level \u003cn\u003e` — set the player's role level (1–100) live\n  - `tp \u003cscene\u003e \u003cx\u003e \u003cy\u003e \u003cz\u003e [rot_y]` — teleport to any scene and position\n  - `spawn \u003ctemplate\u003e [x y z] [level] [entity_type]` — dynamically spawn a monster\n  - `give weapon \u003ctemplate\u003e` — add a weapon instance and sync the item bag\n  - `kick [reason]` — disconnect the player\n\n\n---\n\n#### NOTE: Perlica RS is currently under active development\n#### NOTE x2: contributions are always welcome, for that read the Contributing section on GitHub\n\n## Getting started\n\n### Requirements\n- [Rust 1.85+](https://www.rust-lang.org/tools/install)\n\n### Setup\n\n#### a) Building from sources\n```sh\ngit clone https://github.com/Yoshk4e/perlica-rs.git\ncd perlica-rs\ncargo build --bin perlica-config-server --release\ncargo build --bin perlica-game-server --release\ncargo build --bin perlica-muip-server --release\n```\n\n#### b) Using pre-built binaries\n\nDownload the latest release from the repository releases page and run the server binaries.\n\n### Configuration\n\nThe server uses a single configuration file at the project root: `Config.toml` (auto-created from `servers/game-server/config.default.toml` on first run if absent).\n\nKey sections:\n\n| Section | Purpose |\n|---|---|\n| `[server]` | Network binding for the game server (default: `0.0.0.0:1337`) |\n| `[assets]` | Path to your dumped JSON asset tables |\n| `[world_state]` | New-player spawn scene, position, rotation, and role level |\n| `[default_team]` | Starting team composition for new players (4 character IDs) |\n| `[muip_gm]` | Local GM bridge the game server listens on (default: `127.0.0.1:2338`) |\n| `[muip]` | MUIP HTTP server binding, auth token, and GM bridge address |\n\nExample `Config.toml`:\n```toml\n[server]\nhost = \"0.0.0.0\"\nport = 1337\n\n[assets]\npath = \"assets\"\n\n[world_state]\nrole_level = 1\nrole_exp = 0\nlast_scene = \"map01_lv001\"\npos_x = 469.0\npos_y = 107.11\npos_z = 217.83\nrot_x = 0.0\nrot_y = 60.0\nrot_z = 0.0\n\n[default_team]\nteam = [\n    \"chr_0003_endmin\",\n    \"chr_0013_aglina\",\n    \"chr_0004_pelica\",\n    \"chr_0009_azrila\",\n]\n\n[muip_gm]\nhost = \"127.0.0.1\"\nport = 2338\nenabled = true\n\n[muip]\nhost = \"0.0.0.0\"\nport = 8080\ntoken = \"change-me\"\ngm_host = \"127.0.0.1\"\ngm_port = 2338\n```\n\nKnown good spawn positions:\n\n| Scene | X | Y | Z |\n|---|---|---|---|\n| `map01_lv001` | 469.00 | 107.11 | 217.83 |\n| `map01_lv002` | 414.41 | 29.53 | 4.01 |\n| `map01_lv003` | 227.90 | 137.60 | 297.00 |\n| `map01_lv004` | 469.00 | 107.11 | 217.83 |\n| `map01_lv005` | 395.00 | 95.00 | 302.40 |\n| `map01_lv006` | 687.00 | 68.00 | 120.00 |\n\n### Running the server\n\nAll three binaries are needed for the full stack:\n\n```sh\ncargo run --bin perlica-config-server --release \u0026\ncargo run --bin perlica-game-server --release \u0026\ncargo run --bin perlica-muip-server --release \u0026\n```\n\nOr with pre-built binaries:\n\n```sh\n./target/release/perlica-config-server \u0026\n./target/release/perlica-game-server \u0026\n./target/release/perlica-muip-server \u0026\n```\n\nThe config server must be reachable at `127.0.0.1:21041`. The game server listens on the address configured in `[server]`.\n\n### Logging in\n\nThe server is compatible with the alpha client.\nFor more information consider joining the Discord server.\n\nTo connect to the local server, apply the provided [client patch](https://github.com/Yoshk4e/beyond-patch-universal) which replaces the server address so the client can communicate with local infrastructure.\n\nPS. if you feel like disabling censorship use [xeon's client patch](https://git.xeondev.com/LR/C)\n\n## Development notes\n\n### Adding a command handler\n1. Create (or extend) a handler function in `servers/game-server/src/handlers/\u003cfeature\u003e.rs`.\n2. Import the module in `handlers/mod.rs`.\n3. Register the command in the `handlers!` macro in `servers/game-server/src/net/router.rs`:\n   - Use `reply { CsMyCommand =\u003e feature::on_cs_my_command }` when the handler returns a direct response.\n   - Use `no_reply { CsMyCommand =\u003e feature::on_cs_my_command }` for fire-and-forget updates and complete control over the wire.\n\n### Error types\n\nEach library crate has its own `error.rs`. Use the most specific variant available:\n\n| Crate | Error enum | Key variants |\n|---|---|---|\n| `config` | `ConfigError` | `ReadFile`, `ParseJson`, `ReadDir`, `InvalidStructure` *(use instead of `Io(InvalidData, …)` for bad JSON shapes)*, `Io` |\n| `db` | `DbError` | `CreateDir`, `ReadSave`, `Deserialize`, `Serialize`, `WriteTmp`, `Rename` |\n| `logic` | `LogicError` | `NotFound`, `InvalidOperation`, `Insufficient` *(typed quantity error, use instead of string-formatted `InvalidOperation` for stackable-item shortfalls)*, `Config` |\n| `game-server` | `ServerError` | `Config`, `Db`, `Logic`, `Io`, `Decode`, `ConfigRead`, `ConfigParse` |\n\n**`LogicError::Insufficient { item_id, have, need }`** — use this instead of `InvalidOperation(format!(\"Insufficient …\"))` whenever a stackable-item consume fails due to quantity. Callers can match on it without parsing the message string.\n\n**`ConfigError::InvalidStructure { path, message }`** — use this for files that parse as valid JSON but whose top-level shape is wrong, instead of wrapping `std::io::Error::new(InvalidData, …)` inside `ConfigError::Io`.\n\n### Other notes\n- Logging starts at DEBUG level with an ANSI art startup banner.\n- Player state is automatically validated after loading to repair inconsistencies.\n- The login sequence is a phase state machine in `handlers/login.rs`. Adding a new phase requires an arm in `LoginPhase`, its `next()` transition, and a `push_*` call in `run_login_sequence`.\n- Dynamic entity visibility uses `ENTER_RADIUS = 80.0` and `LEAVE_RADIUS = 100.0` constants defined in `logic/src/scene.rs`, updated on every leader movement packet.\n\nFor questions about the code, refer to the inline module documentation in the source code. Otherwise, join the Discord server.\n\n## License\n\nThis project is licensed under the AGPL-3.0 license\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyoshk4e%2Fperlica-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyoshk4e%2Fperlica-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyoshk4e%2Fperlica-rs/lists"}