├── .editorconfig ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── behavior-bug.yml │ ├── config.yml │ ├── feature-request.yml │ ├── performance-problems.yml │ └── server-crash-or-stacktrace.yml └── workflows │ └── build.yml ├── .gitignore ├── PATCHES-LICENSE ├── PROJECT_DESCRIPTION.md ├── README.md ├── REGION_LOGIC.md ├── build-data ├── dev-imports.txt └── reobf-mappings-patch.tiny ├── build.gradle.kts ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── install.bat ├── jar.bat ├── paperrecorder.png ├── patch.bat ├── patches └── server │ ├── 0001-Build-changes.patch │ ├── 0002-ServerSideRecorder.patch │ ├── 0003-ServerSideRecorder.patch │ ├── 0004-ServerSideRecorder.patch │ ├── 0005-ServerSideRecorder.patch │ ├── 0006-ServerSideRecorder.patch │ ├── 0007-ServerSideRecorder.patch │ ├── 0008-ServerSideRecorder.patch │ ├── 0009-ServerSideRecorder.patch │ ├── 0010-ServerSideRecorder.patch │ ├── 0011-ServerSideRecorder.patch │ ├── 0012-ServerSideRecorder.patch │ ├── 0013-ServerSideRecorder.patch │ ├── 0014-ServerSideRecorder.patch │ ├── 0015-ServerSideRecorder.patch │ ├── 0016-ServerSideRecorder.patch │ ├── 0017-ServerSideRecorder.patch │ ├── 0018-ServerSideRecorder.patch │ ├── 0019-ServerSideRecorder.patch │ ├── 0020-ServerSideVoiceChat.patch │ ├── 0021-ServerSideVoiceChat.patch │ ├── 0022-ServerSideVoiceChat.patch │ ├── 0023-Improved-Performance-For-Simple-Voice-Chat.patch │ ├── 0024-Improved-Performance-For-Simple-Voice-Chat.patch │ ├── 0025-Support-Region-Voice-Recording.patch │ ├── 0026-Support-Region-Voice-Recording.patch │ ├── 0027-Support-Region-Voice-Recording.patch │ ├── 0028-Support-Region-Voice-Recording.patch │ ├── 0029-Support-Region-Voice-Recording.patch │ ├── 0030-Support-Region-Voice-Recording.patch │ ├── 0031-Support-Region-Voice-Recording.patch │ ├── 0032-Support-Region-Voice-Recording.patch │ ├── 0033-Support-Region-Voice-Recording.patch │ └── 0034-Support-Region-Voice-Recording.patch ├── rb.bat ├── regiontodo.txt └── settings.gradle.kts /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.java] 2 | charset=utf-8 3 | end_of_line=lf 4 | insert_final_newline=true 5 | indent_style=space 6 | indent_size=4 7 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | 3 | *.sh text eol=lf 4 | gradlew text eol=lf 5 | *.bat text eol=crlf 6 | 7 | *.jar binary 8 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/behavior-bug.yml: -------------------------------------------------------------------------------- 1 | name: Behavior Bug 2 | description: Report behavior related issues, where Folia does not work like vanilla. Paper and Bukkit plugins are not guaranteed to work on Folia. Do not submit bug reports for plugin issues here. 3 | labels: [ "status: needs triage", "type: bug" ] 4 | body: 5 | - type: textarea 6 | attributes: 7 | label: Expected behavior 8 | description: What you expected to see. 9 | validations: 10 | required: true 11 | 12 | - type: textarea 13 | attributes: 14 | label: Observed/Actual behavior 15 | description: What you actually saw. 16 | validations: 17 | required: true 18 | 19 | - type: textarea 20 | attributes: 21 | label: Steps/models to reproduce 22 | description: This may include a build schematic, a video, or detailed instructions to help reconstruct the issue. 23 | validations: 24 | required: true 25 | 26 | - type: textarea 27 | attributes: 28 | label: Plugin and Datapack List 29 | description: | 30 | All plugins and datapacks running on your server. 31 | To list plugins, run `/plugins`. For datapacks, run `/datapack list`. 32 | validations: 33 | required: true 34 | 35 | - type: textarea 36 | attributes: 37 | label: Folia version 38 | description: | 39 | Run `/version` on your server and **paste** the full, unmodified output here. 40 | "latest" is *not* a version; we require the output of `/version` so we can adequately track down the issue. 41 | Additionally, do NOT provide a screenshot, you MUST paste the entire output. 42 |
43 | Example 44 | 45 | ``` 46 | > version 47 | [10:00:11 INFO]: Checking version, please wait... 48 | [10:00:12 INFO]: This server is running Folia version git-Folia-"5b74945" (MC: 1.19.4) (Implementing API version 1.19.4-R0.1-SNAPSHOT) (Git: 5b74945) 49 | You are running the latest version 50 | Previous version: git-Paper-481 (MC: 1.19.4) 51 | ``` 52 | 53 |
54 | validations: 55 | required: true 56 | 57 | - type: textarea 58 | attributes: 59 | label: Other 60 | description: | 61 | Please include other helpful information below. 62 | The more information we receive, the quicker and more effective we can be at finding the solution to the issue. 63 | validations: 64 | required: false 65 | 66 | - type: markdown 67 | attributes: 68 | value: | 69 | Before submitting this issue, please ensure the following: 70 | 71 | 1. You are running the latest version of Folia from [our downloads page](https://papermc.io/downloads). 72 | 2. You searched for and ensured there isn't already an open issue regarding this. 73 | 3. Your version of Minecraft is supported by Folia. 74 | 75 | If you think you have a bug but are not sure, feel free to ask the `#folia-help` channel of our 76 | [Discord](https://discord.gg/papermc). 77 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: PaperMC Discord 4 | url: https://discord.gg/papermc 5 | about: If you are having minor issues, come ask us on our Discord server! 6 | - name: Exploit Report 7 | url: https://discord.gg/papermc 8 | about: | 9 | Due to GitHub not currently allowing private issues, exploit reports are currently handled via our Discord. 10 | To report an exploit, see the #paper-exploit-report channel. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.yml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: Suggest an idea for Folia 3 | labels: [ "status: needs triage", "type: feature" ] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | Thank you for filling out a feature request for Folia! Please be as detailed as possible so that we may consider and review the request easier. 9 | We ask that you search all the issues to avoid a duplicate feature request. If one exists, please reply if you have anything to add. 10 | Before requesting a new feature, please make sure you are using the latest version and that the feature you are requesting is not already in Folia. 11 | 12 | - type: textarea 13 | attributes: 14 | label: Is your feature request related to a problem? 15 | description: Please give some context for this request. Why do you want it added? 16 | validations: 17 | required: true 18 | 19 | - type: textarea 20 | attributes: 21 | label: Describe the solution you'd like. 22 | description: A clear and concise description of what you want. 23 | validations: 24 | required: true 25 | 26 | - type: textarea 27 | attributes: 28 | label: Describe alternatives you've considered. 29 | description: List any alternatives you might have tried to get the feature you want. 30 | validations: 31 | required: true 32 | 33 | - type: textarea 34 | attributes: 35 | label: Other 36 | description: Add any other context or screenshots about the feature request below. 37 | validations: 38 | required: false 39 | 40 | - type: markdown 41 | attributes: 42 | value: | 43 | Before submitting this feature request, please search our issue tracker to ensure your feature has not 44 | already been requested. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/performance-problems.yml: -------------------------------------------------------------------------------- 1 | name: Performance Problem 2 | description: Report performance related problems or other areas of concern 3 | labels: [ "status: needs triage", "type: performance" ] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | Before creating an issue regarding server performance, please consider reaching out for support in the 9 | `#folia-help` channel of [our Discord](https://discord.gg/papermc)! 10 | 11 | - type: input 12 | attributes: 13 | label: Profile link 14 | description: We ask that all profiles are a link, not a screenshot. Screenshots inhibit our ability to figure out the real cause of the issue. 15 | placeholder: "Example: https://spark.lucko.me/abcdefg12h" 16 | validations: 17 | required: true 18 | 19 | - type: textarea 20 | attributes: 21 | label: Description of issue 22 | description: If applicable, please describe your issue. 23 | validations: 24 | required: false 25 | 26 | - type: textarea 27 | attributes: 28 | label: Plugin and Datapack List 29 | description: | 30 | All plugins and datapacks running on your server. 31 | To list plugins, run `/plugins`. For datapacks, run `/datapack list`. 32 | validations: 33 | required: true 34 | 35 | - type: textarea 36 | attributes: 37 | label: Server config files 38 | description: We need bukkit.yml, spigot.yml, paper-global.yml, paper-world-defaults.yml and server.properties. If you use per-world Paper configs, make sure to include them. You can paste it below or use a paste site like https://paste.gg. 39 | value: | 40 | ``` 41 | Paste configs or paste.gg link here! 42 | ``` 43 | placeholder: Please don't remove the backticks; it makes your issue a lot harder to read! 44 | validations: 45 | required: true 46 | 47 | - type: textarea 48 | attributes: 49 | label: Folia version 50 | description: | 51 | Run `/version` on your server and **paste** the full, unmodified output here. 52 | "latest" is *not* a version; we require the output of `/version` so we can adequately track down the issue. 53 | Additionally, do NOT provide a screenshot, you MUST paste the entire output. 54 |
55 | Example 56 | 57 | ``` 58 | > version 59 | [10:00:11 INFO]: Checking version, please wait... 60 | [10:00:12 INFO]: This server is running Folia version git-Folia-"5b74945" (MC: 1.19.4) (Implementing API version 1.19.4-R0.1-SNAPSHOT) (Git: 5b74945) 61 | You are running the latest version 62 | Previous version: git-Paper-481 (MC: 1.19.4) 63 | ``` 64 | 65 |
66 | validations: 67 | required: true 68 | 69 | - type: textarea 70 | attributes: 71 | label: Other 72 | description: | 73 | Please include other helpful links below. 74 | The more information we receive, the quicker and more effective we can be at finding the solution to the issue. 75 | validations: 76 | required: false 77 | - type: markdown 78 | attributes: 79 | value: | 80 | Before submitting this issue, please ensure the following: 81 | 82 | 1. You are running the latest version of Folia from [our downloads page](https://papermc.io/downloads). 83 | 2. You searched for and ensured there isn't already an open issue regarding this. 84 | 3. Your version of Minecraft is supported by Folia. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/server-crash-or-stacktrace.yml: -------------------------------------------------------------------------------- 1 | name: Server crash or Stacktrace 2 | description: Report server crashes or scary stacktraces 3 | labels: [ "status: needs triage" ] 4 | body: 5 | - type: textarea 6 | attributes: 7 | label: Stack trace 8 | description: | 9 | We need all of the stack trace! Do not cut off parts of it. Please do not use attachments. 10 | If you prefer, you can use a paste site like https://paste.gg. 11 | value: | 12 | ``` 13 | paste your stack trace or a paste.gg link here! 14 | ``` 15 | placeholder: Please don't remove the backticks; it makes your issue a lot harder to read! 16 | validations: 17 | required: true 18 | 19 | - type: textarea 20 | attributes: 21 | label: Plugin and Datapack List 22 | description: | 23 | All plugins and datapacks running on your server. 24 | To list plugins, run `/plugins`. For datapacks, run `/datapack list`. 25 | validations: 26 | required: true 27 | 28 | - type: textarea 29 | attributes: 30 | label: Actions to reproduce (if known) 31 | description: This may include a build schematic, a video, or detailed instructions to help reconstruct the issue. Anything helps! 32 | validations: 33 | required: false 34 | 35 | - type: textarea 36 | attributes: 37 | label: Folia version 38 | description: | 39 | Run `/version` on your server and **paste** the full, unmodified output here. 40 | "latest" is *not* a version; we require the output of `/version` so we can adequately track down the issue. 41 | Additionally, do NOT provide a screenshot, you MUST paste the entire output. 42 |
43 | Example 44 | 45 | ``` 46 | > version 47 | [10:00:11 INFO]: Checking version, please wait... 48 | [10:00:12 INFO]: This server is running Folia version git-Folia-"5b74945" (MC: 1.19.4) (Implementing API version 1.19.4-R0.1-SNAPSHOT) (Git: 5b74945) 49 | You are running the latest version 50 | Previous version: git-Paper-481 (MC: 1.19.4) 51 | ``` 52 | 53 |
54 | validations: 55 | required: true 56 | 57 | - type: textarea 58 | attributes: 59 | label: Other 60 | description: | 61 | Please include other helpful information below, if any. 62 | The more information we receive, the quicker and more effective we can be at finding the solution to the issue. 63 | validations: 64 | required: false 65 | 66 | - type: markdown 67 | attributes: 68 | value: | 69 | Before submitting this issue, please ensure the following: 70 | 71 | 1. You are running the latest version of Folia from [our downloads page](https://papermc.io/downloads). 72 | 2. Your version of Minecraft is supported by Folia. 73 | 74 | If your server crash log contains `DO NOT REPORT THIS TO FOLIA`, please ask in our 75 | [Discord](https://discord.gg/papermc) before opening this issue. These messages are informing you of server 76 | lag and providing debug information. -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Patch and Build 2 | 3 | on: 4 | push: 5 | branches: [ "**"] 6 | pull_request: 7 | 8 | jobs: 9 | build: 10 | # Only run on PRs if the source branch is on someone else's repo 11 | if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }} 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checking Environment 15 | run: | 16 | echo "Compile_Date=$(date +%Y%m%d%H%M)" >> $GITHUB_ENV 17 | - name: Checkout Git Repository 18 | uses: actions/checkout@v3 19 | - name: Validate Gradle wrapper 20 | uses: gradle/wrapper-validation-action@v1 21 | - name: Setup Gradle 22 | uses: gradle/gradle-build-action@v2 23 | - name: Set up JDK 24 | uses: actions/setup-java@v3 25 | with: 26 | distribution: 'temurin' 27 | java-version: '17' 28 | - name: Configure Git User Details 29 | run: git config --global user.email "actions@github.com" && git config --global user.name "Github Actions" 30 | - name: Apply Patches 31 | run: ./gradlew applyPatches 32 | - name: Build Bundler & Paperclip 33 | run: ./gradlew createReobfBundlerJar 34 | - name: capture build artifacts 35 | uses: actions/upload-artifact@v2 36 | with: 37 | name: Artifacts 38 | path: build/libs/ 39 | - name: Create Release Tag 40 | uses: rickstaa/action-create-tag@v1 41 | with: 42 | tag: "v1_20_1-${{ env.Compile_Date }}" 43 | message: "1.20.1 Build ${{ env.Compile_Date }}" 44 | - name: Upload Build to Release 45 | uses: svenstaro/upload-release-action@v2 46 | with: 47 | repo_token: ${{ secrets.GITHUB_TOKEN }} 48 | file: build/libs/* 49 | file_glob: true 50 | tag: "v1_20_1-${{ env.Compile_Date }}" 51 | release_name: "1.20.1_PaperRecord-${{ env.Compile_Date }}" 52 | overwrite: true 53 | prerelease: false 54 | body: | 55 | PaperRecord Build 56 | Version: 1.20.1 57 | Build Time: ${{ env.Compile_Date }} 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle/ 2 | build/ 3 | 4 | # Eclipse stuff 5 | .classpath 6 | .project 7 | .settings/ 8 | 9 | # VSCode stuff 10 | .vscode/ 11 | 12 | # netbeans 13 | nbproject/ 14 | nbactions.xml 15 | 16 | # we use maven! 17 | build.xml 18 | 19 | # maven 20 | target/ 21 | dependency-reduced-pom.xml 22 | 23 | # vim 24 | .*.sw[a-p] 25 | 26 | # various other potential build files 27 | build/ 28 | bin/ 29 | dist/ 30 | manifest.mf 31 | 32 | # Mac filesystem dust 33 | .DS_Store/ 34 | .DS_Store 35 | 36 | # intellij 37 | *.iml 38 | *.ipr 39 | *.iws 40 | .idea/ 41 | out/ 42 | 43 | # Linux temp files 44 | *~ 45 | 46 | # other stuff 47 | run/ 48 | 49 | Folia-Server 50 | Folia-API 51 | PaperRecord-Server 52 | PaperRecord-API 53 | 54 | !gradle/wrapper/gradle-wrapper.jar 55 | -------------------------------------------------------------------------------- /PATCHES-LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2022 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /PROJECT_DESCRIPTION.md: -------------------------------------------------------------------------------- 1 | # Project overview 2 | 3 | This page has been moved to [the PaperMC documentation](https://docs.papermc.io/folia/reference/overview) site. 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |

4 |

PaperRecorder

5 |
6 | 7 | 8 | ## Overview 9 | PaperRecorder for 1.20.1 is a Fork of paper allowing players to record players and replay it using the replay mod.
10 | Original Mod for ServerSideReplayRecorder https://github.com/thecolonel63/server-side-replay-recorder 11 | 12 | ## Commands 13 | **/replay players (add|remove|list)** - Add/list/remove players to/from the blacklist/whitelist
14 | **/replay status** - Show the active recording list as well as if recording is enabled
15 | **/replay status (enable|disable)** - Toggle recording across entire mod
16 | **/replay region (start|stop|status)** - Enable recording of a pre-defined large area independent of players
17 | **/replay file (player|region)** - Delete / Upload replay files without manually accessing the replay folder
18 | **/replay marker (player|region)** - Add a marker to the specified replay file
19 | 20 | ## Config 21 | Config is in **/config/ServerSideReplayRecorder.yml** 22 | 23 | # Compatibility 24 | This Paper Fork is compatible with [Simple Voice Chat](https://modrinth.com/plugin/simple-voice-chat). 25 | To use please download the [Simple Voice Chat](https://modrinth.com/plugin/simple-voice-chat) plugin for Bukkit and install in the plugins folder 26 | and PaperRecorder will take care of the rest. To hear the voices in the [Replay Mod](https://modrinth.com/mod/replaymod) please download 27 | [Replay Voice Chat](https://modrinth.com/mod/replay-voice-chat) 28 | 29 | ## License 30 | The PATCHES-LICENSE file describes the license for api & server patches, 31 | found in `./patches` and its subdirectories except when noted otherwise. 32 | 33 | The fork is based off of PaperMC's fork example found [here](https://github.com/PaperMC/paperweight-examples). 34 | As such, it contains modifications to it in this project, please see the repository for license information 35 | of modified files. 36 | -------------------------------------------------------------------------------- /REGION_LOGIC.md: -------------------------------------------------------------------------------- 1 | # Region Logic 2 | 3 | This page has been moved to [the PaperMC documentation](https://docs.papermc.io/folia/reference/region-logic) site. 4 | -------------------------------------------------------------------------------- /build-data/dev-imports.txt: -------------------------------------------------------------------------------- 1 | # You can use this file to import files from minecraft libraries into the project 2 | # format: 3 | # 4 | # both fully qualified and a file based syntax are accepted for : 5 | # authlib com/mojang/authlib/yggdrasil/YggdrasilGameProfileRepository.java 6 | # datafixerupper com.mojang.datafixers.DataFixerBuilder 7 | # datafixerupper com/mojang/datafixers/util/Either.java 8 | # To import classes from the vanilla Minecraft jar use `minecraft` as the artifactId: 9 | # minecraft net.minecraft.world.level.entity.LevelEntityGetterAdapter 10 | # minecraft net/minecraft/world/level/entity/LevelEntityGetter.java 11 | -------------------------------------------------------------------------------- /build-data/reobf-mappings-patch.tiny: -------------------------------------------------------------------------------- 1 | # We would like for paperweight to generate 100% perfect reobf mappings (and deobf mappings for that matter). 2 | # But unfortunately it's not quite there yet - and it may be some time before that happens. Generating perfect mappings 3 | # from Spigot's mappings is extremely difficult due to Spigot's bad tooling and bad mappings. To add insult to injury 4 | # we remap Spigot's _source code_ which is a lot more complex and error-prone than bytecode remapping. So with all that 5 | # said, this file exists to help fill in the gap. 6 | # 7 | # We will continue to improve paperweight and will work on fixing these issues so they don't come up in the first place, 8 | # but these mappings exist to prevent these issues from holding everything else in Paper up while we work through all 9 | # of these issues. Due to the complex nature of mappings generation and the debugging difficulty involved it may take 10 | # a significant amount of time for us to track down every possible issue, so this file will likely be around and in 11 | # use - at least in some capacity - for a long time. 12 | # 13 | # If you are adding mappings patches which are correcting for issues in paperweight's reobf mappings generation, 14 | # unrelated to any changes in your patches, we ask that you PR the mapping to Paper so more users can benefit rather 15 | # than keep the fix for your own fork. If the mappings patch is there to correct reobf for changes made in your patches, 16 | # then obviously it doesn't make any sense to PR them upstream. 17 | 18 | tiny 2 0 mojang+yarn spigot 19 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | import io.papermc.paperweight.tasks.RebuildGitPatches 2 | 3 | plugins { 4 | java 5 | `maven-publish` 6 | id("com.github.johnrengelman.shadow") version "8.1.1" apply false 7 | id("io.papermc.paperweight.patcher") version "1.5.5" 8 | } 9 | 10 | val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/" 11 | val voicechatMavenPublicUrl = "https://maven.maxhenkel.de/repository/public" 12 | val modrinthMavenPublicUrl = "https://api.modrinth.com/maven" 13 | repositories { 14 | mavenCentral() 15 | maven(paperMavenPublicUrl) { 16 | content { onlyForConfigurations(configurations.paperclip.name) } 17 | } 18 | 19 | } 20 | 21 | dependencies { 22 | remapper("net.fabricmc:tiny-remapper:0.8.6:fat") 23 | decompiler("net.minecraftforge:forgeflower:2.0.627.2") 24 | paperclip("io.papermc:paperclip:3.0.3") 25 | } 26 | 27 | allprojects { 28 | apply(plugin = "java") 29 | apply(plugin = "maven-publish") 30 | 31 | java { 32 | toolchain { 33 | languageVersion.set(JavaLanguageVersion.of(17)) 34 | } 35 | } 36 | } 37 | 38 | subprojects { 39 | tasks.withType { 40 | options.encoding = Charsets.UTF_8.name() 41 | options.release.set(17) 42 | } 43 | tasks.withType { 44 | options.encoding = Charsets.UTF_8.name() 45 | } 46 | tasks.withType { 47 | filteringCharset = Charsets.UTF_8.name() 48 | } 49 | 50 | repositories { 51 | mavenCentral() 52 | maven(paperMavenPublicUrl) 53 | maven(voicechatMavenPublicUrl) 54 | maven(modrinthMavenPublicUrl) 55 | } 56 | } 57 | 58 | paperweight { 59 | serverProject.set(project(":paperrecord-server")) 60 | 61 | remapRepo.set(paperMavenPublicUrl) 62 | decompileRepo.set(paperMavenPublicUrl) 63 | 64 | usePaperUpstream(providers.gradleProperty("paperRef")) { 65 | withPaperPatcher { 66 | apiPatchDir.set(layout.projectDirectory.dir("patches/api")) 67 | apiOutputDir.set(layout.projectDirectory.dir("PaperRecord-API")) 68 | 69 | serverPatchDir.set(layout.projectDirectory.dir("patches/server")) 70 | serverOutputDir.set(layout.projectDirectory.dir("PaperRecord-Server")) 71 | } 72 | } 73 | } 74 | 75 | tasks.generateDevelopmentBundle { 76 | apiCoordinates.set("dev.paperrecord:paperrecord-api") 77 | mojangApiCoordinates.set("io.papermc.paper:paper-mojangapi") 78 | libraryRepositories.addAll( 79 | "https://repo.maven.apache.org/maven2/", 80 | paperMavenPublicUrl, 81 | ) 82 | } 83 | 84 | allprojects { 85 | publishing { 86 | repositories { 87 | maven("https://repo.papermc.io/repository/maven-snapshots/") { 88 | name = "paperSnapshots" 89 | credentials(PasswordCredentials::class) 90 | } 91 | } 92 | } 93 | } 94 | 95 | publishing { 96 | if (project.hasProperty("publishDevBundle")) { 97 | publications.create("devBundle") { 98 | artifact(tasks.generateDevelopmentBundle) { 99 | artifactId = "dev-bundle" 100 | } 101 | } 102 | } 103 | } 104 | 105 | tasks.withType { 106 | filterPatches.set(false) 107 | } 108 | 109 | tasks.register("printMinecraftVersion") { 110 | doLast { 111 | println(providers.gradleProperty("mcVersion").get().trim()) 112 | } 113 | } 114 | 115 | tasks.register("printPaperVersion") { 116 | doLast { 117 | println(project.version) 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | group=dev.paperrecord 2 | 3 | version=1.20.1-R0.1-SNAPSHOT 4 | mcVersion=1.20.1 5 | paperRef=e8bec64217064476784a5c65a5060cfc0145fa98 6 | 7 | org.gradle.caching=true 8 | org.gradle.parallel=true 9 | org.gradle.vfs.watch=false 10 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Moyettes/PaperRecorder/b72f6a1f0ca38ba4315950b6cd27736658391a48/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip 4 | networkTimeout=10000 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 147 | # shellcheck disable=SC3045 148 | MAX_FD=$( ulimit -H -n ) || 149 | warn "Could not query maximum file descriptor limit" 150 | esac 151 | case $MAX_FD in #( 152 | '' | soft) :;; #( 153 | *) 154 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 155 | # shellcheck disable=SC3045 156 | ulimit -n "$MAX_FD" || 157 | warn "Could not set maximum file descriptor limit to $MAX_FD" 158 | esac 159 | fi 160 | 161 | # Collect all arguments for the java command, stacking in reverse order: 162 | # * args from the command line 163 | # * the main class name 164 | # * -classpath 165 | # * -D...appname settings 166 | # * --module-path (only if needed) 167 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 168 | 169 | # For Cygwin or MSYS, switch paths to Windows format before running java 170 | if "$cygwin" || "$msys" ; then 171 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 172 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 173 | 174 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 175 | 176 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 177 | for arg do 178 | if 179 | case $arg in #( 180 | -*) false ;; # don't mess with options #( 181 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 182 | [ -e "$t" ] ;; #( 183 | *) false ;; 184 | esac 185 | then 186 | arg=$( cygpath --path --ignore --mixed "$arg" ) 187 | fi 188 | # Roll the args list around exactly as many times as the number of 189 | # args, so each arg winds up back in the position where it started, but 190 | # possibly modified. 191 | # 192 | # NB: a `for` loop captures its iteration list before it begins, so 193 | # changing the positional parameters here affects neither the number of 194 | # iterations, nor the values presented in `arg`. 195 | shift # remove old arg 196 | set -- "$@" "$arg" # push replacement arg 197 | done 198 | fi 199 | 200 | # Collect all arguments for the java command; 201 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 202 | # shell script including quotes and variable substitutions, so put them in 203 | # double quotes to make sure that they get re-expanded; and 204 | # * put everything else in single quotes, so that it's not re-expanded. 205 | 206 | set -- \ 207 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 208 | -classpath "$CLASSPATH" \ 209 | org.gradle.wrapper.GradleWrapperMain \ 210 | "$@" 211 | 212 | # Stop when "xargs" is not available. 213 | if ! command -v xargs >/dev/null 2>&1 214 | then 215 | die "xargs is not available" 216 | fi 217 | 218 | # Use "xargs" to parse quoted args. 219 | # 220 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 221 | # 222 | # In Bash we could simply go: 223 | # 224 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 225 | # set -- "${ARGS[@]}" "$@" 226 | # 227 | # but POSIX shell has neither arrays nor command substitution, so instead we 228 | # post-process each arg (as a line of input to sed) to backslash-escape any 229 | # character that might be a shell metacharacter, then use eval to reverse 230 | # that process (while maintaining the separation between arguments), and wrap 231 | # the whole thing up as a single "set" statement. 232 | # 233 | # This will of course break if any of these variables contains a newline or 234 | # an unmatched quote. 235 | # 236 | 237 | eval "set -- $( 238 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 239 | xargs -n1 | 240 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 241 | tr '\n' ' ' 242 | )" '"$@"' 243 | 244 | exec "$JAVACMD" "$@" 245 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /install.bat: -------------------------------------------------------------------------------- 1 | ./gradlew publishToMavenLocal -------------------------------------------------------------------------------- /jar.bat: -------------------------------------------------------------------------------- 1 | ./gradlew createMojmapPaperclipJar -------------------------------------------------------------------------------- /paperrecorder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Moyettes/PaperRecorder/b72f6a1f0ca38ba4315950b6cd27736658391a48/paperrecorder.png -------------------------------------------------------------------------------- /patch.bat: -------------------------------------------------------------------------------- 1 | ./gradlew applypatches -------------------------------------------------------------------------------- /patches/server/0005-ServerSideRecorder.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Bryan1029384756 <23323626+Bryan1029384756@users.noreply.github.com> 3 | Date: Sat, 17 Jun 2023 23:00:30 -0500 4 | Subject: [PATCH] ServerSideRecorder 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/ServerSideReplayRecorderServer.java b/src/main/java/net/minecraft/serversidereplayrecorder/ServerSideReplayRecorderServer.java 8 | index be30a4f207069228d62990614bfcea30415a7e62..198841e836943e20e65d75a432884b709c9e405f 100644 9 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/ServerSideReplayRecorderServer.java 10 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/ServerSideReplayRecorderServer.java 11 | @@ -8,6 +8,7 @@ import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import java.io.*; 15 | +import java.nio.file.Path; 16 | import java.util.ResourceBundle; 17 | import java.util.concurrent.ExecutorService; 18 | import java.util.concurrent.Executors; 19 | @@ -15,57 +16,68 @@ import java.util.concurrent.Executors; 20 | public class ServerSideReplayRecorderServer { 21 | 22 | static { 23 | - YAMLFactoryBuilder builder = YAMLFactory.builder(); 24 | - builder.disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER); 25 | - builder.enable(YAMLGenerator.Feature.INDENT_ARRAYS_WITH_INDICATOR); 26 | - yaml = new ObjectMapper(builder.build()).configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 27 | - placeholders = ResourceBundle.getBundle("placeholders"); 28 | - upload_sites = ResourceBundle.getBundle("upload_sites"); 29 | +// YAMLFactoryBuilder builder = YAMLFactory.builder(); 30 | +// builder.disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER); 31 | +// builder.enable(YAMLGenerator.Feature.INDENT_ARRAYS_WITH_INDICATOR); 32 | +// yaml = new ObjectMapper(builder.build()).configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 33 | +// placeholders = ResourceBundle.getBundle("placeholders"); 34 | +// upload_sites = ResourceBundle.getBundle("upload_sites"); 35 | } 36 | 37 | public static final ExecutorService recorderExecutor = Executors.newSingleThreadExecutor(new DefaultThreadFactory("Replay",true)); 38 | 39 | - private static final ObjectMapper yaml; 40 | - 41 | - public static final ResourceBundle placeholders; 42 | - public static final ResourceBundle upload_sites; 43 | +// private static final ObjectMapper yaml; 44 | +// 45 | +// public static final ResourceBundle placeholders; 46 | +// public static final ResourceBundle upload_sites; 47 | 48 | public static final Logger LOGGER = LoggerFactory.getLogger(ServerSideReplayRecorderServer.class.getName()); 49 | 50 | public static MinecraftServer server; 51 | 52 | - public static final String configPath = FabricLoader.getInstance().getConfigDir() + "/ServerSideReplayRecorder.yml"; 53 | + public static final String configPath = getConfigDirectory() + "/ServerSideReplayRecorder.yml"; 54 | public static MainConfig config = new MainConfig(); 55 | 56 | - public static void loadConfig() { 57 | - try { 58 | - 59 | - yaml.findAndRegisterModules(); 60 | - config = yaml.readValue(new FileReader(configPath), MainConfig.class); 61 | - 62 | - }catch (FileNotFoundException e){ 63 | - System.out.println("Config file not found, creating with default values..."); 64 | - saveConfig(); 65 | - }catch (Throwable t){ 66 | - throw new RuntimeException(t); 67 | - } 68 | +// public static void loadConfig() { 69 | +// try { 70 | +// yaml.findAndRegisterModules(); 71 | +// config = yaml.readValue(new FileReader(configPath), MainConfig.class); 72 | +// 73 | +// }catch (FileNotFoundException e){ 74 | +// System.out.println("Config file not found, creating with default values..."); 75 | +// saveConfig(); 76 | +// }catch (Throwable t){ 77 | +// throw new RuntimeException(t); 78 | +// } 79 | +// } 80 | +// 81 | +// public static void saveConfig() { 82 | +// try { 83 | +// yaml.findAndRegisterModules(); 84 | +// //noinspection ResultOfMethodCallIgnored 85 | +// 86 | +// new File(getConfigDirectory()).mkdirs(); 87 | +// BufferedWriter writer = new BufferedWriter(new FileWriter(configPath)); 88 | +// writer.write("#Config for Server Side Replay Recorder\n"); 89 | +// writer.write("##WARNING any comments in this file might get deleted\n"); 90 | +// writer.write("\n"); 91 | +// yaml.writeValue(writer, config); 92 | +// writer.close(); 93 | +// } catch (IOException ioException) { 94 | +// ioException.printStackTrace(); 95 | +// } 96 | +// } 97 | + 98 | + public static String getConfigDirectory(){ 99 | + System.out.println(System.getProperty("user.dir") + "/config"); 100 | + return System.getProperty("user.dir") + "/config"; 101 | } 102 | 103 | - public static void saveConfig() { 104 | - try { 105 | - yaml.findAndRegisterModules(); 106 | - //noinspection ResultOfMethodCallIgnored 107 | - new File(FabricLoader.getInstance().getConfigDir().toString()).mkdirs(); 108 | - BufferedWriter writer = new BufferedWriter(new FileWriter(configPath)); 109 | - writer.write("#Config for Server Side Replay Recorder\n"); 110 | - writer.write("##WARNING any comments in this file might get deleted\n"); 111 | - writer.write("\n"); 112 | - yaml.writeValue(writer, config); 113 | - writer.close(); 114 | - } catch (IOException ioException) { 115 | - ioException.printStackTrace(); 116 | - } 117 | + public static String getDirectory(){ 118 | + System.out.println(System.getProperty("user.dir")); 119 | + return System.getProperty("user.dir"); 120 | } 121 | + 122 | public static void registerServer(MinecraftServer mcServer) { 123 | server = mcServer; 124 | //fixStoppedReplays(); 125 | @@ -73,7 +85,7 @@ public class ServerSideReplayRecorderServer { 126 | 127 | public void onInitialize() { 128 | LOGGER.info(ServerSideReplayRecorderServer.class.getSimpleName() + " loaded"); 129 | - loadConfig(); 130 | + //loadConfig(); 131 | } 132 | 133 | } 134 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/recorder/PlayerRecorder.java b/src/main/java/net/minecraft/serversidereplayrecorder/recorder/PlayerRecorder.java 135 | index a417433aa83be221fd26f5ef8a3197ca48fb408a..0b89881480c14f44b5943c547606ff2bbc6b9bab 100644 136 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/recorder/PlayerRecorder.java 137 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/recorder/PlayerRecorder.java 138 | @@ -12,6 +12,7 @@ import net.minecraft.serversidereplayrecorder.ServerSideReplayRecorderServer; 139 | import net.minecraft.serversidereplayrecorder.util.WrappedPacket; 140 | import net.minecraft.serversidereplayrecorder.util.interfaces.LightUpdatePacketAccessor; 141 | import net.minecraft.world.entity.player.Player; 142 | +import net.minecraft.world.level.storage.LevelStorageSource; 143 | 144 | import java.io.File; 145 | import java.io.IOException; 146 | @@ -39,6 +40,8 @@ public class PlayerRecorder extends ReplayRecorder { 147 | return this.playerName; 148 | } 149 | 150 | + 151 | + 152 | @Override 153 | protected String getSaveFolder() { 154 | String name; 155 | @@ -51,7 +54,7 @@ public class PlayerRecorder extends ReplayRecorder { 156 | if (new File(ServerSideReplayRecorderServer.config.getReplay_folder_name()).isAbsolute()) 157 | return Paths.get(ServerSideReplayRecorderServer.config.getReplay_folder_name(), PLAYER_FOLDER, name).toString(); 158 | else 159 | - return Paths.get(FabricLoader.getInstance().getGameDir().toString(), ServerSideReplayRecorderServer.config.getReplay_folder_name(), PLAYER_FOLDER, name).toString(); 160 | + return Paths.get(ServerSideReplayRecorderServer.getDirectory(), ServerSideReplayRecorderServer.config.getReplay_folder_name(), PLAYER_FOLDER, name).toString(); 161 | } 162 | 163 | 164 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/recorder/RegionRecorder.java b/src/main/java/net/minecraft/serversidereplayrecorder/recorder/RegionRecorder.java 165 | index 04b34176da3ab7fc62ca33212e2de41776bf8ea1..ffdbd36015553ca8d15d55803c945f8949f234f0 100644 166 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/recorder/RegionRecorder.java 167 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/recorder/RegionRecorder.java 168 | @@ -23,7 +23,9 @@ import net.minecraft.world.flag.FeatureFlags; 169 | import net.minecraft.world.item.ItemStack; 170 | import net.minecraft.world.level.ChunkPos; 171 | import net.minecraft.world.level.GameRules; 172 | +import net.minecraft.world.level.GameType; 173 | import net.minecraft.world.level.border.WorldBorder; 174 | +import net.minecraft.world.level.chunk.ChunkAccess; 175 | import net.minecraft.world.level.chunk.ChunkStatus; 176 | import net.minecraft.world.level.chunk.ImposterProtoChunk; 177 | import net.minecraft.world.level.chunk.LevelChunk; 178 | @@ -97,26 +99,26 @@ public class RegionRecorder extends ReplayRecorder { 179 | onPacket(new ClientboundLoginPacket( 180 | 0, 181 | worldProperties.isHardcore(), 182 | - GameMode.SPECTATOR, 183 | - GameMode.SPECTATOR, 184 | + GameType.SPECTATOR, 185 | + GameType.SPECTATOR, 186 | ms.levelKeys(), 187 | - ms.registryAccess().toImmutable(), 188 | - world.getDimensionKey(), 189 | - world.getRegistryKey(), 190 | + ms.registryAccess().freeze(), 191 | + world.dimensionTypeId(), 192 | + world.dimension(), 193 | world.getSeed(), 194 | ms.getMaxPlayers(), 195 | region.radius, 196 | region.radius, 197 | false, 198 | false, 199 | - world.isDebugWorld(), 200 | + world.isDebug(), 201 | world.isFlat(), 202 | Optional.empty(), 203 | 0 204 | )); 205 | onPacket(new ClientboundUpdateEnabledFeaturesPacket(FeatureFlags.REGISTRY.toNames(world.enabledFeatures()))); 206 | onPacket( 207 | - new ClientboundCustomPayloadPacket(ClientboundCustomPayloadPacket.BRAND, new FriendlyByteBuf(Unpooled.buffer()).writeString(ms.getServerModName())) 208 | + new ClientboundCustomPayloadPacket(ClientboundCustomPayloadPacket.BRAND, new FriendlyByteBuf(Unpooled.buffer()).writeUtf(ms.getServerModName())) 209 | ); 210 | onPacket(new ClientboundChangeDifficultyPacket(worldProperties.getDifficulty(), worldProperties.isDifficultyLocked())); 211 | onPacket(new ClientboundPlayerAbilitiesPacket(new Abilities())); 212 | @@ -130,12 +132,12 @@ public class RegionRecorder extends ReplayRecorder { 213 | //save world ( dimension ) information 214 | WorldBorder worldBorder = world.getWorldBorder(); 215 | onPacket(new ClientboundInitializeBorderPacket(worldBorder)); 216 | - onPacket(new ClientboundSetTimePacket(world.getTime(), world.getTimeOfDay(), world.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT))); 217 | - onPacket(new ClientboundSetDefaultSpawnPositionPacket(world.getSpawnPos(), world.getSpawnAngle())); 218 | + onPacket(new ClientboundSetTimePacket(world.getGameTime(), world.getDayTime(), world.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT))); 219 | + onPacket(new ClientboundSetDefaultSpawnPositionPacket(world.getSharedSpawnPos(), world.getSharedSpawnAngle())); 220 | if (world.isRaining()) { 221 | onPacket(new ClientboundGameEventPacket(ClientboundGameEventPacket.START_RAINING, ClientboundGameEventPacket.DEMO_PARAM_INTRO)); 222 | - onPacket(new ClientboundGameEventPacket(ClientboundGameEventPacket.RAIN_LEVEL_CHANGE, world.getRainGradient(1.0F))); 223 | - onPacket(new ClientboundGameEventPacket(ClientboundGameEventPacket.THUNDER_LEVEL_CHANGE, world.getThunderGradient(1.0F))); 224 | + onPacket(new ClientboundGameEventPacket(ClientboundGameEventPacket.RAIN_LEVEL_CHANGE, world.getRainLevel(1.0F))); 225 | + onPacket(new ClientboundGameEventPacket(ClientboundGameEventPacket.THUNDER_LEVEL_CHANGE, world.getThunderLevel(1.0F))); 226 | } 227 | ms 228 | .getServerResourcePack() 229 | @@ -170,7 +172,7 @@ public class RegionRecorder extends ReplayRecorder { 230 | for (ChunkPos pos : this.region.expandedChunks ){ 231 | //get chunk, load if needed, no create 232 | //this call is deferred to the MainServer executor which runs at the end of a tick in the spare time 233 | - Chunk chunk = world.getChunk(pos.x,pos.z, ChunkStatus.EMPTY); 234 | + ChunkAccess chunk = world.getChunk(pos.x,pos.z, ChunkStatus.EMPTY); 235 | LevelChunk worldChunk = null; 236 | if (chunk instanceof LevelChunk) 237 | worldChunk = (LevelChunk) chunk; 238 | @@ -183,17 +185,17 @@ public class RegionRecorder extends ReplayRecorder { 239 | if (pos.equals(this.region.center)) { 240 | 241 | //find the highest non-transparent block as viewpoint 242 | - int surface_y = worldChunk.sampleHeightmap(Heightmap.Type.MOTION_BLOCKING, viewpoint.getX(), viewpoint.getZ()); 243 | + int surface_y = worldChunk.getHeight(Heightmap.Types.MOTION_BLOCKING, viewpoint.getX(), viewpoint.getZ()); 244 | BlockPos b_pos = new BlockPos(viewpoint.getX(), surface_y, viewpoint.getZ()); 245 | while (!worldChunk.getBlockState(b_pos).isOpaque() && surface_y != chunk.getMinBuildHeight()) { 246 | b_pos = new BlockPos(viewpoint.getX(), --surface_y, viewpoint.getZ()); 247 | } 248 | //if no blocks are found in the column keep the original viewpoint 249 | - if (surface_y != chunk.getBottomY()) 250 | + if (surface_y != chunk.getMinBuildHeight()) 251 | this.viewpoint = new Vec3i(viewpoint.getX(), surface_y + 1, viewpoint.getZ()); 252 | } 253 | //save chunk 254 | - onPacket(new WrappedPacket(new ClientboundLevelChunkWithLightPacket(worldChunk, world.getLightingProvider(), null, null))); 255 | + onPacket(new WrappedPacket(new ClientboundLevelChunkWithLightPacket(worldChunk, world.getLightEngine(), null, null))); 256 | //--obsolete in new versions 257 | //onPacket(new WrappedPacket(new LightUpdateS2CPacket(pos, world.getLightingProvider(), null, null, true))); 258 | known_chunk_data.add(pos); 259 | @@ -256,7 +258,7 @@ public class RegionRecorder extends ReplayRecorder { 260 | if (new File(ServerSideReplayRecorderServer.config.getReplay_folder_name()).isAbsolute()) 261 | return Paths.get(ServerSideReplayRecorderServer.config.getReplay_folder_name(), REGION_FOLDER,name).toString(); 262 | else 263 | - return Paths.get(FabricLoader.getInstance().getGameDir().toString(), ServerSideReplayRecorderServer.config.getReplay_folder_name(), REGION_FOLDER,name).toString(); 264 | + return Paths.get(ServerSideReplayRecorderServer.getDirectory(), ServerSideReplayRecorderServer.config.getReplay_folder_name(), REGION_FOLDER,name).toString(); 265 | } 266 | 267 | @Override 268 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/recorder/ReplayRecorder.java b/src/main/java/net/minecraft/serversidereplayrecorder/recorder/ReplayRecorder.java 269 | index 7a28f357e71c4c964de200557182222d2fbd6665..d6f1308bc76895094dc07f71ba00b1ace427d494 100644 270 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/recorder/ReplayRecorder.java 271 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/recorder/ReplayRecorder.java 272 | @@ -84,7 +84,7 @@ public abstract class ReplayRecorder { 273 | if (new File(ServerSideReplayRecorderServer.config.getReplay_folder_name()).isAbsolute()) 274 | tmp_folder = Paths.get(ServerSideReplayRecorderServer.config.getReplay_folder_name(), "recording_" + this.hashCode()).toFile(); 275 | else 276 | - tmp_folder = Paths.get(FabricLoader.getInstance().getGameDir().toString(), ServerSideReplayRecorderServer.config.getReplay_folder_name(), "recording_" + this.hashCode()).toFile(); 277 | + tmp_folder = Paths.get(ServerSideReplayRecorderServer.getDirectory(), ServerSideReplayRecorderServer.config.getReplay_folder_name(), "recording_" + this.hashCode()).toFile(); 278 | tmp_folder.mkdirs(); 279 | recording_file= Paths.get(tmp_folder.getAbsolutePath(), "recording.tmcpr").toFile(); 280 | fileName = String.format("%s.mcpr", new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss").format(new Date())); 281 | -------------------------------------------------------------------------------- /patches/server/0006-ServerSideRecorder.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Bryan1029384756 <23323626+Bryan1029384756@users.noreply.github.com> 3 | Date: Sat, 17 Jun 2023 23:37:21 -0500 4 | Subject: [PATCH] ServerSideRecorder 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java 8 | index 60f77d4f519cf0864ce8a01fdc7bebd5fe548e01..8a2fae854e07482fd5cd372ab12571618fdbeacb 100644 9 | --- a/src/main/java/net/minecraft/server/level/ChunkMap.java 10 | +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java 11 | @@ -1336,7 +1336,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider 12 | } 13 | level.timings.tracker2.stopTiming(); // Paper 14 | } 15 | - ((RegionRecorderEntityTracker)playerchunkmap_entitytracker).updateTrackedStatus(((RegionRecorderWorld)playerchunkmap_entitytracker.entity.level()).getRegionRecorders()); //Seversiderecorder 16 | + ((RegionRecorderEntityTracker)this.entityMap).updateTrackedStatus(((RegionRecorderWorld)this.level).getRegionRecorders()); //Seversiderecorder 17 | } 18 | 19 | public void broadcast(Entity entity, Packet packet) { 20 | @@ -1464,6 +1464,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider 21 | this.recorder = new WeakReference<>(recorder); 22 | //send the spawn packets when the tracker is creaed 23 | //works also for dimension change as a new tracker is created while changing dimension 24 | + 25 | if (recorder != null) { 26 | serverEntity.sendPairingData(null, recorder::onPacket); 27 | } 28 | diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java 29 | index 6670e657e08e130f7e0368f418379fd1ece00cdf..27edf4a0eb3caed5923fd1187c4da1472f77a959 100644 30 | --- a/src/main/java/net/minecraft/server/level/ServerEntity.java 31 | +++ b/src/main/java/net/minecraft/server/level/ServerEntity.java 32 | @@ -308,11 +308,13 @@ public class ServerEntity { 33 | if (this.entity instanceof LivingEntity) { 34 | Collection collection = ((LivingEntity) this.entity).getAttributes().getSyncableAttributes(); 35 | 36 | - // CraftBukkit start - If sending own attributes send scaled health instead of current maximum health 37 | - if (this.entity.getId() == player.getId()) { 38 | - ((ServerPlayer) this.entity).getBukkitEntity().injectScaledMaxHealth(collection, false); 39 | + if(player != null){ 40 | + // CraftBukkit start - If sending own attributes send scaled health instead of current maximum health 41 | + if (this.entity.getId() == player.getId()) { 42 | + ((ServerPlayer) this.entity).getBukkitEntity().injectScaledMaxHealth(collection, false); 43 | + } 44 | + // CraftBukkit end 45 | } 46 | - // CraftBukkit end 47 | 48 | if (!collection.isEmpty()) { 49 | sender.accept(new ClientboundUpdateAttributesPacket(this.entity.getId(), collection)); 50 | diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java 51 | index b0c7f13cf93108349dabdd378e38ff001fc92e7c..1a79374bb771b20309fb087703bfe278d90ed71d 100644 52 | --- a/src/main/java/net/minecraft/server/players/PlayerList.java 53 | +++ b/src/main/java/net/minecraft/server/players/PlayerList.java 54 | @@ -171,8 +171,8 @@ public abstract class PlayerList { 55 | 56 | public void placeNewPlayer(Connection connection, ServerPlayer player) { 57 | //ServerSideReplayRecorder start 58 | - if (ServerSideReplayRecorderServer.config.isRecording_enabled() && !PlayerRecorder.playerRecorderMap.containsKey(connection) 59 | - && ( ServerSideReplayRecorderServer.config.getRecordable_users().contains(player.getGameProfile().getName())) != ServerSideReplayRecorderServer.config.invert_user_list() ) { 60 | + // if (ServerSideReplayRecorderServer.config.isRecording_enabled() && !PlayerRecorder.playerRecorderMap.containsKey(connection) 61 | + // && ( ServerSideReplayRecorderServer.config.getRecordable_users().contains(player.getGameProfile().getName())) != ServerSideReplayRecorderServer.config.invert_user_list() ) { 62 | try { 63 | ServerSideReplayRecorderServer.LOGGER.info("Started Recording Player %s".formatted(player.getGameProfile().getName())); 64 | 65 | @@ -183,7 +183,7 @@ public abstract class PlayerList { 66 | } catch (IOException e) { 67 | e.printStackTrace(); 68 | } 69 | - } 70 | + // } 71 | //ServerSideReplayRecorder end 72 | 73 | player.isRealPlayer = true; // Paper 74 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/ServerSideReplayRecorderServer.java b/src/main/java/net/minecraft/serversidereplayrecorder/ServerSideReplayRecorderServer.java 75 | index 198841e836943e20e65d75a432884b709c9e405f..9a5ae6b35154bc7cc634306ae3534beca47cb170 100644 76 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/ServerSideReplayRecorderServer.java 77 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/ServerSideReplayRecorderServer.java 78 | @@ -69,8 +69,8 @@ public class ServerSideReplayRecorderServer { 79 | // } 80 | 81 | public static String getConfigDirectory(){ 82 | - System.out.println(System.getProperty("user.dir") + "/config"); 83 | - return System.getProperty("user.dir") + "/config"; 84 | + System.out.println(System.getProperty("user.dir") + "\\config"); 85 | + return System.getProperty("user.dir") + "\\config"; 86 | } 87 | 88 | public static String getDirectory(){ 89 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/command/ReplayCommand.java b/src/main/java/net/minecraft/serversidereplayrecorder/command/ReplayCommand.java 90 | index f1efdd1fa54243110efc6719c3c75c33fdac3199..50634cba3a60eea3d8474c88e8a34f1c97c8fdf0 100644 91 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/command/ReplayCommand.java 92 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/command/ReplayCommand.java 93 | @@ -180,7 +180,7 @@ public class ReplayCommand { 94 | }); 95 | if (count.get() > 0) { 96 | source.sendSuccess(()->Component.literal("Added players will start recording next time they join the server"), true); 97 | - ServerSideReplayRecorderServer.saveConfig(); 98 | + //ServerSideReplayRecorderServer.saveConfig(); 99 | } 100 | return 0; 101 | }) 102 | @@ -211,7 +211,7 @@ public class ReplayCommand { 103 | }); 104 | if (count.get() > 0) { 105 | source.sendSuccess(()->Component.literal("Removed players will stop recording on logout"), true); 106 | - ServerSideReplayRecorderServer.saveConfig(); 107 | + // ServerSideReplayRecorderServer.saveConfig(); 108 | } 109 | return 0; 110 | }) 111 | @@ -278,13 +278,13 @@ public class ReplayCommand { 112 | .then(Commands.literal("enable").executes(context -> { 113 | ServerSideReplayRecorderServer.config.setRecording_enabled(true); 114 | context.getSource().sendSuccess(()->Component.literal("Recording " + ((ServerSideReplayRecorderServer.config.isRecording_enabled()) ? "Enabled" : "Disabled")), true); 115 | - ServerSideReplayRecorderServer.saveConfig(); 116 | + // ServerSideReplayRecorderServer.saveConfig(); 117 | return 0; 118 | })) 119 | .then(Commands.literal("disable").executes(context -> { 120 | ServerSideReplayRecorderServer.config.setRecording_enabled(false); 121 | context.getSource().sendSuccess(()->Component.literal("Recording " + ((ServerSideReplayRecorderServer.config.isRecording_enabled()) ? "Enabled" : "Disabled")), true); 122 | - ServerSideReplayRecorderServer.saveConfig(); 123 | + // ServerSideReplayRecorderServer.saveConfig(); 124 | return 0; 125 | })) 126 | ).then( 127 | -------------------------------------------------------------------------------- /patches/server/0007-ServerSideRecorder.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Bryan1029384756 <23323626+Bryan1029384756@users.noreply.github.com> 3 | Date: Sat, 17 Jun 2023 23:46:08 -0500 4 | Subject: [PATCH] ServerSideRecorder 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java 8 | index 1a79374bb771b20309fb087703bfe278d90ed71d..f13581964ac8399a1d1acf651a9856d0e6502766 100644 9 | --- a/src/main/java/net/minecraft/server/players/PlayerList.java 10 | +++ b/src/main/java/net/minecraft/server/players/PlayerList.java 11 | @@ -1192,7 +1192,7 @@ public abstract class PlayerList { 12 | //Serversiderecorder start 13 | 14 | if (player != null) { 15 | - ReplayRecorder recorder = ((RecorderHolder)(((ServerPlayer) player).connection)).getRecorder(); 16 | + ReplayRecorder recorder = ((RecorderHolder)(((ServerPlayer) player).connection.connection)).getRecorder(); 17 | if (recorder != null) { 18 | recorder.onPacket(packet); 19 | } 20 | -------------------------------------------------------------------------------- /patches/server/0008-ServerSideRecorder.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Bryan1029384756 <23323626+Bryan1029384756@users.noreply.github.com> 3 | Date: Sun, 18 Jun 2023 05:32:29 -0500 4 | Subject: [PATCH] ServerSideRecorder 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java 8 | index b25eef60573cb217ac2a288ab7dd9e502e39e247..f56d50a9936ee72ebb74175520d5a08e55bbded6 100644 9 | --- a/src/main/java/net/minecraft/network/Connection.java 10 | +++ b/src/main/java/net/minecraft/network/Connection.java 11 | @@ -435,10 +435,12 @@ public class Connection extends SimpleChannelInboundHandler> implement 12 | this.flushQueue(); 13 | // Paper end 14 | 15 | + //Serversiderecorder start 16 | ReplayRecorder recorder = this.recorder.get(); 17 | if (recorder != null){ 18 | recorder.onPacket(packet); 19 | } 20 | + //Serversiderecorder end 21 | } 22 | 23 | private void sendPacket(Packet packet, @Nullable PacketSendListener callbacks) { 24 | @@ -836,10 +838,7 @@ public class Connection extends SimpleChannelInboundHandler> implement 25 | } 26 | 27 | public void handleDisconnection() { 28 | - ReplayRecorder recorder = this.recorder.get(); 29 | - if (recorder != null){ 30 | - recorder.handleDisconnect(); 31 | - } 32 | + 33 | 34 | if (this.channel != null && !this.channel.isOpen()) { 35 | if (this.disconnectionHandled) { 36 | diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java 37 | index 37610964e6057709b4d0fb82e36d3943d50b45b1..a6fded634d1545611337ee39b6dcde655b0b6b82 100644 38 | --- a/src/main/java/net/minecraft/server/MinecraftServer.java 39 | +++ b/src/main/java/net/minecraft/server/MinecraftServer.java 40 | @@ -1114,6 +1114,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 3 | Date: Sun, 18 Jun 2023 19:01:55 -0500 4 | Subject: [PATCH] ServerSideRecorder 5 | 6 | 7 | diff --git a/build.gradle.kts b/build.gradle.kts 8 | index 1e6743e1ac5cfc7f5fbd5a40ead0ca519dac74c9..bc657aeac475dfc5a55e5d91939d5e8318b0c12f 100644 9 | --- a/build.gradle.kts 10 | +++ b/build.gradle.kts 11 | @@ -35,7 +35,8 @@ dependencies { 12 | implementation("org.spongepowered:configurate-yaml:4.1.2") // Paper - config files 13 | implementation("commons-lang:commons-lang:2.6") 14 | implementation("net.fabricmc:mapping-io:0.3.0") // Paper - needed to read mappings for stacktrace deobfuscation 15 | - implementation("com.fasterxml.jackson.core:jackson-annotations:2.15.2") 16 | + implementation("com.fasterxml.jackson.core:jackson-annotations:2.15.2") //ServersideRecording 17 | + implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.15.2") //ServersideRecording 18 | runtimeOnly("org.xerial:sqlite-jdbc:3.42.0.0") 19 | runtimeOnly("com.mysql:mysql-connector-j:8.0.33") 20 | runtimeOnly("com.lmax:disruptor:3.4.4") // Paper 21 | diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java 22 | index a6fded634d1545611337ee39b6dcde655b0b6b82..c301cc293a93c45c3955932ff6bb445bcd32842a 100644 23 | --- a/src/main/java/net/minecraft/server/MinecraftServer.java 24 | +++ b/src/main/java/net/minecraft/server/MinecraftServer.java 25 | @@ -1114,6 +1114,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop this.isOp(p.getGameProfile())).forEach( p -> p.displayClientMessage(Component.literal("Started Recording Player %s".formatted(player.getGameProfile().getName())), false)); 57 | + //player.connection 58 | PlayerRecorder recorder = new PlayerRecorder(connection); 59 | PlayerRecorder.playerRecorderMap.put(connection, recorder); 60 | +// PlayerRecorder recorder = new PlayerRecorder(connection); 61 | +// PlayerRecorder.playerRecorderMap.put(connection, recorder); 62 | recorder.onPacket(new ClientboundGameProfilePacket(player.getGameProfile())); 63 | } catch (IOException e) { 64 | e.printStackTrace(); 65 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/ServerSideReplayRecorderServer.java b/src/main/java/net/minecraft/serversidereplayrecorder/ServerSideReplayRecorderServer.java 66 | index 9a5ae6b35154bc7cc634306ae3534beca47cb170..723aca57bbe71764774ff8991de6e3c6b134c323 100644 67 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/ServerSideReplayRecorderServer.java 68 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/ServerSideReplayRecorderServer.java 69 | @@ -1,6 +1,10 @@ 70 | package net.minecraft.serversidereplayrecorder; 71 | 72 | -import com.mojang.authlib.minecraft.client.ObjectMapper; 73 | +import com.fasterxml.jackson.databind.DeserializationFeature; 74 | +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; 75 | +import com.fasterxml.jackson.dataformat.yaml.YAMLFactoryBuilder; 76 | +import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator; 77 | +import com.fasterxml.jackson.databind.ObjectMapper; 78 | import io.netty.util.concurrent.DefaultThreadFactory; 79 | import net.minecraft.server.MinecraftServer; 80 | import net.minecraft.serversidereplayrecorder.config.MainConfig; 81 | @@ -8,7 +12,6 @@ import org.slf4j.Logger; 82 | import org.slf4j.LoggerFactory; 83 | 84 | import java.io.*; 85 | -import java.nio.file.Path; 86 | import java.util.ResourceBundle; 87 | import java.util.concurrent.ExecutorService; 88 | import java.util.concurrent.Executors; 89 | @@ -16,20 +19,20 @@ import java.util.concurrent.Executors; 90 | public class ServerSideReplayRecorderServer { 91 | 92 | static { 93 | -// YAMLFactoryBuilder builder = YAMLFactory.builder(); 94 | -// builder.disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER); 95 | -// builder.enable(YAMLGenerator.Feature.INDENT_ARRAYS_WITH_INDICATOR); 96 | -// yaml = new ObjectMapper(builder.build()).configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 97 | -// placeholders = ResourceBundle.getBundle("placeholders"); 98 | -// upload_sites = ResourceBundle.getBundle("upload_sites"); 99 | + YAMLFactoryBuilder builder = YAMLFactory.builder(); 100 | + builder.disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER); 101 | + builder.enable(YAMLGenerator.Feature.INDENT_ARRAYS_WITH_INDICATOR); 102 | + yaml = new ObjectMapper(builder.build()).configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 103 | + placeholders = ResourceBundle.getBundle("placeholders"); 104 | + upload_sites = ResourceBundle.getBundle("upload_sites"); 105 | } 106 | 107 | public static final ExecutorService recorderExecutor = Executors.newSingleThreadExecutor(new DefaultThreadFactory("Replay",true)); 108 | 109 | -// private static final ObjectMapper yaml; 110 | -// 111 | -// public static final ResourceBundle placeholders; 112 | -// public static final ResourceBundle upload_sites; 113 | + private static final ObjectMapper yaml; 114 | + 115 | + public static final ResourceBundle placeholders; 116 | + public static final ResourceBundle upload_sites; 117 | 118 | public static final Logger LOGGER = LoggerFactory.getLogger(ServerSideReplayRecorderServer.class.getName()); 119 | 120 | @@ -38,35 +41,35 @@ public class ServerSideReplayRecorderServer { 121 | public static final String configPath = getConfigDirectory() + "/ServerSideReplayRecorder.yml"; 122 | public static MainConfig config = new MainConfig(); 123 | 124 | -// public static void loadConfig() { 125 | -// try { 126 | -// yaml.findAndRegisterModules(); 127 | -// config = yaml.readValue(new FileReader(configPath), MainConfig.class); 128 | -// 129 | -// }catch (FileNotFoundException e){ 130 | -// System.out.println("Config file not found, creating with default values..."); 131 | -// saveConfig(); 132 | -// }catch (Throwable t){ 133 | -// throw new RuntimeException(t); 134 | -// } 135 | -// } 136 | -// 137 | -// public static void saveConfig() { 138 | -// try { 139 | -// yaml.findAndRegisterModules(); 140 | -// //noinspection ResultOfMethodCallIgnored 141 | -// 142 | -// new File(getConfigDirectory()).mkdirs(); 143 | -// BufferedWriter writer = new BufferedWriter(new FileWriter(configPath)); 144 | -// writer.write("#Config for Server Side Replay Recorder\n"); 145 | -// writer.write("##WARNING any comments in this file might get deleted\n"); 146 | -// writer.write("\n"); 147 | -// yaml.writeValue(writer, config); 148 | -// writer.close(); 149 | -// } catch (IOException ioException) { 150 | -// ioException.printStackTrace(); 151 | -// } 152 | -// } 153 | + public static void loadConfig() { 154 | + try { 155 | + yaml.findAndRegisterModules(); 156 | + config = yaml.readValue(new FileReader(configPath), MainConfig.class); 157 | + 158 | + }catch (FileNotFoundException e){ 159 | + System.out.println("Config file not found, creating with default values..."); 160 | + saveConfig(); 161 | + }catch (Throwable t){ 162 | + throw new RuntimeException(t); 163 | + } 164 | + } 165 | + 166 | + public static void saveConfig() { 167 | + try { 168 | + yaml.findAndRegisterModules(); 169 | + //noinspection ResultOfMethodCallIgnored 170 | + 171 | + new File(getConfigDirectory()).mkdirs(); 172 | + BufferedWriter writer = new BufferedWriter(new FileWriter(configPath)); 173 | + writer.write("#Config for Server Side Replay Recorder\n"); 174 | + writer.write("##WARNING any comments in this file might get deleted\n"); 175 | + writer.write("\n"); 176 | + yaml.writeValue(writer, config); 177 | + writer.close(); 178 | + } catch (IOException ioException) { 179 | + ioException.printStackTrace(); 180 | + } 181 | + } 182 | 183 | public static String getConfigDirectory(){ 184 | System.out.println(System.getProperty("user.dir") + "\\config"); 185 | @@ -83,9 +86,9 @@ public class ServerSideReplayRecorderServer { 186 | //fixStoppedReplays(); 187 | } 188 | 189 | - public void onInitialize() { 190 | + public static void onInitialize() { 191 | LOGGER.info(ServerSideReplayRecorderServer.class.getSimpleName() + " loaded"); 192 | - //loadConfig(); 193 | + loadConfig(); 194 | } 195 | 196 | } 197 | -------------------------------------------------------------------------------- /patches/server/0011-ServerSideRecorder.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Bryan1029384756 <23323626+Bryan1029384756@users.noreply.github.com> 3 | Date: Sun, 18 Jun 2023 20:13:13 -0500 4 | Subject: [PATCH] ServerSideRecorder 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/recorder/ReplayRecorder.java b/src/main/java/net/minecraft/serversidereplayrecorder/recorder/ReplayRecorder.java 8 | index 324e2b9fe2e4141cac1ec0a1d2ef8fe9710f94e6..4c1e74dc5acb0519a15f7274f3e7983737292f09 100644 9 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/recorder/ReplayRecorder.java 10 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/recorder/ReplayRecorder.java 11 | @@ -305,12 +305,14 @@ public abstract class ReplayRecorder { 12 | 13 | public void onServerTick(){ 14 | if (Thread.currentThread() == ms.getRunningThread()){ 15 | + 16 | if (!this.open.get()) 17 | return; 18 | int old_timestamp = this.server_timestamp.get(); 19 | int new_timestamp = (ms.getTickCount() - server_start.get()) * 50; 20 | this.server_timestamp.set(new_timestamp); 21 | if (ServerSideReplayRecorderServer.config.use_server_timestamps()){ 22 | + if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("ReplayRecorder.onServerTick: use_server_timestamps"); 23 | Queue> tick_packets = this.packetQueue.getAndSet(new ConcurrentLinkedQueue<>()); 24 | this.fileWriterExecutor.execute(()->{ 25 | double delta = (new_timestamp - old_timestamp)/(double)tick_packets.size(); 26 | @@ -352,12 +354,13 @@ public abstract class ReplayRecorder { 27 | private final AtomicBoolean metadataQueued = new AtomicBoolean(false); 28 | 29 | private void _save(Packet packet, int timestamp) { 30 | - 31 | + if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("ReplayRecorder._save: "); 32 | if(this.current_file_size.get() > ServerSideReplayRecorderServer.config.getMax_file_size()){ 33 | if (tooBigFileSize.compareAndSet(false,true)) { 34 | ServerSideReplayRecorderServer.LOGGER.warn("Max File Size Reached, stopping recording %s:%s".formatted(this.getClass().getSimpleName(), this.getRecordingName())); 35 | this.handleDisconnect(true); 36 | } 37 | + if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("ReplayRecorder._save: big return"); 38 | return; 39 | } 40 | 41 | @@ -388,13 +391,15 @@ public abstract class ReplayRecorder { 42 | } 43 | 44 | if (packetId == null) { 45 | + if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("ReplayRecorder._save: packetId null"); 46 | //The packet ID is something we do not have an ID for. 47 | throw new IOException("Unknown packet ID for class " + packet.getClass()); 48 | } else { 49 | + if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("ReplayRecorder._save: packetId:" + packetId); 50 | //Write the packet ID. 51 | buffer.write(packetId); 52 | } 53 | - 54 | + if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("ReplayRecorder._save: Write packet"); 55 | //Write the packet. 56 | buffer.write(buf.array(), 0, buf.readableBytes()); 57 | bos.write(buffer.toByteArray()); 58 | -------------------------------------------------------------------------------- /patches/server/0012-ServerSideRecorder.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Bryan1029384756 <23323626+Bryan1029384756@users.noreply.github.com> 3 | Date: Sun, 18 Jun 2023 20:53:18 -0500 4 | Subject: [PATCH] ServerSideRecorder 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/recorder/ReplayRecorder.java b/src/main/java/net/minecraft/serversidereplayrecorder/recorder/ReplayRecorder.java 8 | index 4c1e74dc5acb0519a15f7274f3e7983737292f09..0580cd5d9c7512b8e6d04c363ba6d48e28ee8535 100644 9 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/recorder/ReplayRecorder.java 10 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/recorder/ReplayRecorder.java 11 | @@ -271,6 +271,7 @@ public abstract class ReplayRecorder { 12 | Runnable endTask = () -> { 13 | try { 14 | try { 15 | + 16 | bos.close(); 17 | fos.close(); 18 | if (debugFile != null) { 19 | -------------------------------------------------------------------------------- /patches/server/0013-ServerSideRecorder.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Bryan1029384756 <23323626+Bryan1029384756@users.noreply.github.com> 3 | Date: Sun, 18 Jun 2023 21:28:20 -0500 4 | Subject: [PATCH] ServerSideRecorder 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java 8 | index 1bd7c0404d4252ee1bc4f2fbd42b4756e22752e2..b972534be2e59a2f0759100537746889fb657c82 100644 9 | --- a/src/main/java/net/minecraft/network/Connection.java 10 | +++ b/src/main/java/net/minecraft/network/Connection.java 11 | @@ -851,12 +851,7 @@ public class Connection extends SimpleChannelInboundHandler> implement 12 | if (this.disconnectionHandled) { 13 | //Connection.LOGGER.warn("handleDisconnection() called twice"); // Paper - Do not log useless message 14 | } else { 15 | - //ServersideRecorder start 16 | - if(this.getRecorder() != null){ 17 | - if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("Connection.handleDisconnection: disconnected"); 18 | - this.getRecorder().handleDisconnect(); 19 | - } 20 | - //ServersideRecorder end 21 | + 22 | this.disconnectionHandled = true; 23 | if (this.getDisconnectedReason() != null) { 24 | this.getPacketListener().onDisconnect(this.getDisconnectedReason()); 25 | diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java 26 | index 2a609e43370e68943c580083f7f7d8c9b0972955..63cf2c1fa0dc5af7d15198fbdb5a7b0b959174e0 100644 27 | --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java 28 | +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java 29 | @@ -135,6 +135,7 @@ import net.minecraft.resources.ResourceLocation; 30 | import net.minecraft.server.MinecraftServer; 31 | import net.minecraft.server.level.ServerLevel; 32 | import net.minecraft.server.level.ServerPlayer; 33 | +import net.minecraft.serversidereplayrecorder.ServerSideReplayRecorderServer; 34 | import net.minecraft.stats.ServerRecipeBook; 35 | import net.minecraft.util.FutureChain; 36 | import net.minecraft.util.Mth; 37 | @@ -484,6 +485,13 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic 38 | } 39 | 40 | public void disconnect(net.kyori.adventure.text.Component reason, org.bukkit.event.player.PlayerKickEvent.Cause cause) { 41 | + //ServersideRecorder start 42 | + if(this.connection.getRecorder() != null){ 43 | + if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("Connection.handleDisconnection: disconnected"); 44 | + this.connection.getRecorder().handleDisconnect(); 45 | + } 46 | + //ServersideRecorder end 47 | + 48 | // Paper end 49 | // CraftBukkit start - fire PlayerKickEvent 50 | if (this.processedDisconnect) { 51 | -------------------------------------------------------------------------------- /patches/server/0014-ServerSideRecorder.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Bryan1029384756 <23323626+Bryan1029384756@users.noreply.github.com> 3 | Date: Sun, 18 Jun 2023 21:33:07 -0500 4 | Subject: [PATCH] ServerSideRecorder 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java 8 | index 63cf2c1fa0dc5af7d15198fbdb5a7b0b959174e0..f3bc5eb88fdd93fbe7fc914c43f20217cd591d98 100644 9 | --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java 10 | +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java 11 | @@ -486,8 +486,9 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic 12 | 13 | public void disconnect(net.kyori.adventure.text.Component reason, org.bukkit.event.player.PlayerKickEvent.Cause cause) { 14 | //ServersideRecorder start 15 | + if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("ServerGamePacketListenerImpl.disconnect: disconnected"); 16 | if(this.connection.getRecorder() != null){ 17 | - if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("Connection.handleDisconnection: disconnected"); 18 | + if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("ServerGamePacketListenerImpl.disconnect: getRecorder"); 19 | this.connection.getRecorder().handleDisconnect(); 20 | } 21 | //ServersideRecorder end 22 | -------------------------------------------------------------------------------- /patches/server/0015-ServerSideRecorder.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Bryan1029384756 <23323626+Bryan1029384756@users.noreply.github.com> 3 | Date: Sun, 18 Jun 2023 21:37:53 -0500 4 | Subject: [PATCH] ServerSideRecorder 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java 8 | index f3bc5eb88fdd93fbe7fc914c43f20217cd591d98..63502534ec83643a9778d22d51b4ebc2a93d9e49 100644 9 | --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java 10 | +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java 11 | @@ -485,13 +485,6 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic 12 | } 13 | 14 | public void disconnect(net.kyori.adventure.text.Component reason, org.bukkit.event.player.PlayerKickEvent.Cause cause) { 15 | - //ServersideRecorder start 16 | - if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("ServerGamePacketListenerImpl.disconnect: disconnected"); 17 | - if(this.connection.getRecorder() != null){ 18 | - if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("ServerGamePacketListenerImpl.disconnect: getRecorder"); 19 | - this.connection.getRecorder().handleDisconnect(); 20 | - } 21 | - //ServersideRecorder end 22 | 23 | // Paper end 24 | // CraftBukkit start - fire PlayerKickEvent 25 | @@ -2107,6 +2100,15 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic 26 | 27 | @Override 28 | public void onDisconnect(Component reason) { 29 | + //ServersideRecorder start 30 | + if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("ServerGamePacketListenerImpl.disconnect: disconnected"); 31 | + if(this.connection.getRecorder() != null){ 32 | + if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("ServerGamePacketListenerImpl.disconnect: getRecorder"); 33 | + this.connection.getRecorder().handleDisconnect(); 34 | + }else{ 35 | + if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("ServerGamePacketListenerImpl.disconnect: getRecorder null"); 36 | + } 37 | + //ServersideRecorder end 38 | // Paper start 39 | this.onDisconnect(reason, null); 40 | } 41 | -------------------------------------------------------------------------------- /patches/server/0016-ServerSideRecorder.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Bryan1029384756 <23323626+Bryan1029384756@users.noreply.github.com> 3 | Date: Sun, 18 Jun 2023 21:54:16 -0500 4 | Subject: [PATCH] ServerSideRecorder 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java 8 | index b972534be2e59a2f0759100537746889fb657c82..6f7cbd65c8e6f539ba5228401549390b191f9c83 100644 9 | --- a/src/main/java/net/minecraft/network/Connection.java 10 | +++ b/src/main/java/net/minecraft/network/Connection.java 11 | @@ -54,7 +54,7 @@ import org.slf4j.Logger; 12 | import org.slf4j.Marker; 13 | import org.slf4j.MarkerFactory; 14 | 15 | -public class Connection extends SimpleChannelInboundHandler> implements RecorderHolder { 16 | +public class Connection extends SimpleChannelInboundHandler> { 17 | 18 | private static final float AVERAGE_PACKETS_SMOOTHING = 0.75F; 19 | private static final Logger LOGGER = LogUtils.getLogger(); 20 | @@ -86,23 +86,6 @@ public class Connection extends SimpleChannelInboundHandler> implement 21 | 22 | 23 | 24 | - //Serversiderecorder start 25 | - WeakReference recorder = new WeakReference<>(null); 26 | - 27 | - @Override 28 | - public void setRecorder(ReplayRecorder recorder){ 29 | - if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("Connection.setRecorder: "); 30 | - this.recorder = new WeakReference<>(recorder); 31 | - } 32 | - 33 | - @Override 34 | - public ReplayRecorder getRecorder() { 35 | - if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("Connection.getRecorder: "); 36 | - return this.recorder.get(); 37 | - } 38 | - //Serversiderecorder end 39 | - 40 | - 41 | 42 | // Spigot Start 43 | public java.util.UUID spoofedUUID; 44 | @@ -438,17 +421,6 @@ public class Connection extends SimpleChannelInboundHandler> implement 45 | } 46 | this.flushQueue(); 47 | // Paper end 48 | - 49 | - //Serversiderecorder start 50 | - if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("Connection.send: "); 51 | - ReplayRecorder recorder = this.recorder.get(); 52 | - if (recorder != null){ 53 | - if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("Connection.send: packet"); 54 | - recorder.onPacket(packet); 55 | - }else{ 56 | - if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("Connection.send: recorder null"); 57 | - } 58 | - //Serversiderecorder end 59 | } 60 | 61 | private void sendPacket(Packet packet, @Nullable PacketSendListener callbacks) { 62 | diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java 63 | index 63502534ec83643a9778d22d51b4ebc2a93d9e49..d1ff154b6bba9b4233d0b989c26ec3730f3b6961 100644 64 | --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java 65 | +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java 66 | @@ -9,6 +9,8 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap.Entry; 67 | import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; 68 | import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; 69 | import it.unimi.dsi.fastutil.objects.ObjectIterator; 70 | + 71 | +import java.lang.ref.WeakReference; 72 | import java.net.SocketAddress; 73 | import java.time.Duration; 74 | import java.time.Instant; 75 | @@ -136,6 +138,9 @@ import net.minecraft.server.MinecraftServer; 76 | import net.minecraft.server.level.ServerLevel; 77 | import net.minecraft.server.level.ServerPlayer; 78 | import net.minecraft.serversidereplayrecorder.ServerSideReplayRecorderServer; 79 | +import net.minecraft.serversidereplayrecorder.recorder.PlayerRecorder; 80 | +import net.minecraft.serversidereplayrecorder.recorder.ReplayRecorder; 81 | +import net.minecraft.serversidereplayrecorder.util.interfaces.RecorderHolder; 82 | import net.minecraft.stats.ServerRecipeBook; 83 | import net.minecraft.util.FutureChain; 84 | import net.minecraft.util.Mth; 85 | @@ -248,7 +253,7 @@ import org.bukkit.inventory.InventoryView; 86 | import org.bukkit.inventory.SmithingInventory; 87 | // CraftBukkit end 88 | 89 | -public class ServerGamePacketListenerImpl implements ServerPlayerConnection, TickablePacketListener, ServerGamePacketListener { 90 | +public class ServerGamePacketListenerImpl implements ServerPlayerConnection, TickablePacketListener, ServerGamePacketListener,RecorderHolder { 91 | 92 | static final Logger LOGGER = LogUtils.getLogger(); 93 | private static final int LATENCY_CHECK_INTERVAL = 15000; 94 | @@ -322,8 +327,33 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic 95 | this.chatMessageChain = new FutureChain(server.chatExecutor); // CraftBukkit - async chat 96 | // CraftBukkit start - add fields and methods 97 | this.cserver = server.server; 98 | + 99 | + //Serversiderecorder start 100 | + ReplayRecorder recorder = PlayerRecorder.playerRecorderMap.get(connection); 101 | + if (recorder != null){ 102 | + this.setRecorder(recorder); 103 | + } 104 | + //Serversiderecorder end 105 | + } 106 | + 107 | + 108 | + 109 | + //Serversiderecorder start 110 | + WeakReference recorder = new WeakReference<>(null); 111 | + 112 | + @Override 113 | + public void setRecorder(ReplayRecorder recorder){ 114 | + if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("Connection.setRecorder: "); 115 | + this.recorder = new WeakReference<>(recorder); 116 | } 117 | 118 | + @Override 119 | + public ReplayRecorder getRecorder() { 120 | + if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("Connection.getRecorder: "); 121 | + return this.recorder.get(); 122 | + } 123 | + //Serversiderecorder end 124 | + 125 | private final org.bukkit.craftbukkit.CraftServer cserver; 126 | public boolean processedDisconnect; 127 | private int lastTick = MinecraftServer.currentTick; 128 | @@ -2102,9 +2132,10 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic 129 | public void onDisconnect(Component reason) { 130 | //ServersideRecorder start 131 | if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("ServerGamePacketListenerImpl.disconnect: disconnected"); 132 | - if(this.connection.getRecorder() != null){ 133 | + 134 | + if(this.getRecorder() != null){ 135 | if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("ServerGamePacketListenerImpl.disconnect: getRecorder"); 136 | - this.connection.getRecorder().handleDisconnect(); 137 | + this.getRecorder().handleDisconnect(); 138 | }else{ 139 | if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("ServerGamePacketListenerImpl.disconnect: getRecorder null"); 140 | } 141 | @@ -2113,6 +2144,12 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic 142 | this.onDisconnect(reason, null); 143 | } 144 | public void onDisconnect(Component reason, @Nullable net.kyori.adventure.text.Component quitMessage) { 145 | + //Serversiderecorder start 146 | + ReplayRecorder recorder = this.getRecorder(); 147 | + if (recorder != null){ 148 | + recorder.handleDisconnect(); 149 | + } 150 | + //Serversiderecorder end 151 | // Paper end 152 | // CraftBukkit start - Rarely it would send a disconnect line twice 153 | if (this.processedDisconnect) { 154 | @@ -2180,6 +2217,17 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic 155 | }); 156 | throw new ReportedException(crashreport); 157 | } 158 | + 159 | + //Serversiderecorder start 160 | + if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("Connection.send: "); 161 | + ReplayRecorder recorder = this.getRecorder(); 162 | + if (recorder != null){ 163 | + if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("Connection.send: packet"); 164 | + recorder.onPacket(packet); 165 | + }else{ 166 | + if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("Connection.send: recorder null"); 167 | + } 168 | + //Serversiderecorder end 169 | } 170 | 171 | @Override 172 | diff --git a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java 173 | index 592eed28a8a700b02040689bf215ed7320bc518e..16489f145ff2b8d1697bd1ac709951774912e641 100644 174 | --- a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java 175 | +++ b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java 176 | @@ -38,13 +38,6 @@ public class ServerHandshakePacketListenerImpl implements ServerHandshakePacketL 177 | 178 | 179 | public ServerHandshakePacketListenerImpl(MinecraftServer server, Connection connection) { 180 | - //Serversiderecorder start 181 | - ReplayRecorder recorder = PlayerRecorder.playerRecorderMap.get(connection); 182 | - if (recorder != null){ 183 | - connection.setRecorder(recorder); 184 | - } 185 | - //Serversiderecorder end 186 | - 187 | this.server = server; 188 | this.connection = connection; 189 | } 190 | @@ -183,12 +176,7 @@ public class ServerHandshakePacketListenerImpl implements ServerHandshakePacketL 191 | 192 | @Override 193 | public void onDisconnect(Component reason) { 194 | - //Serversiderecorder start 195 | - ReplayRecorder recorder = this.connection.getRecorder(); 196 | - if (recorder != null){ 197 | - recorder.handleDisconnect(); 198 | - } 199 | - //Serversiderecorder end 200 | + 201 | } 202 | 203 | @Override 204 | -------------------------------------------------------------------------------- /patches/server/0017-ServerSideRecorder.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Bryan1029384756 <23323626+Bryan1029384756@users.noreply.github.com> 3 | Date: Sun, 18 Jun 2023 22:03:16 -0500 4 | Subject: [PATCH] ServerSideRecorder 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java 8 | index 6f7cbd65c8e6f539ba5228401549390b191f9c83..9a2777e39c0182bb6cfa302fac407783b3925f17 100644 9 | --- a/src/main/java/net/minecraft/network/Connection.java 10 | +++ b/src/main/java/net/minecraft/network/Connection.java 11 | @@ -44,9 +44,6 @@ import net.minecraft.network.protocol.game.ClientboundDisconnectPacket; 12 | import net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacket; 13 | import net.minecraft.server.MinecraftServer; 14 | import net.minecraft.server.RunningOnDifferentThreadException; 15 | -import net.minecraft.serversidereplayrecorder.ServerSideReplayRecorderServer; 16 | -import net.minecraft.serversidereplayrecorder.recorder.ReplayRecorder; 17 | -import net.minecraft.serversidereplayrecorder.util.interfaces.RecorderHolder; 18 | import net.minecraft.util.LazyLoadedValue; 19 | import net.minecraft.util.Mth; 20 | import org.apache.commons.lang3.Validate; 21 | diff --git a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java 22 | index 16489f145ff2b8d1697bd1ac709951774912e641..6b5a0ad2fd19361bc44f683d56656e8e7b9e7bc5 100644 23 | --- a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java 24 | +++ b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java 25 | @@ -4,15 +4,11 @@ import net.minecraft.SharedConstants; 26 | import net.minecraft.network.Connection; 27 | import net.minecraft.network.ConnectionProtocol; 28 | import net.minecraft.network.chat.Component; 29 | -import net.minecraft.network.chat.MutableComponent; 30 | import net.minecraft.network.protocol.handshake.ClientIntentionPacket; 31 | import net.minecraft.network.protocol.handshake.ServerHandshakePacketListener; 32 | import net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacket; 33 | import net.minecraft.network.protocol.status.ServerStatus; 34 | import net.minecraft.server.MinecraftServer; 35 | -import net.minecraft.serversidereplayrecorder.recorder.PlayerRecorder; 36 | -import net.minecraft.serversidereplayrecorder.recorder.ReplayRecorder; 37 | -import net.minecraft.serversidereplayrecorder.util.interfaces.RecorderHolder; 38 | 39 | // CraftBukkit start 40 | import java.lang.ref.WeakReference; 41 | diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java 42 | index 99b9015aa628ea2434f2a9b697565f6f3524cf4c..1aa50493969f2fb841274ba24a30409812daf07d 100644 43 | --- a/src/main/java/net/minecraft/server/players/PlayerList.java 44 | +++ b/src/main/java/net/minecraft/server/players/PlayerList.java 45 | @@ -1198,7 +1198,7 @@ public abstract class PlayerList { 46 | 47 | if (player != null) { 48 | if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("PlayerList.broadcast: player"); 49 | - ReplayRecorder recorder = ((RecorderHolder)(((ServerPlayer) player).connection.connection)).getRecorder(); 50 | + ReplayRecorder recorder = ((RecorderHolder)(((ServerPlayer) player).connection)).getRecorder(); 51 | if (recorder != null) { 52 | if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("PlayerList.broadcast: recorder"); 53 | recorder.onPacket(packet); 54 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/ServerSideReplayRecorderServer.java b/src/main/java/net/minecraft/serversidereplayrecorder/ServerSideReplayRecorderServer.java 55 | index a0cf4c044850fcfc7dcc33182716893466184b29..ae3826202dd3d14bd833caa50bc4ae47c286bff2 100644 56 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/ServerSideReplayRecorderServer.java 57 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/ServerSideReplayRecorderServer.java 58 | @@ -73,12 +73,10 @@ public class ServerSideReplayRecorderServer { 59 | } 60 | 61 | public static String getConfigDirectory(){ 62 | - System.out.println(System.getProperty("user.dir") + "\\config"); 63 | return System.getProperty("user.dir") + "\\config"; 64 | } 65 | 66 | public static String getDirectory(){ 67 | - System.out.println(System.getProperty("user.dir")); 68 | return System.getProperty("user.dir"); 69 | } 70 | 71 | -------------------------------------------------------------------------------- /patches/server/0018-ServerSideRecorder.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Bryan1029384756 <23323626+Bryan1029384756@users.noreply.github.com> 3 | Date: Mon, 19 Jun 2023 18:29:18 -0500 4 | Subject: [PATCH] ServerSideRecorder 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java 8 | index 1aa50493969f2fb841274ba24a30409812daf07d..8c54cf82a5bfccfb28cf73797dff5c595caf6404 100644 9 | --- a/src/main/java/net/minecraft/server/players/PlayerList.java 10 | +++ b/src/main/java/net/minecraft/server/players/PlayerList.java 11 | @@ -171,9 +171,9 @@ public abstract class PlayerList { 12 | 13 | public void placeNewPlayer(Connection connection, ServerPlayer player) { 14 | //ServerSideReplayRecorder start 15 | -// if (ServerSideReplayRecorderServer.config.isRecording_enabled() && !PlayerRecorder.playerRecorderMap.containsKey(connection) 16 | -// && ( ServerSideReplayRecorderServer.config.getRecordable_users().contains(player.getGameProfile().getName())) != ServerSideReplayRecorderServer.config.invert_user_list() ) { 17 | - if (!PlayerRecorder.playerRecorderMap.containsKey(connection)) { 18 | + if (ServerSideReplayRecorderServer.config.isRecording_enabled() && !PlayerRecorder.playerRecorderMap.containsKey(connection) 19 | + && ( ServerSideReplayRecorderServer.config.getRecordable_users().contains(player.getGameProfile().getName())) != ServerSideReplayRecorderServer.config.invert_user_list() ) { 20 | + // if (!PlayerRecorder.playerRecorderMap.containsKey(connection)) { 21 | if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("PlayerList.placeNewPlayer: "); 22 | try { 23 | ServerSideReplayRecorderServer.LOGGER.info("Started Recording Player %s".formatted(player.getGameProfile().getName())); 24 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/ServerSideReplayRecorderServer.java b/src/main/java/net/minecraft/serversidereplayrecorder/ServerSideReplayRecorderServer.java 25 | index ae3826202dd3d14bd833caa50bc4ae47c286bff2..1d6673b4e81a4f322cfde4b22779a999c134cf56 100644 26 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/ServerSideReplayRecorderServer.java 27 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/ServerSideReplayRecorderServer.java 28 | @@ -23,16 +23,14 @@ public class ServerSideReplayRecorderServer { 29 | builder.disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER); 30 | builder.enable(YAMLGenerator.Feature.INDENT_ARRAYS_WITH_INDICATOR); 31 | yaml = new ObjectMapper(builder.build()).configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 32 | - // placeholders = ResourceBundle.getBundle("placeholders"); 33 | - //upload_sites = ResourceBundle.getBundle("upload_sites"); 34 | + upload_sites = ResourceBundle.getBundle("upload_sites"); 35 | } 36 | 37 | public static final ExecutorService recorderExecutor = Executors.newSingleThreadExecutor(new DefaultThreadFactory("Replay",true)); 38 | 39 | private static final ObjectMapper yaml; 40 | 41 | - //public static final ResourceBundle placeholders; 42 | - //public static final ResourceBundle upload_sites; 43 | + public static final ResourceBundle upload_sites; 44 | 45 | public static final Logger LOGGER = LoggerFactory.getLogger(ServerSideReplayRecorderServer.class.getName()); 46 | 47 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/config/MainConfig.java b/src/main/java/net/minecraft/serversidereplayrecorder/config/MainConfig.java 48 | index ebd564edbbf60f603e0cf642af99c2f8f5bf1601..8e2d0ec530e408e572d1f0af38f6206e1fa94af7 100644 49 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/config/MainConfig.java 50 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/config/MainConfig.java 51 | @@ -17,7 +17,7 @@ public class MainConfig { 52 | private String server_name = "My Server"; 53 | private Set recordable_users = new HashSet<>(); 54 | private boolean invert_user_list = false; 55 | - private boolean recording_enabled = false; 56 | + private boolean recording_enabled = true; 57 | private boolean use_server_timestamps = true; 58 | private boolean assume_unloaded_chunks_dont_change = true; 59 | private boolean render_distance_fog_fix = false; 60 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/recorder/ReplayRecorder.java b/src/main/java/net/minecraft/serversidereplayrecorder/recorder/ReplayRecorder.java 61 | index 0580cd5d9c7512b8e6d04c363ba6d48e28ee8535..f0627468012f1725ff4493e559ad8636e122460e 100644 62 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/recorder/ReplayRecorder.java 63 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/recorder/ReplayRecorder.java 64 | @@ -125,7 +125,6 @@ public abstract class ReplayRecorder { 65 | object.addProperty("fileFormat", "MCPR"); 66 | object.addProperty("fileFormatVersion", 14); //Unlikely to change any time soon, last time this was updates was several major versions ago. 67 | object.addProperty("protocol", SharedConstants.getProtocolVersion()); 68 | - // object.addProperty("generator", "thecolonel63's Server Side Replay Recorder " + placeholders.getString("version") + "-" + placeholders.getString("build")); 69 | object.addProperty("selfId", -1); 70 | object.add("players", new JsonArray()); 71 | FileWriter fw = new FileWriter(Paths.get(tmp_folder.getAbsolutePath(), "metaData.json").toFile(), false); 72 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/util/FileHandlingUtility.java b/src/main/java/net/minecraft/serversidereplayrecorder/util/FileHandlingUtility.java 73 | index 13ffb6123158c09605a0030afa35d2ca541eb5ad..19e7c8fa2c1390f534972884ddd9877fbf73f2b0 100644 74 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/util/FileHandlingUtility.java 75 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/util/FileHandlingUtility.java 76 | @@ -1,5 +1,7 @@ 77 | package net.minecraft.serversidereplayrecorder.util; 78 | 79 | +import net.minecraft.ChatFormatting; 80 | +import net.minecraft.network.chat.ClickEvent; 81 | import net.minecraft.network.chat.Component; 82 | import net.minecraft.serversidereplayrecorder.ServerSideReplayRecorderServer; 83 | import org.jetbrains.annotations.NotNull; 84 | @@ -149,18 +151,18 @@ public class FileHandlingUtility { 85 | 86 | Component response_text = Component.literal(response); 87 | 88 | -// if (ServerSideReplayRecorderServer.upload_sites.containsKey(url.getHost())){ 89 | -// String regex = ServerSideReplayRecorderServer.upload_sites.getString(url.getHost()); 90 | -// Pattern pattern = Pattern.compile(regex); 91 | -// Matcher matcher = pattern.matcher(response); 92 | -// if (matcher.find()){ 93 | -// String download_url = matcher.group(1); 94 | -// response_text = Component.literal("%s download link: ".formatted(file.getName())).formatted(Formatting.YELLOW) 95 | -// .append(Component.literal(download_url) 96 | -// .formatted(Formatting.UNDERLINE,Formatting.BLUE) 97 | -// .styled(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, download_url)))); 98 | -// } 99 | -// } 100 | + if (ServerSideReplayRecorderServer.upload_sites.containsKey(url.getHost())){ 101 | + String regex = ServerSideReplayRecorderServer.upload_sites.getString(url.getHost()); 102 | + Pattern pattern = Pattern.compile(regex); 103 | + Matcher matcher = pattern.matcher(response); 104 | + if (matcher.find()){ 105 | + String download_url = matcher.group(1); 106 | + response_text = Component.literal("%s download link: ".formatted(file.getName())).withStyle(ChatFormatting.YELLOW) 107 | + .append(Component.literal(download_url) 108 | + .withStyle(ChatFormatting.UNDERLINE,ChatFormatting.BLUE) 109 | + .withStyle(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, download_url)))); 110 | + } 111 | + } 112 | 113 | return response_text; 114 | } 115 | diff --git a/src/main/resources/upload_sites.properties b/src/main/resources/upload_sites.properties 116 | new file mode 100644 117 | index 0000000000000000000000000000000000000000..49bc43c610f43604db01e254929d3c27c7152d70 118 | --- /dev/null 119 | +++ b/src/main/resources/upload_sites.properties 120 | @@ -0,0 +1,2 @@ 121 | +file.io: \\{"success":true,"status":200,.*"link":"(http[^"]+)".*\\} 122 | +tmpfiles.org: \\{"status":"success",.*"data":\\{.*"url":"(http[^"]+)".*\\}.*\\} 123 | \ No newline at end of file 124 | -------------------------------------------------------------------------------- /patches/server/0019-ServerSideRecorder.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Bryan1029384756 <23323626+Bryan1029384756@users.noreply.github.com> 3 | Date: Mon, 19 Jun 2023 18:37:49 -0500 4 | Subject: [PATCH] ServerSideRecorder 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/command/ReplayCommand.java b/src/main/java/net/minecraft/serversidereplayrecorder/command/ReplayCommand.java 8 | index 50634cba3a60eea3d8474c88e8a34f1c97c8fdf0..d598a7901459fef7334025ca83758b8df0d0c99d 100644 9 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/command/ReplayCommand.java 10 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/command/ReplayCommand.java 11 | @@ -180,7 +180,7 @@ public class ReplayCommand { 12 | }); 13 | if (count.get() > 0) { 14 | source.sendSuccess(()->Component.literal("Added players will start recording next time they join the server"), true); 15 | - //ServerSideReplayRecorderServer.saveConfig(); 16 | + ServerSideReplayRecorderServer.saveConfig(); 17 | } 18 | return 0; 19 | }) 20 | -------------------------------------------------------------------------------- /patches/server/0021-ServerSideVoiceChat.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Bryan1029384756 <23323626+Bryan1029384756@users.noreply.github.com> 3 | Date: Sun, 25 Jun 2023 18:23:30 -0500 4 | Subject: [PATCH] ServerSideVoiceChat 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/voice/ServerSideVoiceChat.java b/src/main/java/net/minecraft/serversidereplayrecorder/voice/ServerSideVoiceChat.java 8 | index b5ddb3a6b717d283f2f7cc3b475b03aa0b527ea6..093d1a39efe81c137674d6c650a31bf243ecdbf7 100644 9 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/voice/ServerSideVoiceChat.java 10 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/voice/ServerSideVoiceChat.java 11 | @@ -2,11 +2,12 @@ package net.minecraft.serversidereplayrecorder.voice; 12 | 13 | import de.maxhenkel.voicechat.api.VoicechatApi; 14 | import de.maxhenkel.voicechat.api.VoicechatPlugin; 15 | -import de.maxhenkel.voicechat.api.events.EventRegistration; 16 | -import de.maxhenkel.voicechat.api.events.MicrophonePacketEvent; 17 | +import de.maxhenkel.voicechat.api.VoicechatServerApi; 18 | +import de.maxhenkel.voicechat.api.events.*; 19 | import de.maxhenkel.voicechat.api.opus.OpusDecoder; 20 | import net.minecraft.server.level.ServerPlayer; 21 | import net.minecraft.serversidereplayrecorder.ServerSideReplayRecorderServer; 22 | +import net.minecraft.serversidereplayrecorder.voice.recording.VoicechatRecorder; 23 | import org.bukkit.Bukkit; 24 | import javax.sound.sampled.*; 25 | import java.io.*; 26 | @@ -18,7 +19,8 @@ import java.util.*; 27 | public class ServerSideVoiceChat implements VoicechatPlugin { 28 | 29 | private OpusDecoder decoder; 30 | - 31 | + public static double distance; 32 | + public static VoicechatApi SERVERAPI; 33 | @Override 34 | public String getPluginId() { 35 | return "PaperRecord"; 36 | @@ -27,15 +29,22 @@ public class ServerSideVoiceChat implements VoicechatPlugin { 37 | @Override 38 | public void initialize(VoicechatApi api) { 39 | System.out.println("Started recording voice chat using PaperRecord"); 40 | + this.distance = api.getVoiceChatDistance(); 41 | + this.SERVERAPI = api; 42 | } 43 | 44 | @Override 45 | public void registerEvents(EventRegistration registration) { 46 | - registration.registerEvent(MicrophonePacketEvent.class, this::onSound); 47 | + registration.registerEvent(EntitySoundPacketEvent.class, VoicechatRecorder::onEntitySound); 48 | + registration.registerEvent(LocationalSoundPacketEvent.class, VoicechatRecorder::onLocationalSound); 49 | + registration.registerEvent(StaticSoundPacketEvent.class, VoicechatRecorder::onStaticSound); 50 | + //registration.registerEvent(ClientSoundEvent.class, VoicechatRecorder::onSound); 51 | + // registration.registerEvent(MicrophonePacketEvent.class, this::onSound); 52 | } 53 | 54 | 55 | 56 | + 57 | public Map> playerPacketMap = new HashMap<>(); 58 | private Map lastPacketTimeMap = new HashMap<>(); 59 | private static final int FRAME_SIZE_MS = 20; // Frame size in milliseconds 60 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/voice/Utils.java b/src/main/java/net/minecraft/serversidereplayrecorder/voice/Utils.java 61 | new file mode 100644 62 | index 0000000000000000000000000000000000000000..36132fcf9b14c52b9e81929172fea8277b28fbc8 63 | --- /dev/null 64 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/voice/Utils.java 65 | @@ -0,0 +1,34 @@ 66 | +package net.minecraft.serversidereplayrecorder.voice; 67 | + 68 | +public class Utils { 69 | + 70 | + public static short[] bytesToShorts(byte[] bytes) { 71 | + if (bytes.length % 2 != 0) { 72 | + throw new IllegalArgumentException("Input bytes need to be divisible by 2"); 73 | + } 74 | + short[] data = new short[bytes.length / 2]; 75 | + for (int i = 0; i < bytes.length; i += 2) { 76 | + data[i / 2] = bytesToShort(bytes[i], bytes[i + 1]); 77 | + } 78 | + return data; 79 | + } 80 | + 81 | + public static byte[] shortsToBytes(short[] shorts) { 82 | + byte[] data = new byte[shorts.length * 2]; 83 | + for (int i = 0; i < shorts.length; i++) { 84 | + byte[] split = shortToBytes(shorts[i]); 85 | + data[i * 2] = split[0]; 86 | + data[i * 2 + 1] = split[1]; 87 | + } 88 | + return data; 89 | + } 90 | + 91 | + public static short bytesToShort(byte b1, byte b2) { 92 | + return (short) (((b2 & 0xFF) << 8) | (b1 & 0xFF)); 93 | + } 94 | + 95 | + public static byte[] shortToBytes(short s) { 96 | + return new byte[]{(byte) (s & 0xFF), (byte) ((s >> 8) & 0xFF)}; 97 | + } 98 | + 99 | +} 100 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/AbstractSoundPacket.java b/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/AbstractSoundPacket.java 101 | new file mode 100644 102 | index 0000000000000000000000000000000000000000..9546f9d8e0fcc92d049a2e716398556f1b24a141 103 | --- /dev/null 104 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/AbstractSoundPacket.java 105 | @@ -0,0 +1,51 @@ 106 | +package net.minecraft.serversidereplayrecorder.voice.net; 107 | + 108 | +import net.minecraft.network.FriendlyByteBuf; 109 | +import net.minecraft.serversidereplayrecorder.voice.Utils; 110 | + 111 | +import java.util.UUID; 112 | + 113 | +public abstract class AbstractSoundPacket> implements Packet { 114 | + 115 | + public static final short CURRENT_VERSION = 1; 116 | + 117 | + protected short version; 118 | + protected UUID id; 119 | + protected short[] rawAudio; 120 | + 121 | + public AbstractSoundPacket(UUID id, short[] rawAudio) { 122 | + version = CURRENT_VERSION; 123 | + this.id = id; 124 | + this.rawAudio = rawAudio; 125 | + } 126 | + 127 | + public AbstractSoundPacket() { 128 | + 129 | + } 130 | + 131 | + public UUID getId() { 132 | + return id; 133 | + } 134 | + 135 | + public short[] getRawAudio() { 136 | + return rawAudio; 137 | + } 138 | + 139 | + @Override 140 | + public T fromBytes(FriendlyByteBuf buf) throws VersionCompatibilityException { 141 | + version = buf.readShort(); 142 | + if (version != CURRENT_VERSION && version != 0) { 143 | + throw new VersionCompatibilityException("Incompatible version"); 144 | + } 145 | + id = buf.readUUID(); 146 | + rawAudio = Utils.bytesToShorts(buf.readByteArray()); 147 | + return (T) this; 148 | + } 149 | + 150 | + @Override 151 | + public void toBytes(FriendlyByteBuf buf) { 152 | + buf.writeShort(version); 153 | + buf.writeUUID(id); 154 | + buf.writeByteArray(Utils.shortsToBytes(rawAudio)); 155 | + } 156 | +} 157 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/EntitySoundPacket.java b/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/EntitySoundPacket.java 158 | new file mode 100644 159 | index 0000000000000000000000000000000000000000..f767678d31b5c8525eaf501878e112b4cb0c277b 160 | --- /dev/null 161 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/EntitySoundPacket.java 162 | @@ -0,0 +1,64 @@ 163 | +package net.minecraft.serversidereplayrecorder.voice.net; 164 | + 165 | + 166 | +import net.minecraft.network.FriendlyByteBuf; 167 | +import net.minecraft.resources.ResourceLocation; 168 | +import net.minecraft.serversidereplayrecorder.voice.ServerSideVoiceChat; 169 | + 170 | +import java.util.UUID; 171 | + 172 | +public class EntitySoundPacket extends AbstractSoundPacket { 173 | + 174 | + public static ResourceLocation ID = new ResourceLocation("PaperRecord", "entity_sound"); 175 | + 176 | + private boolean whispering; 177 | + private float distance; 178 | + 179 | + public EntitySoundPacket(UUID id, short[] rawAudio, boolean whispering, float distance) { 180 | + super(id, rawAudio); 181 | + this.whispering = whispering; 182 | + this.distance = distance; 183 | + } 184 | + 185 | + public EntitySoundPacket() { 186 | + 187 | + } 188 | + 189 | + @Override 190 | + public ResourceLocation getIdentifier() { 191 | + return ID; 192 | + } 193 | + 194 | + public boolean isWhispering() { 195 | + return whispering; 196 | + } 197 | + 198 | + public float getDistance() { 199 | + return distance; 200 | + } 201 | + 202 | + @Override 203 | + public EntitySoundPacket fromBytes(FriendlyByteBuf buf) throws VersionCompatibilityException { 204 | + super.fromBytes(buf); 205 | + whispering = buf.readBoolean(); 206 | + if (version >= 1) { 207 | + distance = buf.readFloat(); 208 | + } else { 209 | + distance = (float) ServerSideVoiceChat.distance; 210 | + } 211 | + return this; 212 | + } 213 | + 214 | + @Override 215 | + public void toBytes(FriendlyByteBuf buf) { 216 | + super.toBytes(buf); 217 | + buf.writeBoolean(whispering); 218 | + buf.writeFloat(distance); 219 | + } 220 | + 221 | +// @Override 222 | +// public void onPacket() { 223 | +// AudioPlaybackManager.INSTANCE.onEntitySound(this); 224 | +// } 225 | + 226 | +} 227 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/LocationalSoundPacket.java b/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/LocationalSoundPacket.java 228 | new file mode 100644 229 | index 0000000000000000000000000000000000000000..a035e09d1f5f1fa6e8e294bd52a25ad0e66683ca 230 | --- /dev/null 231 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/LocationalSoundPacket.java 232 | @@ -0,0 +1,66 @@ 233 | +package net.minecraft.serversidereplayrecorder.voice.net; 234 | + 235 | +import de.maxhenkel.voicechat.api.Position; 236 | +import net.minecraft.network.FriendlyByteBuf; 237 | +import net.minecraft.resources.ResourceLocation; 238 | +import net.minecraft.serversidereplayrecorder.voice.ServerSideVoiceChat; 239 | + 240 | +import java.util.UUID; 241 | + 242 | +public class LocationalSoundPacket extends AbstractSoundPacket { 243 | + 244 | + public static ResourceLocation ID = new ResourceLocation("PaperRecord", "locational_sound"); 245 | + 246 | + private Position location; 247 | + private float distance; 248 | + 249 | + public LocationalSoundPacket(UUID id, short[] rawAudio, Position location, float distance) { 250 | + super(id, rawAudio); 251 | + this.location = location; 252 | + this.distance = distance; 253 | + } 254 | + 255 | + public LocationalSoundPacket() { 256 | + 257 | + } 258 | + 259 | + public Position getLocation() { 260 | + return location; 261 | + } 262 | + 263 | + public float getDistance() { 264 | + return distance; 265 | + } 266 | + 267 | + @Override 268 | + public ResourceLocation getIdentifier() { 269 | + return ID; 270 | + } 271 | + 272 | + @Override 273 | + public LocationalSoundPacket fromBytes(FriendlyByteBuf buf) throws VersionCompatibilityException { 274 | + super.fromBytes(buf); 275 | + location = ServerSideVoiceChat.SERVERAPI.createPosition(buf.readDouble(), buf.readDouble(), buf.readDouble()); 276 | + if (version >= 1) { 277 | + distance = buf.readFloat(); 278 | + } else { 279 | + distance = (float) ServerSideVoiceChat.distance; 280 | + } 281 | + return this; 282 | + } 283 | + 284 | + @Override 285 | + public void toBytes(FriendlyByteBuf buf) { 286 | + super.toBytes(buf); 287 | + buf.writeDouble(location.getX()); 288 | + buf.writeDouble(location.getY()); 289 | + buf.writeDouble(location.getZ()); 290 | + buf.writeFloat(distance); 291 | + } 292 | + 293 | +// @Override 294 | +// public void onPacket() { 295 | +// AudioPlaybackManager.INSTANCE.onLocationalSound(this); 296 | +// } 297 | + 298 | +} 299 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/Packet.java b/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/Packet.java 300 | new file mode 100644 301 | index 0000000000000000000000000000000000000000..0913d06dcdc14c618aea3b8d19b36be16e70ae7e 302 | --- /dev/null 303 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/Packet.java 304 | @@ -0,0 +1,15 @@ 305 | +package net.minecraft.serversidereplayrecorder.voice.net; 306 | + 307 | +import net.minecraft.network.FriendlyByteBuf; 308 | +import net.minecraft.resources.ResourceLocation; 309 | + 310 | +public interface Packet> { 311 | + 312 | + ResourceLocation getIdentifier(); 313 | + 314 | + T fromBytes(FriendlyByteBuf buf) throws VersionCompatibilityException; 315 | + 316 | + void toBytes(FriendlyByteBuf buf); 317 | + 318 | + 319 | +} 320 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/StaticSoundPacket.java b/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/StaticSoundPacket.java 321 | new file mode 100644 322 | index 0000000000000000000000000000000000000000..15934e72e926d4dae343d6fc0b283c078487c741 323 | --- /dev/null 324 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/StaticSoundPacket.java 325 | @@ -0,0 +1,25 @@ 326 | +package net.minecraft.serversidereplayrecorder.voice.net; 327 | + 328 | +import net.minecraft.resources.ResourceLocation; 329 | + 330 | +import java.util.UUID; 331 | + 332 | +public class StaticSoundPacket extends AbstractSoundPacket { 333 | + 334 | + public static ResourceLocation ID = new ResourceLocation("PaperRecord", "static_sound"); 335 | + 336 | + public StaticSoundPacket(UUID id, short[] rawAudio) { 337 | + super(id, rawAudio); 338 | + } 339 | + 340 | + public StaticSoundPacket() { 341 | + 342 | + } 343 | + 344 | + @Override 345 | + public ResourceLocation getIdentifier() { 346 | + return ID; 347 | + } 348 | + 349 | + 350 | +} 351 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/VersionCompatibilityException.java b/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/VersionCompatibilityException.java 352 | new file mode 100644 353 | index 0000000000000000000000000000000000000000..bdeee43a3512ed64d07051d89e49f6dfb7a7379e 354 | --- /dev/null 355 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/VersionCompatibilityException.java 356 | @@ -0,0 +1,8 @@ 357 | +package net.minecraft.serversidereplayrecorder.voice.net; 358 | + 359 | +public class VersionCompatibilityException extends Exception { 360 | + 361 | + public VersionCompatibilityException(String message) { 362 | + super(message); 363 | + } 364 | +} 365 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/voice/recording/VoicechatRecorder.java b/src/main/java/net/minecraft/serversidereplayrecorder/voice/recording/VoicechatRecorder.java 366 | new file mode 100644 367 | index 0000000000000000000000000000000000000000..9f6d7d9e00a8ff4c1a6f5f274ce4479199826496 368 | --- /dev/null 369 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/voice/recording/VoicechatRecorder.java 370 | @@ -0,0 +1,67 @@ 371 | +package net.minecraft.serversidereplayrecorder.voice.recording; 372 | + 373 | + 374 | +import de.maxhenkel.voicechat.api.events.*; 375 | +import de.maxhenkel.voicechat.api.opus.OpusDecoder; 376 | +import de.maxhenkel.voicechat.api.packets.SoundPacket; 377 | +import io.netty.buffer.Unpooled; 378 | +import net.minecraft.network.FriendlyByteBuf; 379 | +import net.minecraft.network.protocol.game.ClientboundCustomPayloadPacket; 380 | +import net.minecraft.server.MinecraftServer; 381 | +import net.minecraft.serversidereplayrecorder.ServerSideReplayRecorderServer; 382 | +import net.minecraft.serversidereplayrecorder.recorder.ReplayRecorder; 383 | +import net.minecraft.serversidereplayrecorder.voice.net.EntitySoundPacket; 384 | +import net.minecraft.serversidereplayrecorder.voice.net.LocationalSoundPacket; 385 | +import net.minecraft.serversidereplayrecorder.voice.net.Packet; 386 | +import net.minecraft.serversidereplayrecorder.voice.net.StaticSoundPacket; 387 | + 388 | +import java.util.UUID; 389 | + 390 | +public class VoicechatRecorder { 391 | + 392 | +// private static final Minecraft MC = Minecraft.getInstance(); 393 | + 394 | + public static void onEntitySound(EntitySoundPacketEvent event) { 395 | + short[] rawAudio = getRawAudio(event, event.getPacket()); 396 | + send(new EntitySoundPacket(event.getPacket().getEntityUuid(), rawAudio, event.getPacket().isWhispering(), event.getPacket().getDistance())); 397 | + } 398 | + 399 | + public static void onLocationalSound(LocationalSoundPacketEvent event) { 400 | + short[] rawAudio = getRawAudio(event, event.getPacket()); 401 | + send(new LocationalSoundPacket(event.getPacket().getSender(), rawAudio, event.getPacket().getPosition(), event.getPacket().getDistance())); 402 | + } 403 | + 404 | + public static void onStaticSound(StaticSoundPacketEvent event) { 405 | + short[] rawAudio = getRawAudio(event, event.getPacket()); 406 | + send(new StaticSoundPacket(event.getPacket().getSender(), rawAudio)); 407 | + } 408 | + 409 | + public static short[] getRawAudio(SoundPacketEvent event, SoundPacket packet){ 410 | + OpusDecoder decoder = event.getVoicechat().createDecoder(); 411 | + 412 | + byte[] opusData = packet.getOpusEncodedData(); 413 | + return decoder.decode(opusData); 414 | + } 415 | + 416 | +// public static void onSound(ClientSoundEvent event) { 417 | +// UUID id = ClientManager.getPlayerStateManager().getOwnID(); 418 | +// short[] rawAudio = event.getRawAudio(); 419 | +// 420 | +// if (ReplayVoicechatPlugin.CLIENT_API.getGroup() != null) { 421 | +// send(new StaticSoundPacket(id, rawAudio)); 422 | +// } else { 423 | +// send(new EntitySoundPacket(id, rawAudio, event.isWhispering(), (float) ReplayVoicechatPlugin.CLIENT_API.getVoiceChatDistance())); 424 | +// } 425 | +// } 426 | + 427 | + public static void send(Packet packet) { 428 | + FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); 429 | + packet.toBytes(buf); 430 | + ClientboundCustomPayloadPacket fakeP = new ClientboundCustomPayloadPacket(packet.getIdentifier(), buf); 431 | + for (ReplayRecorder recorder : ReplayRecorder.active_recorders){ 432 | + recorder.onPacket(fakeP); 433 | + } 434 | + // ReplayInterface.INSTANCE.sendFakePacket(packet.getIdentifier(), buf); 435 | + } 436 | + 437 | +} 438 | -------------------------------------------------------------------------------- /patches/server/0022-ServerSideVoiceChat.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Bryan1029384756 <23323626+Bryan1029384756@users.noreply.github.com> 3 | Date: Sun, 25 Jun 2023 19:24:20 -0500 4 | Subject: [PATCH] ServerSideVoiceChat 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/recorder/ReplayRecorder.java b/src/main/java/net/minecraft/serversidereplayrecorder/recorder/ReplayRecorder.java 8 | index f0627468012f1725ff4493e559ad8636e122460e..b4450cb0ba56b113d21da107951f4d4c49975c6e 100644 9 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/recorder/ReplayRecorder.java 10 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/recorder/ReplayRecorder.java 11 | @@ -330,7 +330,7 @@ public abstract class ReplayRecorder { 12 | 13 | protected final AtomicReference>> packetQueue = new AtomicReference<>(new ConcurrentLinkedQueue<>()); 14 | 15 | - protected void save(Packet packet) { 16 | + public void save(Packet packet) { 17 | if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("ReplayRecorder.save: "); 18 | if (ServerSideReplayRecorderServer.config.use_server_timestamps()) { 19 | if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("ReplayRecorder.save: use_server_timestamps"); 20 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/voice/ServerSideVoiceChat.java b/src/main/java/net/minecraft/serversidereplayrecorder/voice/ServerSideVoiceChat.java 21 | index 093d1a39efe81c137674d6c650a31bf243ecdbf7..1cd99d4708062328e338b25958cd3fabd15b25fb 100644 22 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/voice/ServerSideVoiceChat.java 23 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/voice/ServerSideVoiceChat.java 24 | @@ -2,7 +2,6 @@ package net.minecraft.serversidereplayrecorder.voice; 25 | 26 | import de.maxhenkel.voicechat.api.VoicechatApi; 27 | import de.maxhenkel.voicechat.api.VoicechatPlugin; 28 | -import de.maxhenkel.voicechat.api.VoicechatServerApi; 29 | import de.maxhenkel.voicechat.api.events.*; 30 | import de.maxhenkel.voicechat.api.opus.OpusDecoder; 31 | import net.minecraft.server.level.ServerPlayer; 32 | @@ -18,7 +17,7 @@ import java.util.*; 33 | 34 | public class ServerSideVoiceChat implements VoicechatPlugin { 35 | 36 | - private OpusDecoder decoder; 37 | + public static OpusDecoder decoder; 38 | public static double distance; 39 | public static VoicechatApi SERVERAPI; 40 | @Override 41 | @@ -28,6 +27,9 @@ public class ServerSideVoiceChat implements VoicechatPlugin { 42 | 43 | @Override 44 | public void initialize(VoicechatApi api) { 45 | + if (decoder == null) { 46 | + decoder = api.createDecoder(); 47 | + } 48 | System.out.println("Started recording voice chat using PaperRecord"); 49 | this.distance = api.getVoiceChatDistance(); 50 | this.SERVERAPI = api; 51 | @@ -38,13 +40,10 @@ public class ServerSideVoiceChat implements VoicechatPlugin { 52 | registration.registerEvent(EntitySoundPacketEvent.class, VoicechatRecorder::onEntitySound); 53 | registration.registerEvent(LocationalSoundPacketEvent.class, VoicechatRecorder::onLocationalSound); 54 | registration.registerEvent(StaticSoundPacketEvent.class, VoicechatRecorder::onStaticSound); 55 | - //registration.registerEvent(ClientSoundEvent.class, VoicechatRecorder::onSound); 56 | - // registration.registerEvent(MicrophonePacketEvent.class, this::onSound); 57 | + registration.registerEvent(MicrophonePacketEvent.class, VoicechatRecorder::onSound); 58 | } 59 | 60 | 61 | - 62 | - 63 | public Map> playerPacketMap = new HashMap<>(); 64 | private Map lastPacketTimeMap = new HashMap<>(); 65 | private static final int FRAME_SIZE_MS = 20; // Frame size in milliseconds 66 | @@ -62,10 +61,6 @@ public class ServerSideVoiceChat implements VoicechatPlugin { 67 | public void onSound(MicrophonePacketEvent event) { 68 | UUID playerUuid = event.getSenderConnection().getPlayer().getUuid(); 69 | 70 | - if (decoder == null) { 71 | - decoder = event.getVoicechat().createDecoder(); 72 | - } 73 | - 74 | long now = System.currentTimeMillis(); 75 | long lastPacketTime = lastPacketTimeMap.get(playerUuid); 76 | if (lastPacketTime != -1) { 77 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/EntitySoundPacket.java b/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/EntitySoundPacket.java 78 | index f767678d31b5c8525eaf501878e112b4cb0c277b..57bccb828db34436c80d4ec05c71b33735cf5a46 100644 79 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/EntitySoundPacket.java 80 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/EntitySoundPacket.java 81 | @@ -9,7 +9,7 @@ import java.util.UUID; 82 | 83 | public class EntitySoundPacket extends AbstractSoundPacket { 84 | 85 | - public static ResourceLocation ID = new ResourceLocation("PaperRecord", "entity_sound"); 86 | + public static ResourceLocation ID = new ResourceLocation("replayvoicechat", "entity_sound"); 87 | 88 | private boolean whispering; 89 | private float distance; 90 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/LocationalSoundPacket.java b/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/LocationalSoundPacket.java 91 | index a035e09d1f5f1fa6e8e294bd52a25ad0e66683ca..6df16a76112407c65e7e6dad344a3c91d330bec4 100644 92 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/LocationalSoundPacket.java 93 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/LocationalSoundPacket.java 94 | @@ -9,7 +9,7 @@ import java.util.UUID; 95 | 96 | public class LocationalSoundPacket extends AbstractSoundPacket { 97 | 98 | - public static ResourceLocation ID = new ResourceLocation("PaperRecord", "locational_sound"); 99 | + public static ResourceLocation ID = new ResourceLocation("replayvoicechat", "locational_sound"); 100 | 101 | private Position location; 102 | private float distance; 103 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/StaticSoundPacket.java b/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/StaticSoundPacket.java 104 | index 15934e72e926d4dae343d6fc0b283c078487c741..6280fe05ce1b60277eecbf35911d7f100a474443 100644 105 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/StaticSoundPacket.java 106 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/StaticSoundPacket.java 107 | @@ -6,7 +6,7 @@ import java.util.UUID; 108 | 109 | public class StaticSoundPacket extends AbstractSoundPacket { 110 | 111 | - public static ResourceLocation ID = new ResourceLocation("PaperRecord", "static_sound"); 112 | + public static ResourceLocation ID = new ResourceLocation("replayvoicechat", "static_sound"); 113 | 114 | public StaticSoundPacket(UUID id, short[] rawAudio) { 115 | super(id, rawAudio); 116 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/voice/recording/VoicechatRecorder.java b/src/main/java/net/minecraft/serversidereplayrecorder/voice/recording/VoicechatRecorder.java 117 | index 9f6d7d9e00a8ff4c1a6f5f274ce4479199826496..ca56f29556cfd1d6da95b930c6332b02d159658e 100644 118 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/voice/recording/VoicechatRecorder.java 119 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/voice/recording/VoicechatRecorder.java 120 | @@ -10,6 +10,7 @@ import net.minecraft.network.protocol.game.ClientboundCustomPayloadPacket; 121 | import net.minecraft.server.MinecraftServer; 122 | import net.minecraft.serversidereplayrecorder.ServerSideReplayRecorderServer; 123 | import net.minecraft.serversidereplayrecorder.recorder.ReplayRecorder; 124 | +import net.minecraft.serversidereplayrecorder.voice.ServerSideVoiceChat; 125 | import net.minecraft.serversidereplayrecorder.voice.net.EntitySoundPacket; 126 | import net.minecraft.serversidereplayrecorder.voice.net.LocationalSoundPacket; 127 | import net.minecraft.serversidereplayrecorder.voice.net.Packet; 128 | @@ -19,49 +20,43 @@ import java.util.UUID; 129 | 130 | public class VoicechatRecorder { 131 | 132 | -// private static final Minecraft MC = Minecraft.getInstance(); 133 | - 134 | public static void onEntitySound(EntitySoundPacketEvent event) { 135 | - short[] rawAudio = getRawAudio(event, event.getPacket()); 136 | - send(new EntitySoundPacket(event.getPacket().getEntityUuid(), rawAudio, event.getPacket().isWhispering(), event.getPacket().getDistance())); 137 | + EntitySoundPacket ssp = (EntitySoundPacket)event.getPacket(); 138 | + send(new EntitySoundPacket(event.getPacket().getEntityUuid(), ssp.getRawAudio(), event.getPacket().isWhispering(), event.getPacket().getDistance())); 139 | } 140 | 141 | public static void onLocationalSound(LocationalSoundPacketEvent event) { 142 | - short[] rawAudio = getRawAudio(event, event.getPacket()); 143 | - send(new LocationalSoundPacket(event.getPacket().getSender(), rawAudio, event.getPacket().getPosition(), event.getPacket().getDistance())); 144 | + LocationalSoundPacket ssp = (LocationalSoundPacket)event.getPacket(); 145 | + send(new LocationalSoundPacket(event.getPacket().getSender(), ssp.getRawAudio(), event.getPacket().getPosition(), event.getPacket().getDistance())); 146 | } 147 | 148 | public static void onStaticSound(StaticSoundPacketEvent event) { 149 | - short[] rawAudio = getRawAudio(event, event.getPacket()); 150 | - send(new StaticSoundPacket(event.getPacket().getSender(), rawAudio)); 151 | + StaticSoundPacket ssp = (StaticSoundPacket)event.getPacket(); 152 | + send(new StaticSoundPacket(event.getPacket().getSender(), ssp.getRawAudio())); 153 | } 154 | 155 | - public static short[] getRawAudio(SoundPacketEvent event, SoundPacket packet){ 156 | - OpusDecoder decoder = event.getVoicechat().createDecoder(); 157 | + public static void onSound(MicrophonePacketEvent event) { 158 | + UUID id = event.getSenderConnection().getPlayer().getUuid(); 159 | 160 | - byte[] opusData = packet.getOpusEncodedData(); 161 | - return decoder.decode(opusData); 162 | - } 163 | + OpusDecoder decoder = ServerSideVoiceChat.decoder; 164 | + byte[] opusData = event.getPacket().getOpusEncodedData(); 165 | + 166 | + short[] rawAudio = decoder.decode(opusData); 167 | 168 | -// public static void onSound(ClientSoundEvent event) { 169 | -// UUID id = ClientManager.getPlayerStateManager().getOwnID(); 170 | -// short[] rawAudio = event.getRawAudio(); 171 | -// 172 | -// if (ReplayVoicechatPlugin.CLIENT_API.getGroup() != null) { 173 | -// send(new StaticSoundPacket(id, rawAudio)); 174 | -// } else { 175 | -// send(new EntitySoundPacket(id, rawAudio, event.isWhispering(), (float) ReplayVoicechatPlugin.CLIENT_API.getVoiceChatDistance())); 176 | -// } 177 | -// } 178 | + if (event.getSenderConnection().getGroup() != null) { 179 | + send(new StaticSoundPacket(id, rawAudio)); 180 | + } else { 181 | + send(new EntitySoundPacket(id, rawAudio, event.getPacket().isWhispering(), (float) ServerSideVoiceChat.distance)); 182 | + } 183 | + } 184 | 185 | public static void send(Packet packet) { 186 | FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); 187 | packet.toBytes(buf); 188 | ClientboundCustomPayloadPacket fakeP = new ClientboundCustomPayloadPacket(packet.getIdentifier(), buf); 189 | for (ReplayRecorder recorder : ReplayRecorder.active_recorders){ 190 | - recorder.onPacket(fakeP); 191 | + recorder.save(fakeP); 192 | } 193 | - // ReplayInterface.INSTANCE.sendFakePacket(packet.getIdentifier(), buf); 194 | } 195 | 196 | } 197 | -------------------------------------------------------------------------------- /patches/server/0023-Improved-Performance-For-Simple-Voice-Chat.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Bryan1029384756 <23323626+Bryan1029384756@users.noreply.github.com> 3 | Date: Mon, 26 Jun 2023 20:34:27 -0500 4 | Subject: [PATCH] Improved Performance For Simple Voice Chat 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java 8 | index c3586d6dc0168c0da3d8b229a47118bfc907d2a0..b5b42e16d514e3941aab646fa171c500b72bf20e 100644 9 | --- a/src/main/java/net/minecraft/server/MinecraftServer.java 10 | +++ b/src/main/java/net/minecraft/server/MinecraftServer.java 11 | @@ -922,11 +922,6 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop> playerPacketMap = new HashMap<>(); 69 | - private Map lastPacketTimeMap = new HashMap<>(); 70 | - private static final int FRAME_SIZE_MS = 20; // Frame size in milliseconds 71 | - private static final int FRAME_SIZE_SAMPLES = 960; // Number of samples in a frame, for 24000 Hz 72 | - private static final byte[] SILENT_FRAME; // A silent frame 73 | - 74 | - static { 75 | - // Initialize the silent frame. 76 | - short[] silentSamples = new short[FRAME_SIZE_SAMPLES]; 77 | - SILENT_FRAME = new byte[silentSamples.length * 2]; 78 | - ByteBuffer.wrap(SILENT_FRAME).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(silentSamples); 79 | - } 80 | - 81 | - 82 | - public void onSound(MicrophonePacketEvent event) { 83 | - UUID playerUuid = event.getSenderConnection().getPlayer().getUuid(); 84 | - 85 | - long now = System.currentTimeMillis(); 86 | - long lastPacketTime = lastPacketTimeMap.get(playerUuid); 87 | - if (lastPacketTime != -1) { 88 | - // If it's not the first packet, add silence to fill in the gap, if needed. 89 | - long gapMs = now - lastPacketTime; 90 | - if(gapMs > 500) { // More than 1 second gap 91 | - while (gapMs > FRAME_SIZE_MS) { 92 | - playerPacketMap.get(playerUuid).add(SILENT_FRAME); 93 | - gapMs -= FRAME_SIZE_MS; 94 | - } 95 | - } 96 | - } 97 | - lastPacketTimeMap.put(playerUuid, now); 98 | - 99 | - byte[] opusData = event.getPacket().getOpusEncodedData(); 100 | - try { 101 | - short[] pcmShorts = decoder.decode(opusData); 102 | - System.out.println(Arrays.toString(Arrays.copyOf(pcmShorts, 10))); // print first 10 samples 103 | - byte[] pcmBytes = new byte[pcmShorts.length * 2]; 104 | - ByteBuffer.wrap(pcmBytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(pcmShorts); 105 | - playerPacketMap.get(playerUuid).add(pcmBytes); 106 | - } catch (Exception e) { 107 | - e.printStackTrace(); 108 | - } 109 | - } 110 | - 111 | - public void startSound(ServerPlayer player){ 112 | - ServerSideReplayRecorderServer.LOGGER.info("Started Voice Recording Player %s".formatted(player.getGameProfile().getName())); 113 | - UUID playerUuid = player.getUUID(); 114 | - 115 | - playerPacketMap.put(playerUuid, new ArrayList<>(Collections.singletonList(SILENT_FRAME))); 116 | - 117 | - // Initialize this player's last packet time as current time 118 | - lastPacketTimeMap.put(playerUuid, System.currentTimeMillis()); 119 | - } 120 | - 121 | - public void saveToWav(UUID playerUuid, String filePath) { 122 | - String playerName = Bukkit.getOfflinePlayer(playerUuid).getName(); 123 | - ServerSideReplayRecorderServer.LOGGER.info("Stopped Voice Recording Player %s".formatted(playerName)); 124 | - String fileName = String.format("%s.wav", new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss").format(new Date())); 125 | - 126 | - AudioFormat audioFormat = new AudioFormat(24000, 16, 2, true, false); 127 | - File outputFile = new File(filePath + playerName + File.separator + fileName); // add the player's UUID to the filename 128 | - outputFile.getParentFile().mkdirs(); 129 | - 130 | - byte[] combinedData = combinePackets(playerUuid); 131 | - 132 | - long numSampleFrames = combinedData.length / 4; // 16 bits = 2 bytes per sample, 2 channels = 4 bytes per frame 133 | - 134 | - try { 135 | - AudioInputStream audioInputStream = new AudioInputStream(new ByteArrayInputStream(combinedData), audioFormat, numSampleFrames); 136 | - AudioSystem.write(audioInputStream, AudioFileFormat.Type.WAVE, outputFile); 137 | - } catch (IOException e) { 138 | - e.printStackTrace(); 139 | - } 140 | - } 141 | - 142 | - public byte[] combinePackets(UUID playerUuid) { 143 | - long now = System.currentTimeMillis(); 144 | - long lastPacketTime = lastPacketTimeMap.get(playerUuid); 145 | - if (lastPacketTime != -1) { 146 | - // If it's not the first packet, add silence to fill in the gap, if needed. 147 | - long gapMs = now - lastPacketTime; 148 | - if(gapMs > 500) { // More than 1 second gap 149 | - while (gapMs > FRAME_SIZE_MS) { 150 | - playerPacketMap.get(playerUuid).add(SILENT_FRAME); 151 | - gapMs -= FRAME_SIZE_MS; 152 | - } 153 | - } 154 | - } 155 | - 156 | - List packetList = playerPacketMap.get(playerUuid); 157 | - 158 | - int totalLength = packetList.stream().mapToInt(packet -> packet.length).sum(); 159 | - byte[] combinedData = new byte[totalLength]; 160 | - int offset = 0; 161 | - 162 | - for (byte[] packet : packetList) { 163 | - System.arraycopy(packet, 0, combinedData, offset, packet.length); 164 | - offset += packet.length; 165 | - } 166 | - 167 | - return combinedData; 168 | - } 169 | } 170 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/voice/recording/VoicechatRecorder.java b/src/main/java/net/minecraft/serversidereplayrecorder/voice/recording/VoicechatRecorder.java 171 | index ca56f29556cfd1d6da95b930c6332b02d159658e..16d4d137726c97a170f951c879c1e0387019318a 100644 172 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/voice/recording/VoicechatRecorder.java 173 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/voice/recording/VoicechatRecorder.java 174 | @@ -1,62 +1,96 @@ 175 | package net.minecraft.serversidereplayrecorder.voice.recording; 176 | 177 | 178 | +import de.maxhenkel.voicechat.api.Position; 179 | +import de.maxhenkel.voicechat.api.ServerLevel; 180 | +import de.maxhenkel.voicechat.api.ServerPlayer; 181 | import de.maxhenkel.voicechat.api.events.*; 182 | import de.maxhenkel.voicechat.api.opus.OpusDecoder; 183 | import de.maxhenkel.voicechat.api.packets.SoundPacket; 184 | import io.netty.buffer.Unpooled; 185 | +import net.minecraft.network.Connection; 186 | import net.minecraft.network.FriendlyByteBuf; 187 | import net.minecraft.network.protocol.game.ClientboundCustomPayloadPacket; 188 | import net.minecraft.server.MinecraftServer; 189 | import net.minecraft.serversidereplayrecorder.ServerSideReplayRecorderServer; 190 | +import net.minecraft.serversidereplayrecorder.recorder.PlayerRecorder; 191 | +import net.minecraft.serversidereplayrecorder.recorder.RegionRecorder; 192 | import net.minecraft.serversidereplayrecorder.recorder.ReplayRecorder; 193 | import net.minecraft.serversidereplayrecorder.voice.ServerSideVoiceChat; 194 | import net.minecraft.serversidereplayrecorder.voice.net.EntitySoundPacket; 195 | import net.minecraft.serversidereplayrecorder.voice.net.LocationalSoundPacket; 196 | import net.minecraft.serversidereplayrecorder.voice.net.Packet; 197 | import net.minecraft.serversidereplayrecorder.voice.net.StaticSoundPacket; 198 | +import net.minecraft.world.phys.Vec3; 199 | 200 | +import java.util.Collection; 201 | import java.util.UUID; 202 | 203 | public class VoicechatRecorder { 204 | 205 | - public static void onEntitySound(EntitySoundPacketEvent event) { 206 | - EntitySoundPacket ssp = (EntitySoundPacket)event.getPacket(); 207 | - send(new EntitySoundPacket(event.getPacket().getEntityUuid(), ssp.getRawAudio(), event.getPacket().isWhispering(), event.getPacket().getDistance())); 208 | - } 209 | + public static void onSound(MicrophonePacketEvent event) { 210 | + ServerPlayer player = event.getSenderConnection().getPlayer(); 211 | + ServerLevel level = player.getServerLevel(); 212 | + Position position = player.getPosition(); 213 | + UUID id = player.getUuid(); 214 | + Packet packet = createPacket(event, id); 215 | 216 | - public static void onLocationalSound(LocationalSoundPacketEvent event) { 217 | - LocationalSoundPacket ssp = (LocationalSoundPacket)event.getPacket(); 218 | - send(new LocationalSoundPacket(event.getPacket().getSender(), ssp.getRawAudio(), event.getPacket().getPosition(), event.getPacket().getDistance())); 219 | - } 220 | + Collection playersInRange = event.getVoicechat().getPlayersInRange( 221 | + level, 222 | + position, 223 | + ServerSideReplayRecorderServer.server.getPlayerList().getViewDistance() * 16 224 | + ); 225 | 226 | - public static void onStaticSound(StaticSoundPacketEvent event) { 227 | - StaticSoundPacket ssp = (StaticSoundPacket)event.getPacket(); 228 | - send(new StaticSoundPacket(event.getPacket().getSender(), ssp.getRawAudio())); 229 | + sendNearbyPlayerPacket(playersInRange, packet); 230 | + //sendRegionPacket(position, packet); 231 | } 232 | 233 | - public static void onSound(MicrophonePacketEvent event) { 234 | - UUID id = event.getSenderConnection().getPlayer().getUuid(); 235 | - 236 | + private static Packet createPacket(MicrophonePacketEvent event, UUID id) { 237 | OpusDecoder decoder = ServerSideVoiceChat.decoder; 238 | byte[] opusData = event.getPacket().getOpusEncodedData(); 239 | - 240 | short[] rawAudio = decoder.decode(opusData); 241 | 242 | if (event.getSenderConnection().getGroup() != null) { 243 | - send(new StaticSoundPacket(id, rawAudio)); 244 | + return new StaticSoundPacket(id, rawAudio); 245 | } else { 246 | - send(new EntitySoundPacket(id, rawAudio, event.getPacket().isWhispering(), (float) ServerSideVoiceChat.distance)); 247 | + return new EntitySoundPacket(id, rawAudio, event.getPacket().isWhispering(), (float) ServerSideVoiceChat.distance); 248 | } 249 | } 250 | 251 | - public static void send(Packet packet) { 252 | + private static void sendNearbyPlayerPacket(Collection playersInRange, Packet packet) { 253 | + playersInRange.forEach(player -> { 254 | + Connection connection = MinecraftServer.getServer().getPlayerList().getPlayer(player.getUuid()).connection.connection; 255 | + PlayerRecorder recorder = getPlayerRecorder(connection); 256 | + if (recorder != null) { 257 | + sendPlayerPacket(recorder, packet); 258 | + } 259 | + }); 260 | + } 261 | + 262 | + public static PlayerRecorder getPlayerRecorder(Connection connection){ 263 | + return PlayerRecorder.playerRecorderMap.get(connection); 264 | + } 265 | + 266 | + public static void sendPlayerPacket(PlayerRecorder recorder, Packet packet) { 267 | + ClientboundCustomPayloadPacket fakePacket = createCustomPacket(packet); 268 | + recorder.onPacket(fakePacket); 269 | + } 270 | + 271 | + public static void sendRegionPacket(Position pos, Packet packet) { 272 | + Vec3 playerPos = new Vec3(pos.getX(), pos.getY(), pos.getZ()); 273 | + ClientboundCustomPayloadPacket fakePacket = createCustomPacket(packet); 274 | + 275 | + for(RegionRecorder recorder : RegionRecorder.regionRecorderMap.values()){ 276 | + if(recorder.region.isInBox(playerPos)){ 277 | + recorder.onPacket(fakePacket); 278 | + } 279 | + } 280 | + } 281 | + 282 | + private static ClientboundCustomPayloadPacket createCustomPacket(Packet packet) { 283 | FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); 284 | packet.toBytes(buf); 285 | - ClientboundCustomPayloadPacket fakeP = new ClientboundCustomPayloadPacket(packet.getIdentifier(), buf); 286 | - for (ReplayRecorder recorder : ReplayRecorder.active_recorders){ 287 | - recorder.save(fakeP); 288 | - } 289 | + return new ClientboundCustomPayloadPacket(packet.getIdentifier(), buf); 290 | } 291 | 292 | } 293 | -------------------------------------------------------------------------------- /patches/server/0024-Improved-Performance-For-Simple-Voice-Chat.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Bryan1029384756 <23323626+Bryan1029384756@users.noreply.github.com> 3 | Date: Mon, 26 Jun 2023 20:35:55 -0500 4 | Subject: [PATCH] Improved Performance For Simple Voice Chat 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java 8 | index e5e474a68e7b5c8f18724f3455a24ae3a8049440..ddc0f9e5ddcd91cfe4f54c62ebb7a9b4d2bc01ab 100644 9 | --- a/src/main/java/net/minecraft/server/players/PlayerList.java 10 | +++ b/src/main/java/net/minecraft/server/players/PlayerList.java 11 | @@ -182,7 +182,6 @@ public abstract class PlayerList { 12 | 13 | this.getPlayers().stream().filter(p -> this.isOp(p.getGameProfile())).forEach( p -> p.displayClientMessage(Component.literal("Started Recording Player %s".formatted(player.getGameProfile().getName())), false)); 14 | 15 | - voiceChat.startSound(player); 16 | PlayerRecorder recorder = new PlayerRecorder(connection); 17 | PlayerRecorder.playerRecorderMap.put(connection, recorder); 18 | recorder.onPacket(new ClientboundGameProfilePacket(player.getGameProfile())); 19 | -------------------------------------------------------------------------------- /patches/server/0025-Support-Region-Voice-Recording.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Bryan1029384756 <23323626+Bryan1029384756@users.noreply.github.com> 3 | Date: Fri, 30 Jun 2023 20:41:08 -0500 4 | Subject: [PATCH] Support Region Voice Recording 5 | 6 | 7 | diff --git a/build.gradle.kts b/build.gradle.kts 8 | index f3b7534eef9fb551146b380e2ba62b1d8ea53aac..27b86c89e8ee3a3b503eef0f71fd9c39132d3f89 100644 9 | --- a/build.gradle.kts 10 | +++ b/build.gradle.kts 11 | @@ -37,7 +37,8 @@ dependencies { 12 | implementation("net.fabricmc:mapping-io:0.3.0") // Paper - needed to read mappings for stacktrace deobfuscation 13 | implementation("com.fasterxml.jackson.core:jackson-annotations:2.15.2") //ServersideRecording 14 | implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.15.2") //ServersideRecording 15 | - implementation("de.maxhenkel.voicechat:voicechat-api:2.4.11") //ServersideRecording 16 | + implementation ("de.maxhenkel.voicechat:voicechat-api:2.4.0") //ServersideRecording 17 | + implementation ("maven.modrinth:simple-voice-chat:fabric-1.20.1-2.4.11") //ServersideRecording 18 | runtimeOnly("org.xerial:sqlite-jdbc:3.42.0.0") 19 | runtimeOnly("com.mysql:mysql-connector-j:8.0.33") 20 | runtimeOnly("com.lmax:disruptor:3.4.4") // Paper 21 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/config/MainConfig.java b/src/main/java/net/minecraft/serversidereplayrecorder/config/MainConfig.java 22 | index 8e2d0ec530e408e572d1f0af38f6206e1fa94af7..788bd8f92f91a330b70f497c8f2dc93dc1864140 100644 23 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/config/MainConfig.java 24 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/config/MainConfig.java 25 | @@ -22,6 +22,8 @@ public class MainConfig { 26 | private boolean assume_unloaded_chunks_dont_change = true; 27 | private boolean render_distance_fog_fix = false; 28 | private long max_file_size = 10000000000L; 29 | + private int voice_recording_range = 48; 30 | + private boolean voice_recording_enabled = false; 31 | private URL file_storage_url; 32 | private boolean debug = false; 33 | 34 | @@ -48,6 +50,22 @@ public class MainConfig { 35 | this.debug = debug; 36 | } 37 | 38 | + public int getVoice_recording_range() { 39 | + return voice_recording_range; 40 | + } 41 | + 42 | + public void setVoice_recording_range(int voice_recording_range) { 43 | + this.voice_recording_range = voice_recording_range; 44 | + } 45 | + 46 | + public boolean isVoice_recording_enabled() { 47 | + return voice_recording_enabled; 48 | + } 49 | + 50 | + public void setVoice_recording_enabled(boolean voice_recording_enabled) { 51 | + this.voice_recording_enabled = voice_recording_enabled; 52 | + } 53 | + 54 | public long getMax_file_size() { 55 | 56 | return max_file_size; 57 | @@ -142,3 +160,4 @@ public class MainConfig { 58 | this.render_distance_fog_fix = render_distance_fog_fix; 59 | } 60 | } 61 | + 62 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/recorder/RegionRecorder.java b/src/main/java/net/minecraft/serversidereplayrecorder/recorder/RegionRecorder.java 63 | index ffdbd36015553ca8d15d55803c945f8949f234f0..7312a60b1af9c66efa60a42e81256ee700c7623f 100644 64 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/recorder/RegionRecorder.java 65 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/recorder/RegionRecorder.java 66 | @@ -1,6 +1,7 @@ 67 | package net.minecraft.serversidereplayrecorder.recorder; 68 | 69 | import com.mojang.authlib.GameProfile; 70 | +import de.maxhenkel.voicechat.Voicechat; 71 | import io.netty.buffer.Unpooled; 72 | import net.minecraft.core.BlockPos; 73 | import net.minecraft.core.NonNullList; 74 | @@ -11,12 +12,15 @@ import net.minecraft.network.protocol.Packet; 75 | import net.minecraft.network.protocol.game.*; 76 | import net.minecraft.network.protocol.login.ClientboundGameProfilePacket; 77 | import net.minecraft.server.level.ServerLevel; 78 | +import net.minecraft.server.level.ServerPlayer; 79 | import net.minecraft.serversidereplayrecorder.ServerSideReplayRecorderServer; 80 | import net.minecraft.serversidereplayrecorder.util.ChunkBox; 81 | import net.minecraft.serversidereplayrecorder.util.WrappedPacket; 82 | import net.minecraft.serversidereplayrecorder.util.interfaces.LightUpdatePacketAccessor; 83 | import net.minecraft.serversidereplayrecorder.util.interfaces.RegionRecorderStorage; 84 | import net.minecraft.serversidereplayrecorder.util.interfaces.RegionRecorderWorld; 85 | +import net.minecraft.serversidereplayrecorder.voice.Utils; 86 | +import net.minecraft.serversidereplayrecorder.voice.net.SecretPacket; 87 | import net.minecraft.tags.TagNetworkSerialization; 88 | import net.minecraft.world.entity.player.Abilities; 89 | import net.minecraft.world.flag.FeatureFlags; 90 | @@ -214,6 +218,10 @@ public class RegionRecorder extends ReplayRecorder { 91 | //set the replay viewpoint to the center of the watched region 92 | onPacket(new ClientboundPlayerPositionPacket(viewpoint.getX() + 0.5d,viewpoint.getY(),viewpoint.getZ() + 0.5d,0f,0f, Collections.emptySet(),0)); 93 | //ready to record changes 94 | + if(ServerSideReplayRecorderServer.config.isVoice_recording_enabled()){ 95 | + ServerPlayer player = new ServerPlayer(ms, ms.overworld(), FAKE_GAMEPROFILE); 96 | + onPacket(Utils.createCustomPacket(new SecretPacket(player, UUID.randomUUID() , Voicechat.SERVER.getServer().getPort(), Voicechat.SERVER_CONFIG))); 97 | + } 98 | } 99 | 100 | @Override 101 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/voice/ServerSideVoiceChat.java b/src/main/java/net/minecraft/serversidereplayrecorder/voice/ServerSideVoiceChat.java 102 | index 3e84ce236b33963bd1bd6ac26f73885d9a9a9864..2afbfcb15a30988f3acb92af798819fa231b3022 100644 103 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/voice/ServerSideVoiceChat.java 104 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/voice/ServerSideVoiceChat.java 105 | @@ -4,6 +4,7 @@ import de.maxhenkel.voicechat.api.VoicechatApi; 106 | import de.maxhenkel.voicechat.api.VoicechatPlugin; 107 | import de.maxhenkel.voicechat.api.events.*; 108 | import de.maxhenkel.voicechat.api.opus.OpusDecoder; 109 | +import net.minecraft.serversidereplayrecorder.ServerSideReplayRecorderServer; 110 | import net.minecraft.serversidereplayrecorder.voice.recording.VoicechatRecorder; 111 | public class ServerSideVoiceChat implements VoicechatPlugin { 112 | 113 | @@ -17,6 +18,7 @@ public class ServerSideVoiceChat implements VoicechatPlugin { 114 | 115 | @Override 116 | public void initialize(VoicechatApi api) { 117 | + if(!ServerSideReplayRecorderServer.config.isVoice_recording_enabled()) return; 118 | if (decoder == null) { 119 | decoder = api.createDecoder(); 120 | } 121 | @@ -27,6 +29,7 @@ public class ServerSideVoiceChat implements VoicechatPlugin { 122 | 123 | @Override 124 | public void registerEvents(EventRegistration registration) { 125 | + if(!ServerSideReplayRecorderServer.config.isVoice_recording_enabled()) return; 126 | registration.registerEvent(MicrophonePacketEvent.class, VoicechatRecorder::onSound); 127 | } 128 | 129 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/voice/Utils.java b/src/main/java/net/minecraft/serversidereplayrecorder/voice/Utils.java 130 | index 36132fcf9b14c52b9e81929172fea8277b28fbc8..99213f8a949ff5f145185c84e87766172b4cacd5 100644 131 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/voice/Utils.java 132 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/voice/Utils.java 133 | @@ -1,5 +1,10 @@ 134 | package net.minecraft.serversidereplayrecorder.voice; 135 | 136 | +import io.netty.buffer.Unpooled; 137 | +import net.minecraft.network.FriendlyByteBuf; 138 | +import net.minecraft.network.protocol.game.ClientboundCustomPayloadPacket; 139 | +import net.minecraft.serversidereplayrecorder.voice.net.Packet; 140 | + 141 | public class Utils { 142 | 143 | public static short[] bytesToShorts(byte[] bytes) { 144 | @@ -31,4 +36,10 @@ public class Utils { 145 | return new byte[]{(byte) (s & 0xFF), (byte) ((s >> 8) & 0xFF)}; 146 | } 147 | 148 | + public static ClientboundCustomPayloadPacket createCustomPacket(Packet packet) { 149 | + FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); 150 | + packet.toBytes(buf); 151 | + return new ClientboundCustomPayloadPacket(packet.getIdentifier(), buf); 152 | + } 153 | + 154 | } 155 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/SecretPacket.java b/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/SecretPacket.java 156 | new file mode 100644 157 | index 0000000000000000000000000000000000000000..c24e8021e76582210caa9a64ce4d5c8cb92b4f92 158 | --- /dev/null 159 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/SecretPacket.java 160 | @@ -0,0 +1,109 @@ 161 | +package net.minecraft.serversidereplayrecorder.voice.net; 162 | + 163 | +import net.minecraft.network.FriendlyByteBuf; 164 | +import net.minecraft.resources.ResourceLocation; 165 | +import net.minecraft.server.level.ServerPlayer; 166 | +import de.maxhenkel.voicechat.config.ServerConfig; 167 | +import de.maxhenkel.voicechat.plugins.PluginManager; 168 | +import java.util.UUID; 169 | + 170 | +public class SecretPacket implements Packet { 171 | + public static final ResourceLocation SECRET = new ResourceLocation("voicechat", "secret"); 172 | + private UUID secret; 173 | + private int serverPort; 174 | + private UUID playerUUID; 175 | + private ServerConfig.Codec codec; 176 | + private int mtuSize; 177 | + private double voiceChatDistance; 178 | + private int keepAlive; 179 | + private boolean groupsEnabled; 180 | + private String voiceHost; 181 | + private boolean allowRecording; 182 | + 183 | + public SecretPacket() { 184 | + } 185 | + 186 | + public SecretPacket(ServerPlayer player, UUID secret, int port, ServerConfig serverConfig) { 187 | + this.secret = secret; 188 | + this.serverPort = port; 189 | + this.playerUUID = player.getUUID(); 190 | + this.codec = (ServerConfig.Codec)serverConfig.voiceChatCodec.get(); 191 | + this.mtuSize = (Integer)serverConfig.voiceChatMtuSize.get(); 192 | + this.voiceChatDistance = (Double)serverConfig.voiceChatDistance.get(); 193 | + this.keepAlive = (Integer)serverConfig.keepAlive.get(); 194 | + this.groupsEnabled = (Boolean)serverConfig.groupsEnabled.get(); 195 | + this.voiceHost = PluginManager.instance().getVoiceHost((String)serverConfig.voiceHost.get()); 196 | + this.allowRecording = (Boolean)serverConfig.allowRecording.get(); 197 | + } 198 | + 199 | + public UUID getSecret() { 200 | + return this.secret; 201 | + } 202 | + 203 | + public int getServerPort() { 204 | + return this.serverPort; 205 | + } 206 | + 207 | + public UUID getPlayerUUID() { 208 | + return this.playerUUID; 209 | + } 210 | + 211 | + public ServerConfig.Codec getCodec() { 212 | + return this.codec; 213 | + } 214 | + 215 | + public int getMtuSize() { 216 | + return this.mtuSize; 217 | + } 218 | + 219 | + public double getVoiceChatDistance() { 220 | + return this.voiceChatDistance; 221 | + } 222 | + 223 | + public int getKeepAlive() { 224 | + return this.keepAlive; 225 | + } 226 | + 227 | + public boolean groupsEnabled() { 228 | + return this.groupsEnabled; 229 | + } 230 | + 231 | + public String getVoiceHost() { 232 | + return this.voiceHost; 233 | + } 234 | + 235 | + public ResourceLocation getIdentifier() { 236 | + return SECRET; 237 | + } 238 | + 239 | + public boolean allowRecording() { 240 | + return this.allowRecording; 241 | + } 242 | + 243 | + public SecretPacket fromBytes(FriendlyByteBuf buf) { 244 | + this.secret = buf.readUUID(); 245 | + this.serverPort = buf.readInt(); 246 | + this.playerUUID = buf.readUUID(); 247 | + this.codec = ServerConfig.Codec.values()[buf.readByte()]; 248 | + this.mtuSize = buf.readInt(); 249 | + this.voiceChatDistance = buf.readDouble(); 250 | + this.keepAlive = buf.readInt(); 251 | + this.groupsEnabled = buf.readBoolean(); 252 | + this.voiceHost = buf.readUtf(32767); 253 | + this.allowRecording = buf.readBoolean(); 254 | + return this; 255 | + } 256 | + 257 | + public void toBytes(FriendlyByteBuf buf) { 258 | + buf.writeUUID(this.secret); 259 | + buf.writeInt(this.serverPort); 260 | + buf.writeUUID(this.playerUUID); 261 | + buf.writeByte(this.codec.ordinal()); 262 | + buf.writeInt(this.mtuSize); 263 | + buf.writeDouble(this.voiceChatDistance); 264 | + buf.writeInt(this.keepAlive); 265 | + buf.writeBoolean(this.groupsEnabled); 266 | + buf.writeUtf(this.voiceHost); 267 | + buf.writeBoolean(this.allowRecording); 268 | + } 269 | +} 270 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/voice/recording/VoicechatRecorder.java b/src/main/java/net/minecraft/serversidereplayrecorder/voice/recording/VoicechatRecorder.java 271 | index 16d4d137726c97a170f951c879c1e0387019318a..7d29883f7c63747caaa6ce5eb92ccdac3f93f23a 100644 272 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/voice/recording/VoicechatRecorder.java 273 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/voice/recording/VoicechatRecorder.java 274 | @@ -17,6 +17,7 @@ import net.minecraft.serversidereplayrecorder.recorder.PlayerRecorder; 275 | import net.minecraft.serversidereplayrecorder.recorder.RegionRecorder; 276 | import net.minecraft.serversidereplayrecorder.recorder.ReplayRecorder; 277 | import net.minecraft.serversidereplayrecorder.voice.ServerSideVoiceChat; 278 | +import net.minecraft.serversidereplayrecorder.voice.Utils; 279 | import net.minecraft.serversidereplayrecorder.voice.net.EntitySoundPacket; 280 | import net.minecraft.serversidereplayrecorder.voice.net.LocationalSoundPacket; 281 | import net.minecraft.serversidereplayrecorder.voice.net.Packet; 282 | @@ -38,11 +39,11 @@ public class VoicechatRecorder { 283 | Collection playersInRange = event.getVoicechat().getPlayersInRange( 284 | level, 285 | position, 286 | - ServerSideReplayRecorderServer.server.getPlayerList().getViewDistance() * 16 287 | + ServerSideReplayRecorderServer.config.getVoice_recording_range() 288 | ); 289 | 290 | sendNearbyPlayerPacket(playersInRange, packet); 291 | - //sendRegionPacket(position, packet); 292 | + sendRegionPacket(position, packet); 293 | } 294 | 295 | private static Packet createPacket(MicrophonePacketEvent event, UUID id) { 296 | @@ -72,13 +73,13 @@ public class VoicechatRecorder { 297 | } 298 | 299 | public static void sendPlayerPacket(PlayerRecorder recorder, Packet packet) { 300 | - ClientboundCustomPayloadPacket fakePacket = createCustomPacket(packet); 301 | + ClientboundCustomPayloadPacket fakePacket = Utils.createCustomPacket(packet); 302 | recorder.onPacket(fakePacket); 303 | } 304 | 305 | public static void sendRegionPacket(Position pos, Packet packet) { 306 | Vec3 playerPos = new Vec3(pos.getX(), pos.getY(), pos.getZ()); 307 | - ClientboundCustomPayloadPacket fakePacket = createCustomPacket(packet); 308 | + ClientboundCustomPayloadPacket fakePacket = Utils.createCustomPacket(packet); 309 | 310 | for(RegionRecorder recorder : RegionRecorder.regionRecorderMap.values()){ 311 | if(recorder.region.isInBox(playerPos)){ 312 | @@ -87,10 +88,6 @@ public class VoicechatRecorder { 313 | } 314 | } 315 | 316 | - private static ClientboundCustomPayloadPacket createCustomPacket(Packet packet) { 317 | - FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); 318 | - packet.toBytes(buf); 319 | - return new ClientboundCustomPayloadPacket(packet.getIdentifier(), buf); 320 | - } 321 | + 322 | 323 | } 324 | -------------------------------------------------------------------------------- /patches/server/0026-Support-Region-Voice-Recording.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Bryan1029384756 <23323626+Bryan1029384756@users.noreply.github.com> 3 | Date: Fri, 30 Jun 2023 20:59:49 -0500 4 | Subject: [PATCH] Support Region Voice Recording 5 | 6 | 7 | diff --git a/build.gradle.kts b/build.gradle.kts 8 | index 27b86c89e8ee3a3b503eef0f71fd9c39132d3f89..eb8e2148a7fef15ef5870ce5ec31393810043128 100644 9 | --- a/build.gradle.kts 10 | +++ b/build.gradle.kts 11 | @@ -38,7 +38,7 @@ dependencies { 12 | implementation("com.fasterxml.jackson.core:jackson-annotations:2.15.2") //ServersideRecording 13 | implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.15.2") //ServersideRecording 14 | implementation ("de.maxhenkel.voicechat:voicechat-api:2.4.0") //ServersideRecording 15 | - implementation ("maven.modrinth:simple-voice-chat:fabric-1.20.1-2.4.11") //ServersideRecording 16 | + implementation ("maven.modrinth:simple-voice-chat:bukkit-2.4.11") //ServersideRecording 17 | runtimeOnly("org.xerial:sqlite-jdbc:3.42.0.0") 18 | runtimeOnly("com.mysql:mysql-connector-j:8.0.33") 19 | runtimeOnly("com.lmax:disruptor:3.4.4") // Paper 20 | diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java 21 | index b5b42e16d514e3941aab646fa171c500b72bf20e..ddd53d0fd3da2b2ba1b9013b459bc398f0354870 100644 22 | --- a/src/main/java/net/minecraft/server/MinecraftServer.java 23 | +++ b/src/main/java/net/minecraft/server/MinecraftServer.java 24 | @@ -304,7 +304,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop S spin(Function serverFactory) { 32 | AtomicReference atomicreference = new AtomicReference(); 33 | @@ -632,7 +632,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 3 | Date: Fri, 30 Jun 2023 21:02:21 -0500 4 | Subject: [PATCH] Support Region Voice Recording 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java 8 | index ddc0f9e5ddcd91cfe4f54c62ebb7a9b4d2bc01ab..e1ba10c920d8deb0c68c2cd87a1e9a8c772ab4a0 100644 9 | --- a/src/main/java/net/minecraft/server/players/PlayerList.java 10 | +++ b/src/main/java/net/minecraft/server/players/PlayerList.java 11 | @@ -148,13 +148,11 @@ public abstract class PlayerList { 12 | private CraftServer cserver; 13 | private final Map playersByName = new java.util.HashMap<>(); 14 | public @Nullable String collideRuleTeamName; // Paper - Team name used for collideRule 15 | - public ServerSideVoiceChat voiceChat; 16 | 17 | public PlayerList(MinecraftServer server, LayeredRegistryAccess registryManager, PlayerDataStorage saveHandler, int maxPlayers) { 18 | this.cserver = server.server = new CraftServer((DedicatedServer) server, this); 19 | server.console = new com.destroystokyo.paper.console.TerminalConsoleCommandSender(); // Paper 20 | // CraftBukkit end 21 | - this.voiceChat = server.voiceChat; 22 | this.bans = new UserBanList(PlayerList.USERBANLIST_FILE); 23 | this.ipBans = new IpBanList(PlayerList.IPBANLIST_FILE); 24 | this.ops = new ServerOpList(PlayerList.OPLIST_FILE); 25 | -------------------------------------------------------------------------------- /patches/server/0028-Support-Region-Voice-Recording.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Bryan1029384756 <23323626+Bryan1029384756@users.noreply.github.com> 3 | Date: Fri, 30 Jun 2023 21:13:48 -0500 4 | Subject: [PATCH] Support Region Voice Recording 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/recorder/RegionRecorder.java b/src/main/java/net/minecraft/serversidereplayrecorder/recorder/RegionRecorder.java 8 | index 7312a60b1af9c66efa60a42e81256ee700c7623f..588d1ee83912b401ee7e1ec1fb867b3bce6b11a2 100644 9 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/recorder/RegionRecorder.java 10 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/recorder/RegionRecorder.java 11 | @@ -1,7 +1,6 @@ 12 | package net.minecraft.serversidereplayrecorder.recorder; 13 | 14 | import com.mojang.authlib.GameProfile; 15 | -import de.maxhenkel.voicechat.Voicechat; 16 | import io.netty.buffer.Unpooled; 17 | import net.minecraft.core.BlockPos; 18 | import net.minecraft.core.NonNullList; 19 | @@ -35,6 +34,10 @@ import net.minecraft.world.level.chunk.ImposterProtoChunk; 20 | import net.minecraft.world.level.chunk.LevelChunk; 21 | import net.minecraft.world.level.levelgen.Heightmap; 22 | import net.minecraft.world.level.storage.LevelData; 23 | +import org.bukkit.Bukkit; 24 | +import org.bukkit.plugin.Plugin; 25 | +import org.bukkit.plugin.java.JavaPlugin; 26 | + 27 | import java.io.File; 28 | import java.io.IOException; 29 | import java.nio.file.Paths; 30 | @@ -219,8 +222,12 @@ public class RegionRecorder extends ReplayRecorder { 31 | onPacket(new ClientboundPlayerPositionPacket(viewpoint.getX() + 0.5d,viewpoint.getY(),viewpoint.getZ() + 0.5d,0f,0f, Collections.emptySet(),0)); 32 | //ready to record changes 33 | if(ServerSideReplayRecorderServer.config.isVoice_recording_enabled()){ 34 | - ServerPlayer player = new ServerPlayer(ms, ms.overworld(), FAKE_GAMEPROFILE); 35 | - onPacket(Utils.createCustomPacket(new SecretPacket(player, UUID.randomUUID() , Voicechat.SERVER.getServer().getPort(), Voicechat.SERVER_CONFIG))); 36 | + if (Bukkit.getServer().getPluginManager().isPluginEnabled("voicechat")) { 37 | + de.maxhenkel.voicechat.Voicechat vc = (de.maxhenkel.voicechat.Voicechat) Bukkit.getServer().getPluginManager().getPlugin("voicechat"); 38 | + ServerPlayer player = new ServerPlayer(ms, ms.overworld(), FAKE_GAMEPROFILE); 39 | + onPacket(Utils.createCustomPacket(new SecretPacket(player, UUID.randomUUID() , vc.SERVER.getServer().getPort(), vc.SERVER_CONFIG))); 40 | + } 41 | + 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /patches/server/0029-Support-Region-Voice-Recording.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Bryan1029384756 <23323626+Bryan1029384756@users.noreply.github.com> 3 | Date: Fri, 30 Jun 2023 21:26:04 -0500 4 | Subject: [PATCH] Support Region Voice Recording 5 | 6 | 7 | diff --git a/build.gradle.kts b/build.gradle.kts 8 | index eb8e2148a7fef15ef5870ce5ec31393810043128..61f0b30f2bcf2c6a32054e16d10179fcd0a52950 100644 9 | --- a/build.gradle.kts 10 | +++ b/build.gradle.kts 11 | @@ -38,7 +38,7 @@ dependencies { 12 | implementation("com.fasterxml.jackson.core:jackson-annotations:2.15.2") //ServersideRecording 13 | implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.15.2") //ServersideRecording 14 | implementation ("de.maxhenkel.voicechat:voicechat-api:2.4.0") //ServersideRecording 15 | - implementation ("maven.modrinth:simple-voice-chat:bukkit-2.4.11") //ServersideRecording 16 | + compileOnly ("maven.modrinth:simple-voice-chat:bukkit-2.4.11") //ServersideRecording 17 | runtimeOnly("org.xerial:sqlite-jdbc:3.42.0.0") 18 | runtimeOnly("com.mysql:mysql-connector-j:8.0.33") 19 | runtimeOnly("com.lmax:disruptor:3.4.4") // Paper 20 | -------------------------------------------------------------------------------- /patches/server/0030-Support-Region-Voice-Recording.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Bryan1029384756 <23323626+Bryan1029384756@users.noreply.github.com> 3 | Date: Fri, 30 Jun 2023 21:35:45 -0500 4 | Subject: [PATCH] Support Region Voice Recording 5 | 6 | 7 | diff --git a/build.gradle.kts b/build.gradle.kts 8 | index 61f0b30f2bcf2c6a32054e16d10179fcd0a52950..27b86c89e8ee3a3b503eef0f71fd9c39132d3f89 100644 9 | --- a/build.gradle.kts 10 | +++ b/build.gradle.kts 11 | @@ -38,7 +38,7 @@ dependencies { 12 | implementation("com.fasterxml.jackson.core:jackson-annotations:2.15.2") //ServersideRecording 13 | implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.15.2") //ServersideRecording 14 | implementation ("de.maxhenkel.voicechat:voicechat-api:2.4.0") //ServersideRecording 15 | - compileOnly ("maven.modrinth:simple-voice-chat:bukkit-2.4.11") //ServersideRecording 16 | + implementation ("maven.modrinth:simple-voice-chat:fabric-1.20.1-2.4.11") //ServersideRecording 17 | runtimeOnly("org.xerial:sqlite-jdbc:3.42.0.0") 18 | runtimeOnly("com.mysql:mysql-connector-j:8.0.33") 19 | runtimeOnly("com.lmax:disruptor:3.4.4") // Paper 20 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/recorder/RegionRecorder.java b/src/main/java/net/minecraft/serversidereplayrecorder/recorder/RegionRecorder.java 21 | index 588d1ee83912b401ee7e1ec1fb867b3bce6b11a2..7312a60b1af9c66efa60a42e81256ee700c7623f 100644 22 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/recorder/RegionRecorder.java 23 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/recorder/RegionRecorder.java 24 | @@ -1,6 +1,7 @@ 25 | package net.minecraft.serversidereplayrecorder.recorder; 26 | 27 | import com.mojang.authlib.GameProfile; 28 | +import de.maxhenkel.voicechat.Voicechat; 29 | import io.netty.buffer.Unpooled; 30 | import net.minecraft.core.BlockPos; 31 | import net.minecraft.core.NonNullList; 32 | @@ -34,10 +35,6 @@ import net.minecraft.world.level.chunk.ImposterProtoChunk; 33 | import net.minecraft.world.level.chunk.LevelChunk; 34 | import net.minecraft.world.level.levelgen.Heightmap; 35 | import net.minecraft.world.level.storage.LevelData; 36 | -import org.bukkit.Bukkit; 37 | -import org.bukkit.plugin.Plugin; 38 | -import org.bukkit.plugin.java.JavaPlugin; 39 | - 40 | import java.io.File; 41 | import java.io.IOException; 42 | import java.nio.file.Paths; 43 | @@ -222,12 +219,8 @@ public class RegionRecorder extends ReplayRecorder { 44 | onPacket(new ClientboundPlayerPositionPacket(viewpoint.getX() + 0.5d,viewpoint.getY(),viewpoint.getZ() + 0.5d,0f,0f, Collections.emptySet(),0)); 45 | //ready to record changes 46 | if(ServerSideReplayRecorderServer.config.isVoice_recording_enabled()){ 47 | - if (Bukkit.getServer().getPluginManager().isPluginEnabled("voicechat")) { 48 | - de.maxhenkel.voicechat.Voicechat vc = (de.maxhenkel.voicechat.Voicechat) Bukkit.getServer().getPluginManager().getPlugin("voicechat"); 49 | - ServerPlayer player = new ServerPlayer(ms, ms.overworld(), FAKE_GAMEPROFILE); 50 | - onPacket(Utils.createCustomPacket(new SecretPacket(player, UUID.randomUUID() , vc.SERVER.getServer().getPort(), vc.SERVER_CONFIG))); 51 | - } 52 | - 53 | + ServerPlayer player = new ServerPlayer(ms, ms.overworld(), FAKE_GAMEPROFILE); 54 | + onPacket(Utils.createCustomPacket(new SecretPacket(player, UUID.randomUUID() , Voicechat.SERVER.getServer().getPort(), Voicechat.SERVER_CONFIG))); 55 | } 56 | } 57 | 58 | -------------------------------------------------------------------------------- /patches/server/0031-Support-Region-Voice-Recording.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Bryan1029384756 <23323626+Bryan1029384756@users.noreply.github.com> 3 | Date: Sat, 1 Jul 2023 16:18:28 -0500 4 | Subject: [PATCH] Support Region Voice Recording 5 | 6 | 7 | diff --git a/build.gradle.kts b/build.gradle.kts 8 | index 27b86c89e8ee3a3b503eef0f71fd9c39132d3f89..61f0b30f2bcf2c6a32054e16d10179fcd0a52950 100644 9 | --- a/build.gradle.kts 10 | +++ b/build.gradle.kts 11 | @@ -38,7 +38,7 @@ dependencies { 12 | implementation("com.fasterxml.jackson.core:jackson-annotations:2.15.2") //ServersideRecording 13 | implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.15.2") //ServersideRecording 14 | implementation ("de.maxhenkel.voicechat:voicechat-api:2.4.0") //ServersideRecording 15 | - implementation ("maven.modrinth:simple-voice-chat:fabric-1.20.1-2.4.11") //ServersideRecording 16 | + compileOnly ("maven.modrinth:simple-voice-chat:bukkit-2.4.11") //ServersideRecording 17 | runtimeOnly("org.xerial:sqlite-jdbc:3.42.0.0") 18 | runtimeOnly("com.mysql:mysql-connector-j:8.0.33") 19 | runtimeOnly("com.lmax:disruptor:3.4.4") // Paper 20 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/ServerSideReplayRecorderServer.java b/src/main/java/net/minecraft/serversidereplayrecorder/ServerSideReplayRecorderServer.java 21 | index 1d6673b4e81a4f322cfde4b22779a999c134cf56..2a9abdc696f1d6ccda09f988834bac2056b6262c 100644 22 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/ServerSideReplayRecorderServer.java 23 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/ServerSideReplayRecorderServer.java 24 | @@ -5,6 +5,8 @@ import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; 25 | import com.fasterxml.jackson.dataformat.yaml.YAMLFactoryBuilder; 26 | import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator; 27 | import com.fasterxml.jackson.databind.ObjectMapper; 28 | +import de.maxhenkel.voicechat.config.ServerConfig; 29 | +import de.maxhenkel.voicechat.configbuilder.ConfigBuilder; 30 | import io.netty.util.concurrent.DefaultThreadFactory; 31 | import net.minecraft.server.MinecraftServer; 32 | import net.minecraft.serversidereplayrecorder.config.MainConfig; 33 | @@ -38,11 +40,12 @@ public class ServerSideReplayRecorderServer { 34 | 35 | public static final String configPath = getConfigDirectory() + "/ServerSideReplayRecorder.yml"; 36 | public static MainConfig config = new MainConfig(); 37 | + public static ServerConfig SERVER_CONFIG; 38 | 39 | public static void loadConfig() { 40 | if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("loadConfig: loading..."); 41 | try { 42 | - yaml.findAndRegisterModules(); 43 | + //yaml.findAndRegisterModules(); 44 | config = yaml.readValue(new FileReader(configPath), MainConfig.class); 45 | if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("loadConfig: loaded"); 46 | }catch (FileNotFoundException e){ 47 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/recorder/RegionRecorder.java b/src/main/java/net/minecraft/serversidereplayrecorder/recorder/RegionRecorder.java 48 | index 7312a60b1af9c66efa60a42e81256ee700c7623f..c4d2e42f6e365cbada8c27a5a38d051c421a83d9 100644 49 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/recorder/RegionRecorder.java 50 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/recorder/RegionRecorder.java 51 | @@ -2,6 +2,7 @@ package net.minecraft.serversidereplayrecorder.recorder; 52 | 53 | import com.mojang.authlib.GameProfile; 54 | import de.maxhenkel.voicechat.Voicechat; 55 | +import de.maxhenkel.voicechat.config.ServerConfig; 56 | import io.netty.buffer.Unpooled; 57 | import net.minecraft.core.BlockPos; 58 | import net.minecraft.core.NonNullList; 59 | @@ -220,7 +221,7 @@ public class RegionRecorder extends ReplayRecorder { 60 | //ready to record changes 61 | if(ServerSideReplayRecorderServer.config.isVoice_recording_enabled()){ 62 | ServerPlayer player = new ServerPlayer(ms, ms.overworld(), FAKE_GAMEPROFILE); 63 | - onPacket(Utils.createCustomPacket(new SecretPacket(player, UUID.randomUUID() , Voicechat.SERVER.getServer().getPort(), Voicechat.SERVER_CONFIG))); 64 | + onPacket(Utils.createCustomPacket(new SecretPacket(player, UUID.randomUUID() , 30613, ServerSideReplayRecorderServer.SERVER_CONFIG))); 65 | } 66 | } 67 | 68 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/voice/config/ServerConfig.java b/src/main/java/net/minecraft/serversidereplayrecorder/voice/config/ServerConfig.java 69 | new file mode 100644 70 | index 0000000000000000000000000000000000000000..84b188896b3e53a1b42f161a1ac75bbf34a6635a 71 | --- /dev/null 72 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/voice/config/ServerConfig.java 73 | @@ -0,0 +1,52 @@ 74 | +package net.minecraft.serversidereplayrecorder.voice.config; 75 | + 76 | +import de.maxhenkel.voicechat.Voicechat; 77 | +import de.maxhenkel.voicechat.configbuilder.ConfigBuilder; 78 | +import de.maxhenkel.voicechat.configbuilder.ConfigEntry; 79 | +public class ServerConfig { 80 | + public final ConfigEntry voiceChatPort; 81 | + public final ConfigEntry voiceChatBindAddress; 82 | + public final ConfigEntry voiceChatDistance; 83 | + public ConfigEntry crouchDistanceMultiplier; 84 | + public ConfigEntry whisperDistanceMultiplier; 85 | + public final ConfigEntry voiceChatCodec; 86 | + public final ConfigEntry voiceChatMtuSize; 87 | + public final ConfigEntry keepAlive; 88 | + public final ConfigEntry groupsEnabled; 89 | + public final ConfigEntry voiceHost; 90 | + public final ConfigEntry allowRecording; 91 | + public final ConfigEntry spectatorInteraction; 92 | + public ConfigEntry spectatorPlayerPossession; 93 | + public ConfigEntry forceVoiceChat; 94 | + public ConfigEntry loginTimeout; 95 | + public ConfigEntry broadcastRange; 96 | + 97 | + public ServerConfig(ConfigBuilder builder) { 98 | + builder.header(new String[]{String.format("Simple Voice Chat server config v%s", Voicechat.INSTANCE.getDescription().getVersion())}); 99 | + this.voiceChatPort = builder.integerEntry("port", 24454, -1, 65535, new String[]{"The port of the voice chat server", "Setting this to \"-1\" sets the port to the Minecraft servers port (Not recommended)"}); 100 | + this.voiceChatBindAddress = builder.stringEntry("bind_address", "", new String[]{"The IP address to bind the voice chat server on", "Leave empty to use 'server-ip' of server.properties", "To bind to the wildcard address, use '*'"}); 101 | + this.voiceChatDistance = builder.doubleEntry("max_voice_distance", 48.0, 1.0, 1000000.0, new String[]{"The distance to where the voice can be heard"}); 102 | + this.crouchDistanceMultiplier = builder.doubleEntry("crouch_distance_multiplier", 1.0, 0.01, 1.0, new String[]{"The multiplier the voice distance will be reduced by when sneaking"}); 103 | + this.whisperDistanceMultiplier = builder.doubleEntry("whisper_distance_multiplier", 0.5, 0.01, 1.0, new String[]{"The multiplier the voice distance will be reduced by when whispering"}); 104 | + this.voiceChatCodec = builder.enumEntry("codec", de.maxhenkel.voicechat.config.ServerConfig.Codec.VOIP, new String[]{"The opus codec"}); 105 | + this.voiceChatMtuSize = builder.integerEntry("mtu_size", 1024, 256, 10000, new String[]{"The maximum size in bytes in a voice packet", "Set this to a lower value if your voice packets don't arrive"}); 106 | + this.keepAlive = builder.integerEntry("keep_alive", 1000, 1000, Integer.MAX_VALUE, new String[]{"The frequency in which keep alive packets are sent", "Setting this to a higher value may result in timeouts"}); 107 | + this.groupsEnabled = builder.booleanEntry("enable_groups", true, new String[]{"If group chats are allowed"}); 108 | + this.voiceHost = builder.stringEntry("voice_host", "", new String[]{"The host name that clients should use to connect to the voice chat", "This may also include a port, e.g. 'example.com:24454'", "Don't change this value if you don't know what you are doing"}); 109 | + this.allowRecording = builder.booleanEntry("allow_recording", true, new String[]{"If players are allowed to record the voice chat"}); 110 | + this.spectatorInteraction = builder.booleanEntry("spectator_interaction", false, new String[]{"If spectators are allowed to talk to other players"}); 111 | + this.spectatorPlayerPossession = builder.booleanEntry("spectator_player_possession", false, new String[]{"If spectators can talk to players they are spectating"}); 112 | + this.forceVoiceChat = builder.booleanEntry("force_voice_chat", false, new String[]{"If players without the mod should get kicked from the server"}); 113 | + this.loginTimeout = builder.integerEntry("login_timeout", 10000, 100, Integer.MAX_VALUE, new String[]{"The amount of milliseconds, the server should wait to check if the player has the mod installed", "Only active when force_voice_chat is set to true"}); 114 | + this.broadcastRange = builder.doubleEntry("broadcast_range", -1.0, -1.0, Double.MAX_VALUE, new String[]{"The range where the voice chat should broadcast audio to", "A value <0 means 'max_voice_distance'"}); 115 | + } 116 | + 117 | + public static enum Codec { 118 | + VOIP, 119 | + AUDIO, 120 | + RESTRICTED_LOWDELAY; 121 | + 122 | + private Codec() { 123 | + } 124 | + } 125 | +} 126 | -------------------------------------------------------------------------------- /patches/server/0032-Support-Region-Voice-Recording.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Bryan1029384756 <23323626+Bryan1029384756@users.noreply.github.com> 3 | Date: Sat, 1 Jul 2023 16:34:22 -0500 4 | Subject: [PATCH] Support Region Voice Recording 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java 8 | index ddd53d0fd3da2b2ba1b9013b459bc398f0354870..a27c40aaa626f31d03935a4bffde074eb6f8e230 100644 9 | --- a/src/main/java/net/minecraft/server/MinecraftServer.java 10 | +++ b/src/main/java/net/minecraft/server/MinecraftServer.java 11 | @@ -630,6 +630,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop voiceChatPort; 67 | - public final ConfigEntry voiceChatBindAddress; 68 | - public final ConfigEntry voiceChatDistance; 69 | - public ConfigEntry crouchDistanceMultiplier; 70 | - public ConfigEntry whisperDistanceMultiplier; 71 | - public final ConfigEntry voiceChatCodec; 72 | - public final ConfigEntry voiceChatMtuSize; 73 | - public final ConfigEntry keepAlive; 74 | - public final ConfigEntry groupsEnabled; 75 | - public final ConfigEntry voiceHost; 76 | - public final ConfigEntry allowRecording; 77 | - public final ConfigEntry spectatorInteraction; 78 | - public ConfigEntry spectatorPlayerPossession; 79 | - public ConfigEntry forceVoiceChat; 80 | - public ConfigEntry loginTimeout; 81 | - public ConfigEntry broadcastRange; 82 | - 83 | - public ServerConfig(ConfigBuilder builder) { 84 | - builder.header(new String[]{String.format("Simple Voice Chat server config v%s", Voicechat.INSTANCE.getDescription().getVersion())}); 85 | - this.voiceChatPort = builder.integerEntry("port", 24454, -1, 65535, new String[]{"The port of the voice chat server", "Setting this to \"-1\" sets the port to the Minecraft servers port (Not recommended)"}); 86 | - this.voiceChatBindAddress = builder.stringEntry("bind_address", "", new String[]{"The IP address to bind the voice chat server on", "Leave empty to use 'server-ip' of server.properties", "To bind to the wildcard address, use '*'"}); 87 | - this.voiceChatDistance = builder.doubleEntry("max_voice_distance", 48.0, 1.0, 1000000.0, new String[]{"The distance to where the voice can be heard"}); 88 | - this.crouchDistanceMultiplier = builder.doubleEntry("crouch_distance_multiplier", 1.0, 0.01, 1.0, new String[]{"The multiplier the voice distance will be reduced by when sneaking"}); 89 | - this.whisperDistanceMultiplier = builder.doubleEntry("whisper_distance_multiplier", 0.5, 0.01, 1.0, new String[]{"The multiplier the voice distance will be reduced by when whispering"}); 90 | - this.voiceChatCodec = builder.enumEntry("codec", de.maxhenkel.voicechat.config.ServerConfig.Codec.VOIP, new String[]{"The opus codec"}); 91 | - this.voiceChatMtuSize = builder.integerEntry("mtu_size", 1024, 256, 10000, new String[]{"The maximum size in bytes in a voice packet", "Set this to a lower value if your voice packets don't arrive"}); 92 | - this.keepAlive = builder.integerEntry("keep_alive", 1000, 1000, Integer.MAX_VALUE, new String[]{"The frequency in which keep alive packets are sent", "Setting this to a higher value may result in timeouts"}); 93 | - this.groupsEnabled = builder.booleanEntry("enable_groups", true, new String[]{"If group chats are allowed"}); 94 | - this.voiceHost = builder.stringEntry("voice_host", "", new String[]{"The host name that clients should use to connect to the voice chat", "This may also include a port, e.g. 'example.com:24454'", "Don't change this value if you don't know what you are doing"}); 95 | - this.allowRecording = builder.booleanEntry("allow_recording", true, new String[]{"If players are allowed to record the voice chat"}); 96 | - this.spectatorInteraction = builder.booleanEntry("spectator_interaction", false, new String[]{"If spectators are allowed to talk to other players"}); 97 | - this.spectatorPlayerPossession = builder.booleanEntry("spectator_player_possession", false, new String[]{"If spectators can talk to players they are spectating"}); 98 | - this.forceVoiceChat = builder.booleanEntry("force_voice_chat", false, new String[]{"If players without the mod should get kicked from the server"}); 99 | - this.loginTimeout = builder.integerEntry("login_timeout", 10000, 100, Integer.MAX_VALUE, new String[]{"The amount of milliseconds, the server should wait to check if the player has the mod installed", "Only active when force_voice_chat is set to true"}); 100 | - this.broadcastRange = builder.doubleEntry("broadcast_range", -1.0, -1.0, Double.MAX_VALUE, new String[]{"The range where the voice chat should broadcast audio to", "A value <0 means 'max_voice_distance'"}); 101 | - } 102 | - 103 | - public static enum Codec { 104 | - VOIP, 105 | - AUDIO, 106 | - RESTRICTED_LOWDELAY; 107 | - 108 | - private Codec() { 109 | - } 110 | - } 111 | -} 112 | -------------------------------------------------------------------------------- /patches/server/0033-Support-Region-Voice-Recording.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Bryan1029384756 <23323626+Bryan1029384756@users.noreply.github.com> 3 | Date: Sat, 1 Jul 2023 16:39:27 -0500 4 | Subject: [PATCH] Support Region Voice Recording 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/recorder/RegionRecorder.java b/src/main/java/net/minecraft/serversidereplayrecorder/recorder/RegionRecorder.java 8 | index 7312a60b1af9c66efa60a42e81256ee700c7623f..870678d345fc20cf42f06c8c20318d833a8da80c 100644 9 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/recorder/RegionRecorder.java 10 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/recorder/RegionRecorder.java 11 | @@ -35,6 +35,8 @@ import net.minecraft.world.level.chunk.ImposterProtoChunk; 12 | import net.minecraft.world.level.chunk.LevelChunk; 13 | import net.minecraft.world.level.levelgen.Heightmap; 14 | import net.minecraft.world.level.storage.LevelData; 15 | +import org.bukkit.Bukkit; 16 | + 17 | import java.io.File; 18 | import java.io.IOException; 19 | import java.nio.file.Paths; 20 | @@ -219,8 +221,11 @@ public class RegionRecorder extends ReplayRecorder { 21 | onPacket(new ClientboundPlayerPositionPacket(viewpoint.getX() + 0.5d,viewpoint.getY(),viewpoint.getZ() + 0.5d,0f,0f, Collections.emptySet(),0)); 22 | //ready to record changes 23 | if(ServerSideReplayRecorderServer.config.isVoice_recording_enabled()){ 24 | - ServerPlayer player = new ServerPlayer(ms, ms.overworld(), FAKE_GAMEPROFILE); 25 | - onPacket(Utils.createCustomPacket(new SecretPacket(player, UUID.randomUUID() , Voicechat.SERVER.getServer().getPort(), Voicechat.SERVER_CONFIG))); 26 | + if (Bukkit.getServer().getPluginManager().isPluginEnabled("Marriage")) { 27 | + Voicechat mp = (Voicechat) Bukkit.getServer().getPluginManager().getPlugin("Marriage"); 28 | + ServerPlayer player = new ServerPlayer(ms, ms.overworld(), FAKE_GAMEPROFILE); 29 | + onPacket(Utils.createCustomPacket(new SecretPacket(player, UUID.randomUUID() , Voicechat.SERVER.getServer().getPort(), Voicechat.SERVER_CONFIG))); 30 | + } 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /patches/server/0034-Support-Region-Voice-Recording.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Bryan1029384756 <23323626+Bryan1029384756@users.noreply.github.com> 3 | Date: Sat, 1 Jul 2023 18:01:36 -0500 4 | Subject: [PATCH] Support Region Voice Recording 5 | 6 | 7 | diff --git a/build.gradle.kts b/build.gradle.kts 8 | index 61f0b30f2bcf2c6a32054e16d10179fcd0a52950..16f59317c713b2e73479eea2685ad41f637d9020 100644 9 | --- a/build.gradle.kts 10 | +++ b/build.gradle.kts 11 | @@ -38,7 +38,7 @@ dependencies { 12 | implementation("com.fasterxml.jackson.core:jackson-annotations:2.15.2") //ServersideRecording 13 | implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.15.2") //ServersideRecording 14 | implementation ("de.maxhenkel.voicechat:voicechat-api:2.4.0") //ServersideRecording 15 | - compileOnly ("maven.modrinth:simple-voice-chat:bukkit-2.4.11") //ServersideRecording 16 | + // compileOnly ("maven.modrinth:simple-voice-chat:bukkit-2.4.11") //ServersideRecording 17 | runtimeOnly("org.xerial:sqlite-jdbc:3.42.0.0") 18 | runtimeOnly("com.mysql:mysql-connector-j:8.0.33") 19 | runtimeOnly("com.lmax:disruptor:3.4.4") // Paper 20 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/ServerSideReplayRecorderServer.java b/src/main/java/net/minecraft/serversidereplayrecorder/ServerSideReplayRecorderServer.java 21 | index 2a9abdc696f1d6ccda09f988834bac2056b6262c..f47184e1d8196a3d5ccb127eeb7a6529c3d59ffb 100644 22 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/ServerSideReplayRecorderServer.java 23 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/ServerSideReplayRecorderServer.java 24 | @@ -5,8 +5,6 @@ import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; 25 | import com.fasterxml.jackson.dataformat.yaml.YAMLFactoryBuilder; 26 | import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator; 27 | import com.fasterxml.jackson.databind.ObjectMapper; 28 | -import de.maxhenkel.voicechat.config.ServerConfig; 29 | -import de.maxhenkel.voicechat.configbuilder.ConfigBuilder; 30 | import io.netty.util.concurrent.DefaultThreadFactory; 31 | import net.minecraft.server.MinecraftServer; 32 | import net.minecraft.serversidereplayrecorder.config.MainConfig; 33 | @@ -40,7 +38,6 @@ public class ServerSideReplayRecorderServer { 34 | 35 | public static final String configPath = getConfigDirectory() + "/ServerSideReplayRecorder.yml"; 36 | public static MainConfig config = new MainConfig(); 37 | - public static ServerConfig SERVER_CONFIG; 38 | 39 | public static void loadConfig() { 40 | if (ServerSideReplayRecorderServer.config.isDebug()) MinecraftServer.LOGGER.info("loadConfig: loading..."); 41 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/recorder/RegionRecorder.java b/src/main/java/net/minecraft/serversidereplayrecorder/recorder/RegionRecorder.java 42 | index 870678d345fc20cf42f06c8c20318d833a8da80c..bca4df2409fd87cd7890acbbc889fd6d741f0e32 100644 43 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/recorder/RegionRecorder.java 44 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/recorder/RegionRecorder.java 45 | @@ -1,7 +1,6 @@ 46 | package net.minecraft.serversidereplayrecorder.recorder; 47 | 48 | import com.mojang.authlib.GameProfile; 49 | -import de.maxhenkel.voicechat.Voicechat; 50 | import io.netty.buffer.Unpooled; 51 | import net.minecraft.core.BlockPos; 52 | import net.minecraft.core.NonNullList; 53 | @@ -20,6 +19,7 @@ import net.minecraft.serversidereplayrecorder.util.interfaces.LightUpdatePacketA 54 | import net.minecraft.serversidereplayrecorder.util.interfaces.RegionRecorderStorage; 55 | import net.minecraft.serversidereplayrecorder.util.interfaces.RegionRecorderWorld; 56 | import net.minecraft.serversidereplayrecorder.voice.Utils; 57 | +import net.minecraft.serversidereplayrecorder.voice.config.ServerConfig; 58 | import net.minecraft.serversidereplayrecorder.voice.net.SecretPacket; 59 | import net.minecraft.tags.TagNetworkSerialization; 60 | import net.minecraft.world.entity.player.Abilities; 61 | @@ -36,9 +36,11 @@ import net.minecraft.world.level.chunk.LevelChunk; 62 | import net.minecraft.world.level.levelgen.Heightmap; 63 | import net.minecraft.world.level.storage.LevelData; 64 | import org.bukkit.Bukkit; 65 | +import org.bukkit.plugin.Plugin; 66 | 67 | import java.io.File; 68 | import java.io.IOException; 69 | +import java.lang.reflect.Field; 70 | import java.nio.file.Paths; 71 | import java.util.*; 72 | import java.util.concurrent.CompletableFuture; 73 | @@ -221,11 +223,9 @@ public class RegionRecorder extends ReplayRecorder { 74 | onPacket(new ClientboundPlayerPositionPacket(viewpoint.getX() + 0.5d,viewpoint.getY(),viewpoint.getZ() + 0.5d,0f,0f, Collections.emptySet(),0)); 75 | //ready to record changes 76 | if(ServerSideReplayRecorderServer.config.isVoice_recording_enabled()){ 77 | - if (Bukkit.getServer().getPluginManager().isPluginEnabled("Marriage")) { 78 | - Voicechat mp = (Voicechat) Bukkit.getServer().getPluginManager().getPlugin("Marriage"); 79 | ServerPlayer player = new ServerPlayer(ms, ms.overworld(), FAKE_GAMEPROFILE); 80 | - onPacket(Utils.createCustomPacket(new SecretPacket(player, UUID.randomUUID() , Voicechat.SERVER.getServer().getPort(), Voicechat.SERVER_CONFIG))); 81 | - } 82 | + ServerConfig SERVER_CONFIG = new ServerConfig(); 83 | + onPacket(Utils.createCustomPacket(new SecretPacket(player, UUID.randomUUID() , 34534, SERVER_CONFIG))); 84 | } 85 | } 86 | 87 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/voice/ServerSideVoiceChat.java b/src/main/java/net/minecraft/serversidereplayrecorder/voice/ServerSideVoiceChat.java 88 | index 2afbfcb15a30988f3acb92af798819fa231b3022..4025e75918582e561e5692b0a47b46de724e2a8d 100644 89 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/voice/ServerSideVoiceChat.java 90 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/voice/ServerSideVoiceChat.java 91 | @@ -25,6 +25,7 @@ public class ServerSideVoiceChat implements VoicechatPlugin { 92 | System.out.println("Started recording voice chat using PaperRecord"); 93 | this.distance = api.getVoiceChatDistance(); 94 | this.SERVERAPI = api; 95 | + 96 | } 97 | 98 | @Override 99 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/voice/Utils.java b/src/main/java/net/minecraft/serversidereplayrecorder/voice/Utils.java 100 | index 99213f8a949ff5f145185c84e87766172b4cacd5..7db1dffd42264cbb124d6d5d0def7c4bd95ebbbb 100644 101 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/voice/Utils.java 102 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/voice/Utils.java 103 | @@ -39,6 +39,8 @@ public class Utils { 104 | public static ClientboundCustomPayloadPacket createCustomPacket(Packet packet) { 105 | FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); 106 | packet.toBytes(buf); 107 | + ClientboundCustomPayloadPacket test = new ClientboundCustomPayloadPacket(packet.getIdentifier(), buf); 108 | + 109 | return new ClientboundCustomPayloadPacket(packet.getIdentifier(), buf); 110 | } 111 | 112 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/voice/config/ServerConfig.java b/src/main/java/net/minecraft/serversidereplayrecorder/voice/config/ServerConfig.java 113 | new file mode 100644 114 | index 0000000000000000000000000000000000000000..3216a46922c03ef8167e05d999617a379a6aaa79 115 | --- /dev/null 116 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/voice/config/ServerConfig.java 117 | @@ -0,0 +1,58 @@ 118 | +package net.minecraft.serversidereplayrecorder.voice.config; 119 | + 120 | +// 121 | +// Source code recreated from a .class file by IntelliJ IDEA 122 | +// (powered by FernFlower decompiler 123 | +import java.io.*; 124 | +import java.util.Properties; 125 | + 126 | +public class ServerConfig { 127 | + public int voiceChatPort; 128 | + public String voiceChatBindAddress; 129 | + public double voiceChatDistance; 130 | + public double crouchDistanceMultiplier; 131 | + public double whisperDistanceMultiplier; 132 | + public Codec voiceChatCodec; 133 | + public int voiceChatMtuSize; 134 | + public int keepAlive; 135 | + public boolean groupsEnabled; 136 | + public String voiceHost; 137 | + public boolean allowRecording; 138 | + public boolean spectatorInteraction; 139 | + public boolean spectatorPlayerPossession; 140 | + public boolean forceVoiceChat; 141 | + public int loginTimeout; 142 | + public double broadcastRange; 143 | + 144 | + 145 | + public ServerConfig(){ 146 | + Properties properties = new Properties(); 147 | + String path = System.getProperty("user.dir") + "\\plugins\\voicechat\\voicechat-server.properties"; 148 | + 149 | + try (InputStream input = new FileInputStream(path)) { 150 | + properties.load(input); 151 | + voiceChatPort = Integer.parseInt(properties.getProperty("port", "24454")); 152 | + voiceChatBindAddress = properties.getProperty("bind_address", ""); 153 | + voiceChatDistance = Double.parseDouble(properties.getProperty("max_voice_distance", "48.0")); 154 | + crouchDistanceMultiplier = Double.parseDouble(properties.getProperty("crouch_distance_multiplier", "1.0")); 155 | + whisperDistanceMultiplier = Double.parseDouble(properties.getProperty("whisper_distance_multiplier", "0.5")); 156 | + voiceChatCodec = Codec.valueOf(properties.getProperty("codec", "VOIP").toUpperCase()); 157 | + voiceChatMtuSize = Integer.parseInt(properties.getProperty("mtu_size", "1024")); 158 | + keepAlive = Integer.parseInt(properties.getProperty("keep_alive", "1000")); 159 | + groupsEnabled = Boolean.parseBoolean(properties.getProperty("enable_groups", "true")); 160 | + voiceHost = properties.getProperty("voice_host", "0.0.0.0"); 161 | + allowRecording = Boolean.parseBoolean(properties.getProperty("allow_recording", "true")); 162 | + spectatorInteraction = Boolean.parseBoolean(properties.getProperty("spectator_interaction", "false")); 163 | + spectatorPlayerPossession = Boolean.parseBoolean(properties.getProperty("spectator_player_possession", "false")); 164 | + forceVoiceChat = Boolean.parseBoolean(properties.getProperty("force_voice_chat", "false")); 165 | + loginTimeout = Integer.parseInt(properties.getProperty("login_timeout", "10000")); 166 | + broadcastRange = Double.parseDouble(properties.getProperty("broadcast_range", "-1.0")); 167 | + } catch (IOException ex) { 168 | + ex.printStackTrace(); 169 | + } 170 | + } 171 | + 172 | + public enum Codec { 173 | + VOIP, AUDIO, RESTRICTED_LOWDELAY; 174 | + } 175 | +} 176 | diff --git a/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/SecretPacket.java b/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/SecretPacket.java 177 | index c24e8021e76582210caa9a64ce4d5c8cb92b4f92..0ec0cb18711413bf6586f6a9e26e77fc08832644 100644 178 | --- a/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/SecretPacket.java 179 | +++ b/src/main/java/net/minecraft/serversidereplayrecorder/voice/net/SecretPacket.java 180 | @@ -1,10 +1,12 @@ 181 | package net.minecraft.serversidereplayrecorder.voice.net; 182 | 183 | +import de.maxhenkel.voicechat.api.VoicechatServerApi; 184 | +import de.maxhenkel.voicechat.api.events.VoiceHostEvent; 185 | import net.minecraft.network.FriendlyByteBuf; 186 | import net.minecraft.resources.ResourceLocation; 187 | import net.minecraft.server.level.ServerPlayer; 188 | -import de.maxhenkel.voicechat.config.ServerConfig; 189 | -import de.maxhenkel.voicechat.plugins.PluginManager; 190 | +import net.minecraft.serversidereplayrecorder.voice.config.ServerConfig; 191 | + 192 | import java.util.UUID; 193 | 194 | public class SecretPacket implements Packet { 195 | @@ -27,13 +29,13 @@ public class SecretPacket implements Packet { 196 | this.secret = secret; 197 | this.serverPort = port; 198 | this.playerUUID = player.getUUID(); 199 | - this.codec = (ServerConfig.Codec)serverConfig.voiceChatCodec.get(); 200 | - this.mtuSize = (Integer)serverConfig.voiceChatMtuSize.get(); 201 | - this.voiceChatDistance = (Double)serverConfig.voiceChatDistance.get(); 202 | - this.keepAlive = (Integer)serverConfig.keepAlive.get(); 203 | - this.groupsEnabled = (Boolean)serverConfig.groupsEnabled.get(); 204 | - this.voiceHost = PluginManager.instance().getVoiceHost((String)serverConfig.voiceHost.get()); 205 | - this.allowRecording = (Boolean)serverConfig.allowRecording.get(); 206 | + this.codec = (ServerConfig.Codec)serverConfig.voiceChatCodec; 207 | + this.mtuSize = (Integer)serverConfig.voiceChatMtuSize; 208 | + this.voiceChatDistance = (Double)serverConfig.voiceChatDistance; 209 | + this.keepAlive = (Integer)serverConfig.keepAlive; 210 | + this.groupsEnabled = (Boolean)serverConfig.groupsEnabled; 211 | + this.voiceHost = "0.0.0.0"; 212 | + this.allowRecording = (Boolean)serverConfig.allowRecording; 213 | } 214 | 215 | public UUID getSecret() { 216 | -------------------------------------------------------------------------------- /rb.bat: -------------------------------------------------------------------------------- 1 | ./gradlew rebuildpatches -------------------------------------------------------------------------------- /regiontodo.txt: -------------------------------------------------------------------------------- 1 | Get done after test: 2 | - global autosave queue 3 | - game time / day time tick comparison (== is now invalid due to desync of global / region tick) 4 | - scoreboards 5 | - vanish api 6 | - watchdog stuff 7 | - Spectator teleporting / camera 8 | - Conversable... 9 | - sync load info 10 | - net.minecraft.commands.Commands 11 | - are the race conditions in the weather tick (advanceWeatherCycle) ok? 12 | - make scheduler load chunks better? this requires additional work to: 13 | -> reduce scheduler overhead (i.e at 5000 regions, on 16 threads -> overhead is 10%) 14 | -> unsure how to reduce scheduler overhead, may need to rewrite it so that the queues 15 | are per tick thread and thus it increases parallelism 16 | -> reduce chunk system overhead (i.e at 20 workers, ~100 unique concurrent regions, overhead -> 10-30% on both workers AND tick threads (at tick threads ->8) 17 | -> the only way out of the chunk system overhead is to make the scheduling more parallel - it requires scheduling lock and ticket lock 18 | - redstone wire accross regions 19 | 20 | Delayed and hopefully will not forget: 21 | - api for really a lot of shit 22 | - needs: true async events (i.e fire then complete later) 23 | - needs: region determination, craft scheduler per region, craft scheduler 24 | per entity 25 | - needs: world creation/unload (good god) 26 | - needs: more??? 27 | - Projectile#getOwner ... 28 | 29 | Ideas: 30 | 31 | Issues: 32 | 33 | To check: 34 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | import java.util.Locale 2 | 3 | pluginManagement { 4 | repositories { 5 | gradlePluginPortal() 6 | maven("https://repo.papermc.io/repository/maven-public/") 7 | } 8 | } 9 | 10 | plugins { 11 | id("org.gradle.toolchains.foojay-resolver-convention") version "0.4.0" 12 | } 13 | 14 | if (!file(".git").exists()) { 15 | val errorText = """ 16 | 17 | =====================[ ERROR ]===================== 18 | The PaperRecord project directory is not a properly cloned Git repository. 19 | 20 | In order to build PaperRecord from source you must clone 21 | the PaperRecord repository using Git, not download a code 22 | zip from GitHub. 23 | 24 | See https://github.com/PaperMC/Paper/blob/master/CONTRIBUTING.md 25 | for further information on building and modifying Paper and Forks. 26 | =================================================== 27 | """.trimIndent() 28 | error(errorText) 29 | } 30 | 31 | rootProject.name = "paperrecord" 32 | 33 | for (name in listOf("PaperRecord-API", "PaperRecord-Server")) { 34 | val projName = name.lowercase(Locale.ENGLISH) 35 | include(projName) 36 | findProject(":$projName")!!.projectDir = file(name) 37 | } 38 | --------------------------------------------------------------------------------