commit bcc5fe1bcb9d8b838552fed514221ea29d6513ae Author: Alexa <53471801+Alexa-RR@users.noreply.github.com> Date: Thu May 21 13:26:46 2026 +0300 Add initial documentation and structure for DorkNet project - Create README.md for project overview and setup instructions - Add admin-ui/README.md for admin UI details and development setup - Introduce client-mod/README.md explaining the MelonLoader mod functionality - Establish docker/README.md for Docker setup and configuration - Create docs/README.md to index project documentation - Implement advanced-setup.md for Docker stack configuration - Document architecture in architecture.md - Provide easy-setup.md for hosting instructions - Add FAQ.md for common questions and legal considerations - Create joining-a-server.md for player connection instructions - Establish troubleshooting.md for common issues and resolutions - Introduce easy-app/README.md for the unified desktop application - Add server/README.md for ASP.NET Core backend details - Document tools/README.md for CLI helper scripts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6cb2c37 --- /dev/null +++ b/.gitignore @@ -0,0 +1,52 @@ +# Build outputs +**/bin/ +**/obj/ +**/node_modules/ +**/dist/ +**/.vite/ +**/build/ + +# IDE +.vs/ +.vscode/ +*.user +*.suo +*.csproj.user + +# Local config (NEVER commit) +appsettings.json +appsettings.Local.json +appsettings.Development.json +.env +.env.local +.env.*.local + +# Runtime data +data/*.db +data/*.db-shm +data/*.db-wal +data/*.db.bak.* +data/images/ +keys/ +**/MelonLoader/UserData/dorknet-clientmod.json +**/MelonLoader/Latest.log +**/MelonLoader/Logs/ +**/output_log.txt +**/crash_reports/ + +# Decompilation dumps — never ship Rec Room IP derivative works +Cpp2IL_ISIL/ +Cpp2IL_CS/ +**/Recroom_Release_Data/ +**/Recroom_Release.exe +**/GameAssembly.dll +**/global-metadata.dat +**/version.dll + +# OS +.DS_Store +Thumbs.db + +# Test outputs +TestResults/ +*.coverage diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..c4ce71b --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,55 @@ +# Contributing to DorkNet + +Thanks for your interest. A few ground rules before you open a PR. + +## Code style + +- **C#**: nullable enabled. Match the file you're editing. No regions, no + multi-paragraph XML docs, no async-without-await. +- **TypeScript / React**: existing patterns — function components, named + exports, tailwind classes, no CSS modules. Lint with `npm run lint` from + `admin-ui/`. +- **No AI-co-author trailers in commit messages.** Use a real attribution + line or none at all. + +## Branches and commits + +- `main` is protected; PR from a feature branch. +- Conventional commits welcome but not required. One-line summary should + describe the *why*, not the *what* — the diff already shows what. + +## Scope of contributions we welcome + +- Bug fixes against documented behavior +- Feature parity with the 2020 client (anything reverse-engineered cleanly) +- Performance work +- Better docs, screenshots, video walkthroughs +- New translations of the admin UI + +## Scope of contributions we don't accept + +- **Rec Room game assets, decompiled source, or modified game binaries.** + We never ship Rec Room IP. See [DISCLAIMER.md](DISCLAIMER.md). PRs that + add these files will be closed. +- **Cheats, exploits, or features that would harm other public Rec Room + servers.** This project exists to let people self-host the 2020 backend + for themselves; it isn't a vehicle for griefing live games. +- **Crypto / NFT / monetization plugins.** Hard no. + +## Reporting security issues + +Don't open a public issue. Email the maintainer at the address in the repo +metadata, or use GitHub's private vulnerability reporting. + +## Setting up a dev environment + +See [docs/advanced-setup.md](docs/advanced-setup.md) for the full server +stack. For just hacking on the admin UI: + +```bash +cd admin-ui +npm install +npm run dev +``` + +Points at `http://localhost:5000` by default — start the server first. diff --git a/DISCLAIMER.md b/DISCLAIMER.md new file mode 100644 index 0000000..5739afb --- /dev/null +++ b/DISCLAIMER.md @@ -0,0 +1,50 @@ +# Disclaimer + +DorkNet is an independent, fan-made, clean-room reimplementation of the +backend protocol used by the **2020 release of Rec Room** (build +`Recroom_Release` dated 2020.03.10). + +It is **not** affiliated with, endorsed by, or sponsored by: + +- Rec Room Inc. +- Against Gravity (the original developer) +- Photon (Exit Games GmbH) +- Steam / Valve Corporation +- Meta / Oculus + +**Rec Room™**, the Rec Room logo, and all in-game art, audio, models, +locations, characters, and brand assets are the intellectual property of +Rec Room Inc. and are used here only for descriptive interoperability. + +## What DorkNet does and doesn't ship + +DorkNet's repository contains: +- Original server code (ASP.NET Core) +- Original admin tooling (React) +- Original MelonLoader mod (C#) +- Patcher scripts that operate on the user's own local Rec Room install + +DorkNet's repository **does not** contain: +- The Rec Room game executable, assets, or any redistributable Rec Room IP +- Decompiled Rec Room source or IL2CPP dumps +- Patched copies of `Recroom_Release.exe`, `global-metadata.dat`, or any + Rec Room game file + +You must acquire the 2020.03.10 Rec Room client yourself through whatever +means are legal in your jurisdiction (e.g. SteamDB depot tools against an +account that owns Rec Room). The patcher runs on your machine, modifies +files locally, and never uploads anything anywhere. + +## Use at your own risk + +This is hobby software. There are no warranties of any kind. If running +DorkNet violates a license you agreed to (e.g. Steam Subscriber Agreement, +Rec Room Terms of Service), that's between you and the rights holder. +DorkNet's authors take no responsibility for consequences arising from +your use of the software. + +## Takedown requests + +If you represent Rec Room Inc. or another rights holder and wish to discuss +this project, please open an issue on the public repository and we will +respond promptly. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..be3f7b2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/README.md b/README.md new file mode 100644 index 0000000..59c9b5f --- /dev/null +++ b/README.md @@ -0,0 +1,84 @@ +# DorkNet + +A self-hostable reimplementation of the 2020 Rec Room backend. Bring your own +client; run a private server for yourself and your friends. + +> ⚠️ **Not affiliated with Rec Room Inc. or Against Gravity.** +> See [DISCLAIMER.md](DISCLAIMER.md). DorkNet ships no Rec Room game assets or +> modified binaries — you supply your own legally-acquired Rec Room 2020.03.10 +> install. + +--- + +## Two ways to run it + +### 🎮 Easy mode — desktop app + +One download. Double-click. Choose "host" or "join" on first launch. + +- **Host a server** for you and your friends — runs a local server + tunnel, + patches your Rec Room install, and gives you a shareable join code. +- **Join a server** someone shared with you — paste the code, point at your + Rec Room install, hit play. + +→ **[Easy setup guide](docs/easy-setup.md)** — screenshots, takes 5 minutes. + +[Download the latest Easy app →](https://github.com/YOUR_GH_USERNAME/dorknet/releases/latest) + +### 🛠️ Advanced mode — Docker + +For people running a community server, doing custom modding, or contributing +back. Postgres + Redis + the ASP.NET Core server behind an nginx reverse proxy. + +```bash +git clone https://github.com/YOUR_GH_USERNAME/dorknet +cd dorknet/docker +cp .env.example .env # fill in 2-3 values +docker compose up -d +``` + +→ **[Advanced setup guide](docs/advanced-setup.md)** + +--- + +## What works / what doesn't + +| Feature | Status | +| -------------------------------- | ------ | +| Account creation + login | ✅ | +| Dorms (per-player save) | ✅ | +| Rec Room Originals (RecCenter, Paintball, Stunt Runner, etc.) | ✅ | +| Maker Pen (build + save rooms) | ✅ | +| Photon Cloud matchmaking | ✅ | +| Room chat | ✅ | +| DM / group chat | ✅ | +| Friend lists + invites | ✅ | +| Leaderboards | ✅ | +| Player profiles + cheer badges | ✅ | +| Store catalog + gifting | ✅ | +| Game invites | ✅ | +| Image upload (polaroids, room thumbnails) | ✅ | +| VR (Quest/Index/etc.) | ⚠️ Photon-dependent; works in dev, untested at scale | +| Mobile / Junior accounts | ⚠️ Partial — Junior chat-restrictions disabled by default in Easy mode | +| Voice chat | ❌ Routes through Photon Voice; needs separate Photon Voice AppId | +| Cross-server federation | ❌ Out of scope | + +--- + +## License & legal + +- **Code**: [AGPL-3.0](LICENSE). Hosted forks must publish their source. +- **"Rec Room"** is a trademark of Rec Room Inc. See [DISCLAIMER.md](DISCLAIMER.md). +- DorkNet is a clean-room reimplementation of the 2020 backend protocol for + educational and personal use. + +--- + +## Docs + +- [Easy setup](docs/easy-setup.md) +- [Advanced setup](docs/advanced-setup.md) +- [Joining a server](docs/joining-a-server.md) +- [Architecture](docs/architecture.md) +- [FAQ](docs/faq.md) +- [Contributing](CONTRIBUTING.md) diff --git a/admin-ui/README.md b/admin-ui/README.md new file mode 100644 index 0000000..af71836 --- /dev/null +++ b/admin-ui/README.md @@ -0,0 +1,36 @@ +# admin-ui/ + +React + Vite + Tailwind SPA. Talks to `/api/admin/v1/*` on the server. + +Embedded into: +1. The standalone server's `wwwroot/admin/` (advanced mode), served at + `https://admin./`. +2. The Easy desktop app via a Photino WebView (host mode admin tab). + +## Dev + +```bash +npm install +npm run dev # http://localhost:5173, proxies /api → :5000 +``` + +Start the server first; Vite's proxy doesn't synthesize endpoints. + +## Build + +```bash +npm run build # dist/ — copied into server/wwwroot/admin by the + # server's CI publish step, and into easy-app/Resources/ + # by tools/build-easy-app.ps1 +``` + +## Stack notes + +- React 18 + Vite 5 + TypeScript +- Tailwind 3 with a custom dark `ink/brand` palette in `tailwind.config.js` +- React Router 6 +- No external component library; primitives in `src/components/` +- No state library beyond per-page `useState` + `useApi` + +See [docs/architecture.md](../docs/architecture.md) for how the SPA is +delivered in both modes. diff --git a/client-mod/README.md b/client-mod/README.md new file mode 100644 index 0000000..1c39188 --- /dev/null +++ b/client-mod/README.md @@ -0,0 +1,57 @@ +# client-mod/ + +MelonLoader 0.6.x mod that retargets the 2020 Rec Room client at a +DorkNet server. Compiles to `DorkNet.ClientMod.dll`, which the patcher +drops into the user's `Recroom_Release/Mods/` folder. + +## What it does + +Harmony patches applied at boot: + +- **`Uri ctor`** — rewrites every `.rec.net` URL to your configured + server host. Catches every hardcoded API endpoint the watch ships with. +- **`PhotonNetwork.ConnectUsingSettings`** — overrides the baked-in + Photon Cloud AppId with yours. +- **`NetworkingPeer.CallAuthenticate`** — injects `userid` + `LoginLock` + into Photon's CustomAuth so your server can identify the player. +- **`BouncyCastle.Tls.*NotifyServerCertificate`** — bypasses TLS chain + validation. The 2020 client only trusts a baked-in cert set; we replace + the verifier so any cert from your server is accepted. (Mitigated by + also force-routing only to your configured host.) +- **`PlayerEmotes.RemoveInvalidCharactersFromMessage`** — skips the + TMP font-validation step that NREs when the font asset isn't loaded + yet (private servers don't always have it cached at chat-send time). +- **`AccountExtensions.CanLocalPlayerChat`** — forces chat-enabled for + Junior / restricted accounts (single-tenant private server, no chat + moderation needed). + +See `Mod.cs` for the full patch list with citations to the Cpp2IL +disassembly that justifies each one. + +## Config + +The mod reads `MelonLoader/UserData/dorknet-clientmod.json`: + +```json +{ + "ServerHost": "abc-def.trycloudflare.com", + "PhotonAppId": "your-photon-realtime-appid", + "PhotonCloudRegion": "eu", + "InjectAuthValues": true, + "EnableTlsTrustBypass": true +} +``` + +The patcher (desktop app and CLI) writes this file as part of the patch +flow — users don't normally edit it by hand. + +## Building + +```bash +dotnet build -c Release +# → bin/Release/DorkNet.ClientMod.dll +``` + +Requires Il2Cpp interop assemblies from the user's MelonLoader install. +Path defaults to `dist/RecRoom-Clean-2020.03.10/MelonLoader/`; override +with `-p:MelonLoaderDir=`. diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 0000000..7c317ed --- /dev/null +++ b/docker/README.md @@ -0,0 +1,22 @@ +# docker/ + +The Docker Compose stack for advanced mode. See +[docs/advanced-setup.md](../docs/advanced-setup.md) for the full +walkthrough. + +``` +docker/ +├── docker-compose.yml Postgres + Redis + server + nginx +├── docker-compose.cloudflared.yml Optional: replace nginx with CF Tunnel +├── Dockerfile.server Multi-stage: SDK build → admin-ui build → runtime +├── nginx.conf Subdomain routing for *.your-domain +└── .env.example Required environment variables +``` + +Quick start: + +```bash +cp .env.example .env +$EDITOR .env +docker compose up -d +``` diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..54192c6 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,10 @@ +# DorkNet docs + +| Doc | For who | +| -------------------------------------- | ---------------------------------------------------- | +| [easy-setup.md](easy-setup.md) | Hosts who want the desktop-app one-click experience | +| [advanced-setup.md](advanced-setup.md) | Hosts running a community server on a VPS | +| [joining-a-server.md](joining-a-server.md) | Players whose friend gave them a join code | +| [architecture.md](architecture.md) | Anyone hacking on the code | +| [faq.md](faq.md) | Common questions before you ask in issues | +| [troubleshooting.md](troubleshooting.md) | Known failure modes + fixes | diff --git a/docs/advanced-setup.md b/docs/advanced-setup.md new file mode 100644 index 0000000..939589a --- /dev/null +++ b/docs/advanced-setup.md @@ -0,0 +1,129 @@ +# Advanced mode — Docker stack + +For hosts running a community server (more than ~10 concurrent players), +doing custom modding work, or contributing to DorkNet itself. + +If you just want to play with friends, the [easy-setup](easy-setup.md) +desktop app is what you want. + +## What you get + +- **server**: the ASP.NET Core backend +- **postgres**: the canonical store (the desktop app uses SQLite; for >10 + concurrent players, Postgres is what you want) +- **redis**: cross-replica presence cache (skip with `REDIS_URL=` empty + to fall back to in-memory; loses presence on restart but otherwise fine) +- **nginx**: TLS termination + multi-subdomain routing + (`api.*`, `auth.*`, `accounts.*`, `match.*`, `chat.*`, `cdn.*`, `commerce.*`, + `img.*`, `leaderboard.*`, `notify.*`) + +Behind a proper TLS certificate (Let's Encrypt via Caddy or Cloudflare +Tunnel) this should comfortably run 50+ concurrent players on a $20/mo VPS. + +## Prerequisites + +- A Linux VPS (Debian 12 / Ubuntu 22.04 / etc.) +- A domain you control with wildcard DNS pointing at the VPS + (`*.your-server.example.com → 1.2.3.4`) +- Docker + Docker Compose + +## Setup + +```bash +git clone https://github.com/YOUR_GH_USERNAME/dorknet +cd dorknet/docker + +cp .env.example .env +$EDITOR .env # fill in the values noted below +``` + +### Required `.env` values + +```env +# Your domain. Server expects to find itself at *.DORKNET_DOMAIN. +DORKNET_DOMAIN=your-server.example.com + +# A long random string. Used to sign JWTs. +JWT_SECRET=$(openssl rand -base64 64) + +# Postgres password. Random, written once, kept in this file. +POSTGRES_PASSWORD=$(openssl rand -base64 32) + +# Photon Cloud AppIds. Free tier at https://dashboard.photonengine.com +PHOTON_APP_ID=your-photon-realtime-appid +PHOTON_VOICE_APP_ID=your-photon-voice-appid # optional +PHOTON_CLOUD_REGION=eu # eu, us, asia, jp, sa, kr, in, au, etc. + +# Steam Web API key — only needed if you want Steam logins to work. +# Free at https://steamcommunity.com/dev/apikey +STEAM_API_KEY= +``` + +### TLS + +The bundled nginx config terminates TLS but expects certificates to exist +on the host. You have two reasonable paths: + +1. **Caddy in front** (recommended for new hosts) — replace the nginx + service with a Caddyfile; Caddy auto-fetches Let's Encrypt certs. +2. **Cloudflare Tunnel** — DNS your wildcard at Cloudflare, run + `cloudflared` as another container, never expose port 443 to the + internet. The repo includes a sample `docker-compose.cloudflared.yml`. + +### Run it + +```bash +docker compose up -d +docker compose logs -f server +``` + +First boot does: + +1. Schema initialization (`EnsureCreated` from the entity classes) +2. Legacy data upgrades (no-op on a fresh install) +3. Seeds RR-Original rooms + store catalog +4. Applies canonical room overrides (Crescendo, Paintball merge, etc.) +5. Downloads the bundled room thumbnail images + +You should see `[boot] migrations complete` within ~3 seconds. Then the +server is ready at `https://api.your-server.example.com/healthz`. + +## Patching the client to point here + +Same patcher as Easy mode, but you'll run it from the command line: + +```powershell +.\tools\patch-client.ps1 ` + -RecRoomDir "C:\path\to\Recroom_Release" ` + -ServerHost "your-server.example.com" ` + -PhotonAppId "your-photon-realtime-appid" ` + -PhotonRegion "eu" +``` + +## Admin UI + +`https://admin.your-server.example.com` — log in with the first account +you create (it auto-promotes to admin) or with the bootstrap credentials +in your `.env` if you set `BOOTSTRAP_ADMIN_*`. + +## Backups + +Postgres is the only stateful service. + +```bash +docker compose exec postgres pg_dump -U dorknet dorknet > backup.sql +``` + +`data/images/` on the host is the image blob store. Back that up too. + +## Updating + +```bash +cd dorknet +git pull +docker compose pull +docker compose up -d +``` + +The server runs all idempotent migrations on boot, so version upgrades +are zero-downtime as long as the schema changes are additive. diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..d5779cb --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,71 @@ +# Architecture + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ Rec Room 2020.03.10 client (patched) │ +│ ┌────────────────────┐ ┌──────────────────────────────────┐ │ +│ │ IL2CPP game code │ │ MelonLoader + client-mod │ │ +│ │ • set_BaseUri │←───│ • rewrites *.rec.net hosts │ │ +│ │ • Photon client │ │ • injects Photon AppId │ │ +│ │ • BouncyCastle TLS│ │ • bypasses TLS trust check │ │ +│ └─────────┬──────────┘ └──────────────────────────────────┘ │ +└────────────┼─────────────────────────────────────────────────────┘ + │ HTTPS to *.your-server.example.com + ▼ +┌──────────────────────────────────────────────────────────────────┐ +│ DorkNet server (ASP.NET Core) │ +│ │ +│ Subdomain-multiplexed routing: │ +│ api.* → REST endpoints (rooms, players, store, etc.) │ +│ auth.* → OAuth-style /connect/token, /photon/customauth │ +│ accounts.* → /account/bulk, /account/me, /account/{id}/bio │ +│ match.* → /goto/room/*, /player/heartbeat, /roominstance/*│ +│ chat.* → /thread, /thread/{id}/message │ +│ cdn.* → static asset serving (room blobs, images) │ +│ notify.* → SignalR hub for push notifications │ +│ img.* → signed image fetch + on-the-fly resize │ +│ leaderboard.* → /leaderboard/SetStat, GetPlayerRank, etc. │ +│ admin.* → React SPA + /api/admin/v1/* │ +│ │ +│ Storage: │ +│ • Postgres (advanced mode) / SQLite (easy mode) │ +│ • Redis presence cache (advanced) / in-memory (easy) │ +│ • data/images/ — room thumbnails + player polaroids │ +└──────────────┬───────────────────────────────────────────────────┘ + │ + │ The server does NOT host Photon. Players' clients + │ connect to Photon Cloud directly via the AppId + │ the server hands them. + ▼ +┌──────────────────────────────────────────────────────────────────┐ +│ Photon Cloud (external — Exit Games) │ +│ Each Rec Room instance = one Photon room. Photon handles │ +│ realtime sync between clients in the same instance. │ +│ Server only touches Photon to authenticate connections via │ +│ /photon/customauth. │ +└──────────────────────────────────────────────────────────────────┘ +``` + +## Why subdomains? + +The 2020 Rec Room client routes every request through a hardcoded +service map (`RecNet.Core.SendRequest(method, Service.Match, …)`) that +picks a host per service. We mirror the official `*.rec.net` layout so +the watch's URI synthesis works unmodified after a single root-host +rewrite by the client mod. + +## Why SignalR? + +The 2020 client expects WebSocket push notifications from a long-poll-or- +WebSocket "Notifications" service. SignalR's transport negotiation +matches what the client expects after a small DTO-shape wrap; see +`Services/NotificationService.cs`. + +## Why a separate Photon Cloud? + +The 2020 build is tightly coupled to Photon Realtime SDK 4 — replacing it +would mean shipping a custom game client. Using Photon Cloud as-is means +clients talk peer-to-peer through Photon's relay; our server only +witnesses the auth handshake. That's also why voice chat needs a Photon +Voice AppId — voice runs through Photon Voice (a separate service from +Photon Realtime). diff --git a/docs/easy-setup.md b/docs/easy-setup.md new file mode 100644 index 0000000..f1f8527 --- /dev/null +++ b/docs/easy-setup.md @@ -0,0 +1,93 @@ +# Easy mode — host your own server + +> Built for non-technical hosts. If you can install Discord, you can do this. + +## What you'll need + +- A Windows PC (Mac and Linux support coming later) +- A copy of **Rec Room 2020.03.10** — the specific old build DorkNet targets. + You acquire this yourself; see [Getting the 2020 client](#getting-the-2020-client) below. +- ~5 GB free disk space +- About 10 minutes + +## Step 1 — Download DorkNet + +Grab `dorknet.exe` from the [latest release](https://github.com/YOUR_GH_USERNAME/dorknet/releases/latest). + +> Windows SmartScreen may warn you. The exe is code-signed; click "More info" +> → "Run anyway". + +## Step 2 — First launch + +When you open DorkNet for the first time, you'll see a welcome screen +asking what you want to do. + +![first-run welcome screen](images/first-run-welcome.png) + +Click **🏠 Host a server**. + +## Step 3 — Patch your Rec Room install + +DorkNet needs to redirect Rec Room to talk to your server instead of the +official one. This is a one-time patch. + +1. Click the **Patch game** tab. +2. Click **Browse for Rec Room install...** — point it at the folder where + `Recroom_Release.exe` lives. +3. Click **Patch**. Takes 30 seconds. + +![patch tab](images/patch-tab.png) + +✅ You're done with patching. You won't need to do this again unless you +reinstall Rec Room. + +## Step 4 — Start the server + tunnel + +1. Click **Start server** on the Status tab. +2. After ~5 seconds you'll see a public URL like + `https://abc-def-ghi.trycloudflare.com`. Anyone with that URL + a + matching join code can connect to you. + +![status tab running](images/status-running.png) + +## Step 5 — Share the join code with your friends + +1. Click the **Share** tab. +2. Click **Copy join code**. +3. Paste it to your friend in Discord / iMessage / wherever. + +That's it for hosting. Your friend opens DorkNet, picks "Join a server", +pastes the code, and they're in. + +--- + +## Getting the 2020 client + +DorkNet doesn't ship the Rec Room game itself — that's Rec Room Inc.'s +intellectual property. You acquire your own copy through legal means. + +Common paths: +- If you bought Rec Room on Steam before 2020, you can use SteamDB depot + tools to download the old build (manifest `4651244957411961725` for + `Recroom_Release_Data`). +- Friends who already have a 2020 install can share files with you under + whatever license terms apply on their end. + +DorkNet's authors can't help you obtain the game. Search the web for +"Steam depot 2020.03.10 Rec Room" if you need pointers. + +--- + +## Troubleshooting + +See [troubleshooting.md](troubleshooting.md) for common issues. + +The most common ones: +- **"This site can't be reached" when joining** — your tunnel URL changed. + Get the new one from the Status tab and share it again. (Cloudflare + Quick Tunnels give a new URL each session. See + [advanced-setup.md](advanced-setup.md) if you want a stable one.) +- **Friend can't connect** — they need to use the same Photon region as + you. Settings → Photon region. Default is `eu`. +- **Game launches but stays on the loading screen** — your friend isn't + patched. Make sure they ran the Patch tab in their copy of DorkNet. diff --git a/docs/faq.md b/docs/faq.md new file mode 100644 index 0000000..f9fc3ed --- /dev/null +++ b/docs/faq.md @@ -0,0 +1,90 @@ +# FAQ + +### Is this legal? + +The DorkNet code itself is original and AGPL-licensed. The Rec Room game +client is not ours — you supply your own copy that you've legally +acquired. The patcher runs locally on your machine and never uploads +modified game files anywhere. + +DorkNet's authors don't ship Rec Room IP and don't help users obtain it. +See [DISCLAIMER.md](../DISCLAIMER.md) for the full position. + +### Will Rec Room Inc. shut this down? + +Possibly. Fan-server projects exist in a grey zone. AGPL doesn't shield +from DMCA. We minimize friction by never distributing Rec Room IP, never +interfering with their live servers, and being explicit that this is for +educational / private use only. + +### Why the 2020 build specifically? Will newer versions work? + +2020.03.10 is the last build before Rec Room shipped server-side +ObscuredInt anti-cheat changes that would require deeper client patching. +It's old enough to be effectively abandonware on Rec Room's roadmap, new +enough to have most of the features people remember. + +Newer builds (any Rec Room from late 2020 onward) aren't supported and +won't be without significant additional reverse-engineering. PRs that +add support for newer builds are welcome but expect scope creep. + +### Can I run a public server that anyone can join? + +Technically yes (just disable signup-disabled in admin settings). Legally +risky — see the C&D answer above. Realistically, "public" private +servers attract attention and shorten the project's lifespan. + +We recommend keeping servers small (friends + community), private +(invite-only signups), and not advertised. + +### Will mobile / Junior accounts work? + +Mobile binaries from 2020 are platform-locked to App Store / Play Store +servers and can't easily be retargeted. Quest standalone is possible in +principle but hasn't been validated. + +Junior accounts work but DorkNet patches out the chat-permission gate by +default since on a private server with friends, the chat moderation +plumbing is overkill. Toggle in admin → Server settings if you need it. + +### Does this work with Quest VR? + +Desktop VR via SteamVR works. Standalone Quest builds aren't easily +patchable (sideloaded APK signing is its own world). Quest Link / Air +Link puts you back in the SteamVR case, which works. + +### How many players can one server handle? + +- **Easy mode (SQLite, single-instance)**: ~30 concurrent players in + practice. Photon does the heavy realtime lifting; the bottleneck is the + server's SignalR fanout + DB writes, both of which SQLite struggles + with past ~50. +- **Advanced mode (Postgres + Redis + multi-replica)**: tested at 200+ + in dev. Real bottleneck becomes Photon AppId quotas at that point. + +### Can I federate multiple DorkNet servers? + +Not supported and not planned. Each server has its own account database; +players are server-local. Same as classic Minecraft realms. + +### Is there a Discord? + +No official one yet. If you start a community, link it from your fork. + +### What about voice chat? + +Routes through Photon Voice. You'll need a (free) Photon Voice AppId +separate from your Photon Realtime AppId. Set `PHOTON_VOICE_APP_ID` in +the server config; the client mod handles the rest. + +### My friend can't connect + +Most common causes, in order: +1. **Tunnel URL stale.** Cloudflare Quick Tunnels rotate the URL on each + restart. Re-share the join code. +2. **Photon region mismatch.** Both clients must use the same Photon + region — set in Settings. +3. **Friend didn't patch.** They need to run the Patch tab pointed at + their own Rec Room install, with your join code. +4. **Junior account / accessibility settings.** Server settings → relax + moderation gates if friends are on accounts with parental controls. diff --git a/docs/joining-a-server.md b/docs/joining-a-server.md new file mode 100644 index 0000000..d4ab35f --- /dev/null +++ b/docs/joining-a-server.md @@ -0,0 +1,67 @@ +# Joining someone's DorkNet server + +> Built for players whose friend already runs a server and gave them a +> code. If you want to *host* instead, see [easy-setup.md](easy-setup.md). + +## What you'll need + +- A Windows PC +- A copy of **Rec Room 2020.03.10** (your own — see + [Getting the 2020 client](easy-setup.md#getting-the-2020-client)) +- The join code your friend gave you (looks like `dorknet://join?...`) +- About 2 minutes + +## Step 1 — Download DorkNet + +Grab `dorknet.exe` from the [latest release](https://github.com/YOUR_GH_USERNAME/dorknet/releases/latest). + +## Step 2 — First launch + +On the welcome screen, click **🎮 Join a server**. + +![first-run welcome screen — Join selected](images/first-run-welcome-join.png) + +## Step 3 — Paste the join code + +Your friend's code goes in the big text box. DorkNet decodes it and shows +you what you're about to connect to so you can sanity-check: + +![join code preview](images/join-preview.png) + +Make sure the server name matches what your friend told you. Codes from +strangers can point anywhere — only paste codes from people you trust. + +## Step 4 — Patch your Rec Room install + +1. Click **Browse for Rec Room install...** — point at the folder with + `Recroom_Release.exe`. +2. Click **Patch & launch**. + +DorkNet patches the game (one-time), then launches it pointed at your +friend's server. You'll see the normal Rec Room login screen, log in with +the account you made on your friend's server, and you're in. + +--- + +## I already patched for a different server. Can I switch? + +Yes — DorkNet's patcher is reversible. Click **Repair / unpatch** in the +Patch tab to undo, then re-patch with a new join code. Or just re-run +**Patch & launch** with the new code; the patcher detects an existing +patch and updates the destination. + +## My account doesn't exist on the new server + +Each DorkNet server runs its own account database. You'll need to create +a new account the first time you join a server. Your friend can sign you +up via their admin panel, or you can use the in-game "Create account" +flow if the server has signups enabled. + +## Voice chat doesn't work + +Voice routes through Photon Voice, which requires a separate Photon Voice +AppId. If your friend hasn't set one up, voice chat is text-only for now. + +## More troubleshooting + +See [troubleshooting.md](troubleshooting.md). diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md new file mode 100644 index 0000000..49d547a --- /dev/null +++ b/docs/troubleshooting.md @@ -0,0 +1,96 @@ +# Troubleshooting + +If your symptom isn't here, check [the FAQ](faq.md) and then open an +issue with: your OS, DorkNet version, server log (Settings → Send logs +to clipboard), and the exact steps that triggered the problem. + +## Client / patcher + +### "Signature verification failed" on launch + +The image-signing public key baked into the patched `global-metadata.dat` +doesn't match the private key on the server. Repair from the Patch tab — +this re-fetches the server's current pubkey before patching. + +### "Check your internet connection" loop at startup + +The watch can't reach the server URL. Verify: +1. The host string in `dorknet-clientmod.json` matches the server's + public URL (tunnel URL for Easy mode). +2. The server responds to `https:///healthz` with `200 OK` from + the same machine the client runs on. +3. No corporate proxy / DNS filter is intercepting `*.trycloudflare.com`. + +### Black screen after the loading bar fills + +The watch authenticated, joined Photon, but couldn't download the room +data blob. Look in MelonLoader's `Latest.log` for +`[DownloadRoomDataBlobCoroutine]` lines — the URL there tells you which +asset the server failed to serve. + +### Save doesn't persist, MakerPen objects disappear after reload + +Known issue with stale `LocalRoomScene.DataBlobName`. The client mod's +`SetRoomDataBlobName_Prefix` hijack should handle this — verify it's +firing in MelonLoader's log. If not, the mod failed to load; check that +`Mods\DorkNet.ClientMod.dll` is present and not blocked by Windows. + +## Server + +### `[boot] migrations failed` + +The schema patch SQL errored. Most likely cause: an existing column whose +type doesn't match what we're trying to add. Look at the exact failure +in the log; if it's a Postgres `cannot alter type` error, the prior +column type needs a manual migration before DorkNet starts. + +### Photon CustomAuth returns 401 + +Either: +- The Photon AppId in `appsettings` doesn't match the AppId baked into + the patched client. They MUST match. +- The user logging in doesn't have a row in the `Players` table — the + auth flow expects `userid` to be a real account. + +### Room chat doesn't send + +Run the client with `SaveDebugMod` enabled (or watch MelonLoader's log) +and look for the `[chat-trace]` lines. The pipeline is: + +``` +SendChatEmote → RemoveInvalidCharactersFromMessage → PurifyString HTTP + → ProcessNewChatMessageReceived → Photon RPC +``` + +If any trace line is missing, that's where it died. The two most common +fixes: +- `[chat-fix] CanLocalPlayerChat returned false`: the account is flagged + as a Junior with chat disabled. Force-true via the client mod (default + behavior) or fix it server-side in admin. +- `Received malformed RecNet response`: the `/api/sanitize/v1` endpoint + returned the wrong shape. Should be a bare JSON-quoted string. See + `SanitizeController.cs`. + +## Easy app + +### "Cloudflared exited unexpectedly" + +The bundled `cloudflared.exe` couldn't start. Most likely a Windows +Defender false-positive — check Defender's quarantine. If you find a +cleaner alternative tunnel provider, open an issue; we've been looking +for one. + +### Patch button is greyed out + +DorkNet didn't find a Rec Room install at the path you selected. Make +sure you pointed at the *folder* containing `Recroom_Release.exe`, not +the exe itself, and that `Recroom_Release_Data/` exists alongside. + +### Mode switch lost my server data + +Switching from Host mode → Join mode preserves the SQLite database; it +just stops auto-starting the server. Switch back to Host mode and your +players / rooms / images are still there. + +If the data really is gone, check `%APPDATA%\DorkNet\dorknet.db` — that +file is the entire host-side state, easy to copy elsewhere as a backup. diff --git a/easy-app/README.md b/easy-app/README.md new file mode 100644 index 0000000..af6894d --- /dev/null +++ b/easy-app/README.md @@ -0,0 +1,112 @@ +# DorkNet Easy App + +The unified desktop app for hosts and guests. One binary, two modes. + +## Project layout + +``` +easy-app/ +├── Shell/ PhotinoNET window host, mode router, settings store, +│ auto-updater, system tray, log viewer. +├── HostMode/ Tunnel manager (cloudflared wrapper), server lifecycle +│ (start/stop the in-process ASP.NET Core), share-code +│ generation. +├── JoinMode/ Join-code parser (dorknet:// URL handler), connection +│ sanity-check, server reachability ping. +├── Shared/ Patcher library (port of tools/patch-client.ps1 to C#), +│ ConfigManager, RecRoomInstallFinder (Steam library scan), +│ ImageSigningKeyManager (auto-generate on first run). +└── Resources/ Icons, admin-ui dist (bundled at build time), + cloudflared.exe, MelonLoader/, mod DLLs. +``` + +## Build flow + +`Resources/admin-ui-dist/` is the production build output from +`../admin-ui/` — copied in by a pre-build task so the Photino webview can +serve it as the host-mode admin tab. + +```pwsh +# One-shot dev build +pwsh tools/build-easy-app.ps1 + +# Release artifact +dotnet publish easy-app -c Release -r win-x64 --self-contained \ + -p:PublishSingleFile=true -p:PublishTrimmed=false +# → bin/Release/net9.0/win-x64/publish/dorknet.exe (~80 MB) +``` + +## Why PhotinoNET + +- The admin UI is already a webview-friendly React SPA. Embedding it in a + Photino window is essentially free. +- Single .NET project. No Node toolchain in the desktop build, no Electron. +- Bundled binary ~50 MB before the runtime, ~80 MB with self-contained + .NET. Acceptable for one-time downloads. + +## Why not Electron / Tauri / Avalonia + +- **Electron**: doubles the binary size, adds Node into the supply chain. +- **Tauri**: Rust dependency we don't otherwise need; mixing it with the + existing .NET server complicates the build matrix. +- **Avalonia**: native, beautiful, but means re-implementing the admin + UI a second time. The point of unified Host mode is *reuse* the admin + SPA verbatim. + +## Modes — first-run decision + +`Shared/ConfigManager` writes `%APPDATA%\DorkNet\mode.json`: + +```json +{ "mode": "host" } +``` + +`Shell` reads this on startup. Missing or `null` → first-run wizard. +Settings → "Switch mode" sets `mode` to the other value, restarts the +process clean (Photino re-init). + +## Host mode lifecycle + +1. User clicks Start server. +2. `HostMode.ServerLauncher` boots the ASP.NET Core host in-process, + wired to a SQLite DB at `%APPDATA%\DorkNet\dorknet.db`. +3. `HostMode.TunnelManager` spawns `cloudflared tunnel --url + http://localhost:5000`, reads the public URL off stderr. +4. UI surfaces the URL + a "Copy join code" button. Join code is + base64(`{host, photonAppId, photonRegion, name}`). + +## Join mode lifecycle + +1. User pastes a join code (or clicks a `dorknet://` URL — the installer + registers the protocol handler). +2. `JoinMode.CodeParser` decodes, ping-checks the host, shows a + "Connecting to X" preview. +3. User points at their Rec Room install (auto-detected via + `RecRoomInstallFinder` if Steam owns it). +4. `Shared.Patcher` patches `global-metadata.dat`, drops MelonLoader, + writes `dorknet-clientmod.json` with the decoded host + Photon AppId. +5. UI offers a "Launch Rec Room" button — runs `Recroom_Release.exe` + directly, no Steam intermediary needed. + +## Auto-updates + +[Velopack](https://velopack.io) is the path of least resistance for .NET +desktop. Drop-in: declare a GitHub Release feed, ship updates as deltas. + +## Testing + +QA matrix to maintain: +- Fresh Windows 10 VM, no Rec Room → install Steam → buy / depot-download + the 2020 build → DorkNet host mode → patch + start + tunnel → connect + from a second VM via Join mode. End-to-end smoke test. +- Mac M1 + Linux: deferred. PhotinoNET supports them but we need separate + cloudflared binaries and a packaging step per OS. + +## Open questions + +- [ ] Code-signing cert. SmartScreen warning is a major adoption friction. + EV cert is ~$200/yr; standard cert is cheaper but takes longer to build + reputation. +- [ ] Crash reporting. Sentry has a generous free tier and a clean .NET SDK. +- [ ] Telemetry — opt-in? Off by default? Right now: no plans, but + document the position so contributors know. diff --git a/server/README.md b/server/README.md new file mode 100644 index 0000000..2195600 --- /dev/null +++ b/server/README.md @@ -0,0 +1,57 @@ +# server/ + +The ASP.NET Core backend. + +Built two ways: +- **Standalone Postgres-backed** for advanced mode (Docker), via + `dotnet run` or the `dorknet-server` container. +- **In-process SQLite-backed** for the Easy desktop app, hosted as a + library inside `easy-app/`. + +## Code layout (TBC) + +``` +server/ +├── Controllers/ HTTP endpoints, sliced by subdomain → service +├── Services/ Business logic (presence, notifications, levels, ...) +├── Hubs/ SignalR NotifyHub +├── Data/ DbContext + EntityFramework entity classes +├── Auth/ JWT issuance, Photon CustomAuth handler +├── Middleware/ SubdomainRouter, request logging, error handling +└── Program.cs Boot: migrations, seeds, canonical overrides, DI +``` + +## Building + +```bash +dotnet build -c Release +dotnet run # localhost:5000 +``` + +## Provider switch + +The DbContext is provider-agnostic. `appsettings` picks one: + +```jsonc +{ + "ConnectionStrings": { + // Postgres for advanced mode + "Default": "Host=localhost;Database=dorknet;Username=dorknet;Password=..." + // OR SQLite for easy mode + // "Default": "Data Source=dorknet.db" + }, + "Database": { + "Provider": "Postgres" // or "Sqlite" + } +} +``` + +Easy app boots with `Provider=Sqlite` baked in; standalone defaults to +`Provider=Postgres`. + +## See also + +- [docs/architecture.md](../docs/architecture.md) — request flow, + subdomain routing, Photon relationship +- [docs/advanced-setup.md](../docs/advanced-setup.md) — production setup +- [CONTRIBUTING.md](../CONTRIBUTING.md) — style + PR rules diff --git a/tools/README.md b/tools/README.md new file mode 100644 index 0000000..eebb7a6 --- /dev/null +++ b/tools/README.md @@ -0,0 +1,10 @@ +# tools/ + +CLI helpers. Most users don't need to touch these — the desktop app +wraps the same logic with a UI. + +| Script | Purpose | +| -------------------- | ------------------------------------------------------ | +| `patch-client.ps1` | Patch a Rec Room install to talk to your DorkNet server. The desktop app wraps this in a UI; CLI path is for advanced-mode hosts. | +| `dump-il2cpp.ps1` | Run Cpp2IL against a Rec Room install to produce the decompiled dumps the project uses for reverse-engineering. Output stays on your machine — never committed. | +| `build-easy-app.ps1` | Build the unified desktop app (`dorknet.exe`). Self-contained .NET single-file publish. |