├── chunkcopy-fabric-1.19 ├── gradlew ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── src │ └── main │ │ ├── resources │ │ ├── assets │ │ │ └── chunkcopy │ │ │ │ ├── icon.png │ │ │ │ ├── icon.aseprite │ │ │ │ └── lang │ │ │ │ ├── en_us.json │ │ │ │ └── ru_ru.json │ │ ├── chunkcopy.mixins.json │ │ ├── chunkcopy.client.mixins.json │ │ └── fabric.mod.json │ │ └── java │ │ └── thecsdev │ │ └── chunkcopy │ │ ├── api │ │ ├── io │ │ │ ├── Tuple.java │ │ │ └── IOUtils.java │ │ ├── data │ │ │ ├── ChunkDataBlockID.java │ │ │ ├── package-info.java │ │ │ ├── ChunkDataBlock.java │ │ │ ├── ChunkDataIO.java │ │ │ └── block │ │ │ │ ├── CDBFillBlocks.java │ │ │ │ ├── CDBEntitiesLegacy.java │ │ │ │ ├── CDBChunkSections.java │ │ │ │ ├── CDBBlocksLegacy.java │ │ │ │ └── CDBEntityBlocksLegacy.java │ │ ├── config │ │ │ ├── ConfigKey.java │ │ │ └── ChunkCopyConfig.java │ │ ├── AutoChunkCopy.java │ │ ├── ChunkCopyUtils.java │ │ └── ChunkCopyAPI.java │ │ ├── mixin │ │ └── WorldMixin.java │ │ ├── client │ │ ├── gui │ │ │ └── CCConfigScreen.java │ │ ├── mixin │ │ │ ├── MinecraftClientMixin.java │ │ │ └── ClientChunkMapMixin.java │ │ ├── ChunkCopyClient.java │ │ └── command │ │ │ └── ChunkCopyClientCommand.java │ │ ├── server │ │ ├── ChunkCopyServer.java │ │ └── command │ │ │ └── ChunkCopyServerCommand.java │ │ ├── command │ │ └── argument │ │ │ ├── ConfigValueArgumentType.java │ │ │ ├── ConfigKeyArgumentType.java │ │ │ └── CopiedChunksArgumentType.java │ │ └── ChunkCopy.java ├── settings.gradle ├── gradle.properties ├── build.gradle └── gradlew.bat ├── chunkcopy-fabric-1.18.2 ├── gradlew ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── src │ └── main │ │ ├── resources │ │ ├── assets │ │ │ └── chunkcopy │ │ │ │ ├── icon.png │ │ │ │ ├── icon.aseprite │ │ │ │ └── lang │ │ │ │ ├── en_us.json │ │ │ │ └── ru_ru.json │ │ ├── chunkcopy.mixins.json │ │ ├── chunkcopy.client.mixins.json │ │ └── fabric.mod.json │ │ └── java │ │ └── thecsdev │ │ └── chunkcopy │ │ ├── api │ │ ├── io │ │ │ ├── Tuple.java │ │ │ └── IOUtils.java │ │ ├── data │ │ │ ├── ChunkDataBlockID.java │ │ │ ├── package-info.java │ │ │ ├── ChunkDataBlock.java │ │ │ ├── ChunkDataIO.java │ │ │ └── block │ │ │ │ ├── CDBFillBlocks.java │ │ │ │ ├── CDBEntitiesLegacy.java │ │ │ │ ├── CDBChunkSections.java │ │ │ │ ├── CDBEntityBlocksLegacy.java │ │ │ │ └── CDBBlocksLegacy.java │ │ ├── config │ │ │ ├── ConfigKey.java │ │ │ └── ChunkCopyConfig.java │ │ ├── AutoChunkCopy.java │ │ └── ChunkCopyUtils.java │ │ ├── mixin │ │ └── WorldMixin.java │ │ ├── client │ │ ├── gui │ │ │ └── CCConfigScreen.java │ │ ├── mixin │ │ │ ├── MinecraftClientMixin.java │ │ │ └── ClientChunkMapMixin.java │ │ ├── ChunkCopyClient.java │ │ └── command │ │ │ └── ChunkCopyClientCommand.java │ │ ├── server │ │ ├── ChunkCopyServer.java │ │ └── command │ │ │ └── ChunkCopyServerCommand.java │ │ ├── command │ │ ├── argument │ │ │ ├── ConfigValueArgumentType.java │ │ │ ├── ConfigKeyArgumentType.java │ │ │ └── CopiedChunksArgumentType.java │ │ └── ChunkCopyCommand.java │ │ └── ChunkCopy.java ├── settings.gradle ├── gradle.properties ├── build.gradle └── gradlew.bat ├── .github └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── README.md ├── .gitignore └── LICENSE /chunkcopy-fabric-1.19/gradlew: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCSDev/chunkcopy/HEAD/chunkcopy-fabric-1.19/gradlew -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/gradlew: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCSDev/chunkcopy/HEAD/chunkcopy-fabric-1.18.2/gradlew -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCSDev/chunkcopy/HEAD/chunkcopy-fabric-1.18.2/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCSDev/chunkcopy/HEAD/chunkcopy-fabric-1.19/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/resources/assets/chunkcopy/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCSDev/chunkcopy/HEAD/chunkcopy-fabric-1.19/src/main/resources/assets/chunkcopy/icon.png -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/resources/assets/chunkcopy/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCSDev/chunkcopy/HEAD/chunkcopy-fabric-1.18.2/src/main/resources/assets/chunkcopy/icon.png -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/resources/assets/chunkcopy/icon.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCSDev/chunkcopy/HEAD/chunkcopy-fabric-1.19/src/main/resources/assets/chunkcopy/icon.aseprite -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/resources/assets/chunkcopy/icon.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheCSDev/chunkcopy/HEAD/chunkcopy-fabric-1.18.2/src/main/resources/assets/chunkcopy/icon.aseprite -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { 4 | name = 'Fabric' 5 | url = 'https://maven.fabricmc.net/' 6 | } 7 | mavenCentral() 8 | gradlePluginPortal() 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { 4 | name = 'Fabric' 5 | url = 'https://maven.fabricmc.net/' 6 | } 7 | mavenCentral() 8 | gradlePluginPortal() 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this mod 4 | title: Feature request 5 | labels: Suggestion 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the feature you'd like** 11 | A description of what you want to be added or changed. 12 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/java/thecsdev/chunkcopy/api/io/Tuple.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.api.io; 2 | 3 | public class Tuple 4 | { 5 | public final X Item1; 6 | public final Y Item2; 7 | 8 | public Tuple(X item1, Y item2) 9 | { 10 | Item1 = item1; 11 | Item2 = item2; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/java/thecsdev/chunkcopy/api/io/Tuple.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.api.io; 2 | 3 | public class Tuple 4 | { 5 | public final X Item1; 6 | public final Y Item2; 7 | 8 | public Tuple(X item1, Y item2) 9 | { 10 | Item1 = item1; 11 | Item2 = item2; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/resources/chunkcopy.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "thecsdev.chunkcopy.mixin", 5 | "compatibilityLevel": "JAVA_17", 6 | "mixins": ["WorldMixin"], 7 | "client": [], 8 | "server": [], 9 | "injectors": { "defaultRequire": 1 } 10 | } 11 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/resources/chunkcopy.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "thecsdev.chunkcopy.mixin", 5 | "compatibilityLevel": "JAVA_17", 6 | "mixins": ["WorldMixin"], 7 | "client": [], 8 | "server": [], 9 | "injectors": { "defaultRequire": 1 } 10 | } 11 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/resources/chunkcopy.client.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "thecsdev.chunkcopy.client.mixin", 5 | "compatibilityLevel": "JAVA_17", 6 | "mixins": [], 7 | "client": ["ClientChunkMapMixin", "MinecraftClientMixin"], 8 | "server": [], 9 | "injectors": { "defaultRequire": 1 } 10 | } 11 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/resources/chunkcopy.client.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "thecsdev.chunkcopy.client.mixin", 5 | "compatibilityLevel": "JAVA_17", 6 | "mixins": [], 7 | "client": ["ClientChunkMapMixin", "MinecraftClientMixin"], 8 | "server": [], 9 | "injectors": { "defaultRequire": 1 } 10 | } 11 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/gradle.properties: -------------------------------------------------------------------------------- 1 | # Done to increase the memory available to gradle. 2 | org.gradle.jvmargs=-Xmx1G 3 | 4 | # Fabric Properties 5 | # check these on https://fabricmc.net/develop 6 | minecraft_version=1.19 7 | yarn_mappings=1.19+build.1 8 | loader_version=0.14.7 9 | 10 | # Mod Properties 11 | mod_version = 2.4 12 | maven_group = thecsdev 13 | archives_base_name = chunkcopy 14 | 15 | # Dependencies 16 | fabric_version=0.55.3+1.19 17 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/gradle.properties: -------------------------------------------------------------------------------- 1 | # Done to increase the memory available to gradle. 2 | org.gradle.jvmargs=-Xmx1G 3 | 4 | # Fabric Properties 5 | # check these on https://fabricmc.net/develop 6 | minecraft_version=1.18.1 7 | yarn_mappings=1.18.1+build.22 8 | loader_version=0.13.2 9 | 10 | # Mod Properties 11 | mod_version = 2.4 12 | maven_group = thecsdev 13 | archives_base_name = chunkcopy 14 | 15 | # Dependencies 16 | fabric_version=0.46.4+1.18 17 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/java/thecsdev/chunkcopy/mixin/WorldMixin.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.mixin; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.gen.Invoker; 5 | 6 | import net.minecraft.entity.Entity; 7 | import net.minecraft.world.World; 8 | import net.minecraft.world.entity.EntityLookup; 9 | 10 | @Mixin(World.class) 11 | public interface WorldMixin 12 | { 13 | @Invoker("getEntityLookup") 14 | public EntityLookup getEntityLookup(); 15 | } 16 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/java/thecsdev/chunkcopy/mixin/WorldMixin.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.mixin; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.gen.Invoker; 5 | 6 | import net.minecraft.entity.Entity; 7 | import net.minecraft.world.World; 8 | import net.minecraft.world.entity.EntityLookup; 9 | 10 | @Mixin(World.class) 11 | public interface WorldMixin 12 | { 13 | @Invoker("getEntityLookup") 14 | public EntityLookup getEntityLookup(); 15 | } 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help the mod improve 4 | title: "[Mod version] Bug report title" 5 | labels: Bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/java/thecsdev/chunkcopy/client/gui/CCConfigScreen.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.client.gui; 2 | 3 | import net.minecraft.client.gui.screen.Screen; 4 | import net.minecraft.text.Text; 5 | 6 | public final class CCConfigScreen extends Screen 7 | { 8 | // ================================================== 9 | protected CCConfigScreen() { super(Text.translatable("chunkcopy.title")); } 10 | // -------------------------------------------------- 11 | @Override public boolean shouldPause() { return true; } 12 | @Override public boolean shouldCloseOnEsc() { return true; } 13 | // ================================================== 14 | } -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/java/thecsdev/chunkcopy/client/gui/CCConfigScreen.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.client.gui; 2 | 3 | import net.minecraft.client.gui.screen.Screen; 4 | import net.minecraft.text.TranslatableText; 5 | 6 | public final class CCConfigScreen extends Screen 7 | { 8 | // ================================================== 9 | protected CCConfigScreen() { super(new TranslatableText("chunkcopy.title")); } 10 | // -------------------------------------------------- 11 | @Override public boolean shouldPause() { return true; } 12 | @Override public boolean shouldCloseOnEsc() { return true; } 13 | // ================================================== 14 | } -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/java/thecsdev/chunkcopy/api/data/ChunkDataBlockID.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.api.data; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | import net.minecraft.util.Identifier; 9 | 10 | /** 11 | * The unique {@link Identifier} of the {@link ChunkDataBlock}. 12 | * This unique ID is used to keep track of and to differentiate 13 | * {@link ChunkDataBlock}s and their data. 14 | */ 15 | @Target(ElementType.TYPE) 16 | @Retention(RetentionPolicy.RUNTIME) 17 | public @interface ChunkDataBlockID 18 | { 19 | /** 20 | * Usually the mod ID. 21 | */ 22 | String namespace(); 23 | 24 | /** 25 | * Usually the name of the block. 26 | */ 27 | String path(); 28 | } 29 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/java/thecsdev/chunkcopy/api/data/ChunkDataBlockID.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.api.data; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | import net.minecraft.util.Identifier; 9 | 10 | /** 11 | * The unique {@link Identifier} of the {@link ChunkDataBlock}. 12 | * This unique ID is used to keep track of and to differentiate 13 | * {@link ChunkDataBlock}s and their data. 14 | */ 15 | @Target(ElementType.TYPE) 16 | @Retention(RetentionPolicy.RUNTIME) 17 | public @interface ChunkDataBlockID 18 | { 19 | /** 20 | * Usually the mod ID. 21 | */ 22 | String namespace(); 23 | 24 | /** 25 | * Usually the name of the block. 26 | */ 27 | String path(); 28 | } 29 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "chunkcopy", 4 | "version": "${version}", 5 | 6 | "name": "Chunk Copy", 7 | "description": "A Minecraft mod that copies worlds from multiplayer servers.", 8 | "authors": ["TheCSDev"], 9 | "contact": 10 | { 11 | "homepage": "https://github.com/TheCSDev", 12 | "sources": "https://github.com/TheCSDev/mc-chunk-copy", 13 | "issues": "https://github.com/TheCSDev/mc-chunk-copy/issues" 14 | }, 15 | 16 | "license": "LGPL-3.0-or-later", 17 | "icon": "assets/chunkcopy/icon.png", 18 | 19 | "environment": "*", 20 | "entrypoints": 21 | { 22 | "client": ["thecsdev.chunkcopy.client.ChunkCopyClient"], 23 | "server": [] 24 | }, 25 | "mixins": ["chunkcopy.mixins.json", "chunkcopy.client.mixins.json"], 26 | 27 | "depends": 28 | { 29 | "fabricloader": ">=0.14.6", 30 | "fabric": "*", 31 | "minecraft": "1.19.x", 32 | "java": ">=17" 33 | }, 34 | "suggests": 35 | { 36 | "another-mod": "*" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Chunk Copy 2 | Chunk Copy is a Fabric Minecraft mod used for downloading multiplayer worlds by copying their chunks and pasting them into singleplayer worlds. This mod adds a client-side command `/chunkcopy` that is used to copy and paste world chunks. All copied world chunks are stored in the `mods/chunkcopy` directory. 3 | 4 | - **Warning:** This mod does not feature a way to undo and redo changes made to chunks. Please be careful as any wrong moves made cannot be undone. 5 | 6 | You can download this mod and find more info about this mod over on [CurseForge](https://www.curseforge.com/minecraft/mc-mods/chunk-copy-fabric) and on [Modrinth](https://modrinth.com/mod/chunk-copy-fabric). 7 | 8 | ## 9 |

10 | CurseForge 11 | Modrinth 12 |

13 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "chunkcopy", 4 | "version": "${version}", 5 | 6 | "name": "Chunk Copy", 7 | "description": "A Minecraft mod that copies worlds from multiplayer servers.", 8 | "authors": ["TheCSDev"], 9 | "contact": 10 | { 11 | "homepage": "https://github.com/TheCSDev", 12 | "sources": "https://github.com/TheCSDev/mc-chunk-copy", 13 | "issues": "https://github.com/TheCSDev/mc-chunk-copy/issues" 14 | }, 15 | 16 | "license": "LGPL-3.0-or-later", 17 | "icon": "assets/chunkcopy/icon.png", 18 | 19 | "environment": "*", 20 | "entrypoints": 21 | { 22 | "client": ["thecsdev.chunkcopy.client.ChunkCopyClient"], 23 | "server": ["thecsdev.chunkcopy.server.ChunkCopyServer"] 24 | }, 25 | "mixins": ["chunkcopy.mixins.json", "chunkcopy.client.mixins.json"], 26 | 27 | "depends": 28 | { 29 | "fabricloader": ">=0.12.12", 30 | "fabric": "*", 31 | "minecraft": "1.18.x", 32 | "java": ">=17" 33 | }, 34 | "suggests": 35 | { 36 | "another-mod": "*" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/resources/assets/chunkcopy/lang/en_us.json: -------------------------------------------------------------------------------- 1 | { 2 | "chunkcopy.title": "Chunk Copy", 3 | 4 | "chunkcopy.feedback.copied": "[Chunk Copy] Copied %d chunks to '%s'.", 5 | "chunkcopy.feedback.pasted": "[Chunk Copy] Pasted %d chunks from '%s'.", 6 | "chunkcopy.feedback.filled": "[Chunk Copy] Filled %d chunks with '%s'.", 7 | "chunkcopy.feedback.autochunkcopy.start_copying": "[Chunk Copy] Now auto-copying chunks to '%s'.", 8 | "chunkcopy.feedback.autochunkcopy.start_pasting": "[Chunk Copy] Now auto-pasting chunks from '%s'.", 9 | "chunkcopy.feedback.autochunkcopy.stop": "[Chunk Copy] Auto chunk copy has been stopped.", 10 | 11 | "chunkcopy.feedback.require_singleplayer": "[Chunk Copy] You need to be in single-player in order to do this.", 12 | "chunkcopy.feedback.paste_file_not_found": "[Chunk Copy] Unable to paste chunks from '%s', file not found.", 13 | "chunkcopy.feedback.command_exception": "[Chunk Copy] An exception was thrown while executing the command: %s", 14 | 15 | "chunkcopy.feedback.syntax.copypaste": "[Chunk Copy] Syntax: / (copy/paste) [chunk_distance]" 16 | } -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/resources/assets/chunkcopy/lang/en_us.json: -------------------------------------------------------------------------------- 1 | { 2 | "chunkcopy.title": "Chunk Copy", 3 | 4 | "chunkcopy.feedback.copied": "[Chunk Copy] Copied %d chunks to '%s'.", 5 | "chunkcopy.feedback.pasted": "[Chunk Copy] Pasted %d chunks from '%s'.", 6 | "chunkcopy.feedback.filled": "[Chunk Copy] Filled %d chunks with '%s'.", 7 | "chunkcopy.feedback.autochunkcopy.start_copying": "[Chunk Copy] Now auto-copying chunks to '%s'.", 8 | "chunkcopy.feedback.autochunkcopy.start_pasting": "[Chunk Copy] Now auto-pasting chunks from '%s'.", 9 | "chunkcopy.feedback.autochunkcopy.stop": "[Chunk Copy] Auto chunk copy has been stopped.", 10 | 11 | "chunkcopy.feedback.require_singleplayer": "[Chunk Copy] You need to be in single-player in order to do this.", 12 | "chunkcopy.feedback.paste_file_not_found": "[Chunk Copy] Unable to paste chunks from '%s', file not found.", 13 | "chunkcopy.feedback.command_exception": "[Chunk Copy] An exception was thrown while executing the command: %s", 14 | 15 | "chunkcopy.feedback.syntax.copypaste": "[Chunk Copy] Syntax: / (copy/paste) [chunk_distance]" 16 | } -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/java/thecsdev/chunkcopy/client/mixin/MinecraftClientMixin.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.client.mixin; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.injection.At; 5 | import org.spongepowered.asm.mixin.injection.Inject; 6 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 7 | 8 | import net.minecraft.client.MinecraftClient; 9 | import net.minecraft.client.gui.screen.Screen; 10 | import thecsdev.chunkcopy.api.AutoChunkCopy; 11 | 12 | @Mixin(MinecraftClient.class) 13 | public abstract class MinecraftClientMixin 14 | { 15 | // ================================================== 16 | //@Accessor("currentScreen") public abstract Screen getCurrentScreen(); 17 | //@Accessor("isConnectedToServer") public abstract boolean isConnectedToServer(); 18 | // -------------------------------------------------- 19 | /** 20 | * Stop {@link AutoChunkCopy} when disconnecting. 21 | */ 22 | @Inject(method = "disconnect(Lnet/minecraft/client/gui/screen/Screen;)V", at = @At("RETURN")) 23 | public void disconnect(Screen screen, CallbackInfo callback) 24 | { 25 | AutoChunkCopy.stop(); 26 | } 27 | // ================================================== 28 | } 29 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/java/thecsdev/chunkcopy/client/mixin/MinecraftClientMixin.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.client.mixin; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.injection.At; 5 | import org.spongepowered.asm.mixin.injection.Inject; 6 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 7 | 8 | import net.minecraft.client.MinecraftClient; 9 | import net.minecraft.client.gui.screen.Screen; 10 | import thecsdev.chunkcopy.api.AutoChunkCopy; 11 | 12 | @Mixin(MinecraftClient.class) 13 | public abstract class MinecraftClientMixin 14 | { 15 | // ================================================== 16 | //@Accessor("currentScreen") public abstract Screen getCurrentScreen(); 17 | //@Accessor("isConnectedToServer") public abstract boolean isConnectedToServer(); 18 | // -------------------------------------------------- 19 | /** 20 | * Stop {@link AutoChunkCopy} when disconnecting. 21 | */ 22 | @Inject(method = "disconnect(Lnet/minecraft/client/gui/screen/Screen;)V", at = @At("RETURN")) 23 | public void disconnect(Screen screen, CallbackInfo callback) 24 | { 25 | AutoChunkCopy.stop(); 26 | } 27 | // ================================================== 28 | } 29 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/resources/assets/chunkcopy/lang/ru_ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "chunkcopy.title": "Chunk Copy", 3 | 4 | "chunkcopy.feedback.copied": "[Chunk Copy] Данные чанков скопированы в папку \"%s\".", 5 | "chunkcopy.feedback.pasted": "[Chunk Copy] Данные чанков вставлены из папки \"%s\".", 6 | "chunkcopy.feedback.filled": "[Chunk Copy] Чанки заполнены блоком \"%s\".", 7 | "chunkcopy.feedback.autochunkcopy.start_copying": "[Chunk Copy] Запущено автоматическое копирование данных чанков в папку \"%s\".", 8 | "chunkcopy.feedback.autochunkcopy.start_pasting": "[Chunk Copy] Запущена автоматическая вставка данных чанков из папки \"%s\".", 9 | "chunkcopy.feedback.autochunkcopy.stop": "[Chunk Copy] Автоматическое копирование и вставка данных чанков завершено.", 10 | 11 | "chunkcopy.feedback.require_singleplayer": "[Chunk Copy] Для выполнения операции необходимо находиться в одиночной игре.", 12 | "chunkcopy.feedback.paste_file_not_found": "[Chunk Copy] Не удалось вставить данные чанков из \"%s\": данные не обнаружены.", 13 | "chunkcopy.feedback.command_exception": "[Chunk Copy] При выполнении команды произошла ошибка: %s", 14 | 15 | "chunkcopy.feedback.syntax.copypaste": "[Chunk Copy] Формат: /<команда> (copy/paste) <название> [радиус_в_чанках]" 16 | } 17 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/resources/assets/chunkcopy/lang/ru_ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "chunkcopy.title": "Chunk Copy", 3 | 4 | "chunkcopy.feedback.copied": "[Chunk Copy] Данные чанков скопированы в папку \"%s\".", 5 | "chunkcopy.feedback.pasted": "[Chunk Copy] Данные чанков вставлены из папки \"%s\".", 6 | "chunkcopy.feedback.filled": "[Chunk Copy] Чанки заполнены блоком \"%s\".", 7 | "chunkcopy.feedback.autochunkcopy.start_copying": "[Chunk Copy] Запущено автоматическое копирование данных чанков в папку \"%s\".", 8 | "chunkcopy.feedback.autochunkcopy.start_pasting": "[Chunk Copy] Запущена автоматическая вставка данных чанков из папки \"%s\".", 9 | "chunkcopy.feedback.autochunkcopy.stop": "[Chunk Copy] Автоматическое копирование и вставка данных чанков завершено.", 10 | 11 | "chunkcopy.feedback.require_singleplayer": "[Chunk Copy] Для выполнения операции необходимо находиться в одиночной игре.", 12 | "chunkcopy.feedback.paste_file_not_found": "[Chunk Copy] Не удалось вставить данные чанков из \"%s\": данные не обнаружены.", 13 | "chunkcopy.feedback.command_exception": "[Chunk Copy] При выполнении команды произошла ошибка: %s", 14 | 15 | "chunkcopy.feedback.syntax.copypaste": "[Chunk Copy] Формат: /<команда> (copy/paste) <название> [радиус_в_чанках]" 16 | } 17 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/java/thecsdev/chunkcopy/client/ChunkCopyClient.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.client; 2 | 3 | import org.jetbrains.annotations.Nullable; 4 | 5 | import net.fabricmc.api.ClientModInitializer; 6 | import net.fabricmc.fabric.api.client.command.v1.ClientCommandManager; 7 | import thecsdev.chunkcopy.ChunkCopy; 8 | import thecsdev.chunkcopy.client.command.ChunkCopyClientCommand; 9 | import thecsdev.chunkcopy.command.ChunkCopyCommand; 10 | 11 | /** 12 | * The {@link ChunkCopy} initializer for clients. 13 | */ 14 | public final class ChunkCopyClient extends ChunkCopy implements ClientModInitializer 15 | { 16 | // ================================================== 17 | /** 18 | * The client-side version of the {@link ChunkCopyCommand}. 19 | */ 20 | private ChunkCopyClientCommand Command = null; 21 | // ================================================== 22 | @Override 23 | public void onInitializeClient() 24 | { 25 | //register the command 26 | Command = new ChunkCopyClientCommand(); 27 | Command.register(ClientCommandManager.DISPATCHER); 28 | } 29 | // -------------------------------------------------- 30 | @Override 31 | public @Nullable ChunkCopyCommand getCommand() { return Command; } 32 | // ================================================== 33 | } 34 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/java/thecsdev/chunkcopy/server/ChunkCopyServer.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.server; 2 | 3 | import org.jetbrains.annotations.Nullable; 4 | 5 | import net.fabricmc.api.DedicatedServerModInitializer; 6 | import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback; 7 | import thecsdev.chunkcopy.ChunkCopy; 8 | import thecsdev.chunkcopy.command.ChunkCopyCommand; 9 | import thecsdev.chunkcopy.server.command.ChunkCopyServerCommand; 10 | 11 | /** 12 | * The {@link ChunkCopy} initializer for dedicated servers. 13 | */ 14 | public final class ChunkCopyServer extends ChunkCopy implements DedicatedServerModInitializer 15 | { 16 | // ================================================== 17 | /** 18 | * The server-side version of the {@link ChunkCopyCommand}. 19 | */ 20 | private ChunkCopyServerCommand Command = null; 21 | // ================================================== 22 | @Override 23 | public void onInitializeServer() 24 | { 25 | //register the command 26 | CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> 27 | { 28 | Command = new ChunkCopyServerCommand(); 29 | Command.register(dispatcher); 30 | }); 31 | } 32 | // -------------------------------------------------- 33 | @Override 34 | public @Nullable ChunkCopyCommand getCommand() { return Command; } 35 | // ================================================== 36 | } 37 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/java/thecsdev/chunkcopy/server/ChunkCopyServer.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.server; 2 | 3 | import org.jetbrains.annotations.Nullable; 4 | 5 | import net.fabricmc.api.DedicatedServerModInitializer; 6 | import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; 7 | import thecsdev.chunkcopy.ChunkCopy; 8 | import thecsdev.chunkcopy.command.ChunkCopyCommand; 9 | import thecsdev.chunkcopy.server.command.ChunkCopyServerCommand; 10 | 11 | /** 12 | * The {@link ChunkCopy} initializer for dedicated servers. 13 | */ 14 | public final class ChunkCopyServer extends ChunkCopy implements DedicatedServerModInitializer 15 | { 16 | // ================================================== 17 | /** 18 | * The server-side version of the {@link ChunkCopyCommand}. 19 | */ 20 | private ChunkCopyServerCommand Command = null; 21 | // ================================================== 22 | @Override 23 | public void onInitializeServer() 24 | { 25 | //register the command 26 | CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, enviroment) -> 27 | { 28 | Command = new ChunkCopyServerCommand(); 29 | Command.register(dispatcher, registryAccess); 30 | }); 31 | } 32 | // -------------------------------------------------- 33 | @Override 34 | public @Nullable ChunkCopyCommand getCommand() { return Command; } 35 | // ================================================== 36 | } 37 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/java/thecsdev/chunkcopy/client/mixin/ClientChunkMapMixin.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.client.mixin; 2 | 3 | import org.jetbrains.annotations.Nullable; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.injection.At; 6 | import org.spongepowered.asm.mixin.injection.Inject; 7 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 8 | 9 | import net.minecraft.util.math.ChunkPos; 10 | import net.minecraft.world.World; 11 | import net.minecraft.world.chunk.WorldChunk; 12 | import thecsdev.chunkcopy.api.AutoChunkCopy; 13 | import thecsdev.chunkcopy.api.ChunkCopyAPI; 14 | 15 | @Mixin(targets = "net/minecraft/client/world/ClientChunkManager$ClientChunkMap") 16 | public abstract class ClientChunkMapMixin 17 | { 18 | // ================================================== 19 | @Inject(method = "set", at = @At("TAIL")) 20 | protected void set(int index, @Nullable WorldChunk chunk, CallbackInfo callback) 21 | { 22 | //check if auto-copy is copying 23 | if(!AutoChunkCopy.isCopying()) return; 24 | 25 | //ignore null chunks 26 | if(chunk == null) return; 27 | 28 | //save chunk 29 | try 30 | { 31 | World world = (World) chunk.getWorld(); 32 | ChunkPos chunkPos = chunk.getPos(); 33 | String fileName = AutoChunkCopy.getFileName(); 34 | 35 | ChunkCopyAPI.saveChunkDataIO(world, chunkPos, fileName); 36 | } 37 | catch (Throwable e) {} 38 | } 39 | // ================================================== 40 | } 41 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/java/thecsdev/chunkcopy/client/mixin/ClientChunkMapMixin.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.client.mixin; 2 | 3 | import org.jetbrains.annotations.Nullable; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.injection.At; 6 | import org.spongepowered.asm.mixin.injection.Inject; 7 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 8 | 9 | import net.minecraft.util.math.ChunkPos; 10 | import net.minecraft.world.World; 11 | import net.minecraft.world.chunk.WorldChunk; 12 | import thecsdev.chunkcopy.api.AutoChunkCopy; 13 | import thecsdev.chunkcopy.api.ChunkCopyAPI; 14 | 15 | @Mixin(targets = "net/minecraft/client/world/ClientChunkManager$ClientChunkMap") 16 | public abstract class ClientChunkMapMixin 17 | { 18 | // ================================================== 19 | @Inject(method = "set", at = @At("TAIL")) 20 | protected void set(int index, @Nullable WorldChunk chunk, CallbackInfo callback) 21 | { 22 | //check if auto-copy is running 23 | if(!AutoChunkCopy.isRunning()) return; 24 | 25 | //ignore null chunks 26 | if(chunk == null) return; 27 | 28 | //save chunk 29 | try 30 | { 31 | World world = (World) chunk.getWorld(); 32 | ChunkPos chunkPos = chunk.getPos(); 33 | String fileName = AutoChunkCopy.getFileName(); 34 | 35 | ChunkCopyAPI.saveChunkDataIO(world, chunkPos, fileName); 36 | } 37 | catch (Throwable e) {} 38 | } 39 | // ================================================== 40 | } 41 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/java/thecsdev/chunkcopy/client/ChunkCopyClient.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.client; 2 | 3 | import org.jetbrains.annotations.Nullable; 4 | 5 | import net.fabricmc.api.ClientModInitializer; 6 | import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager; 7 | import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; 8 | import thecsdev.chunkcopy.ChunkCopy; 9 | import thecsdev.chunkcopy.client.command.ChunkCopyClientCommand; 10 | import thecsdev.chunkcopy.command.ChunkCopyCommand; 11 | 12 | /** 13 | * The {@link ChunkCopy} initializer for clients. 14 | */ 15 | public final class ChunkCopyClient extends ChunkCopy implements ClientModInitializer 16 | { 17 | // ================================================== 18 | /** 19 | * The client-side version of the {@link ChunkCopyCommand}. 20 | */ 21 | private ChunkCopyClientCommand Command = null; 22 | // ================================================== 23 | @Override 24 | public void onInitializeClient() 25 | { 26 | //register the command 27 | ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> 28 | { 29 | Command = new ChunkCopyClientCommand(); 30 | Command.register(ClientCommandManager.getActiveDispatcher(), registryAccess); 31 | }); 32 | } 33 | // -------------------------------------------------- 34 | @Override 35 | public @Nullable ChunkCopyCommand getCommand() { return Command; } 36 | // ================================================== 37 | } 38 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/java/thecsdev/chunkcopy/api/data/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Important: Please wrap API calls to {@link ChunkDataBlock}s in a 3 | * {@link MinecraftServer#execute(Runnable)} to avoid concurrency issues 4 | * (crashes) that occur while copying and pasting chunk data 5 | * using {@link ChunkDataBlock}s.
6 | *
7 | * Basically, Minecraft is a multi-threaded game. While copying and pasting chunk data, 8 | * it is extremely likely that another Minecraft's thread will attempt to access 9 | * {@link PalettedContainer}s, blocks, entities, and other places where block and entity data are stored, 10 | * while the {@link ChunkDataBlock}s are copying and pasting chunks. This always results in concurrent 11 | * modification problems, which cause the game to crash every time.
12 | *
13 | * To resolve this issue, simply use the {@link MinecraftServer#execute(Runnable)} method 14 | * provided by the game itself to avoid such issues.
15 | *
16 | * Example:
17 | *
18 |  * {@code
19 |  * ChunkDataBlock chunkData = ...;
20 |  * ServerWorld    world     = ...;
21 |  * ChunkPos       chunkPos  = ...;
22 |  * world.getServer().execute(() -> chunkData.pasteChunkData(world, chunkPos));
23 |  * }
24 |  * 
25 | * The {@link ChunkCopyAPI} and {@link ChunkData} already take care of this for you, so there is 26 | * no need to use {@link MinecraftServer#execute(Runnable)} when calling those methods.
27 | *
28 | */ 29 | package thecsdev.chunkcopy.api.data; -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/java/thecsdev/chunkcopy/api/data/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Important: Please wrap API calls to {@link ChunkDataBlock}s in a 3 | * {@link MinecraftServer#execute(Runnable)} to avoid concurrency issues 4 | * (crashes) that occur while copying and pasting chunk data 5 | * using {@link ChunkDataBlock}s.
6 | *
7 | * Basically, Minecraft is a multi-threaded game. While copying and pasting chunk data, 8 | * it is extremely likely that another Minecraft's thread will attempt to access 9 | * {@link PalettedContainer}s, blocks, entities, and other places where block and entity data are stored, 10 | * while the {@link ChunkDataBlock}s are copying and pasting chunks. This always results in concurrent 11 | * modification problems, which cause the game to crash every time.
12 | *
13 | * To resolve this issue, simply use the {@link MinecraftServer#execute(Runnable)} method 14 | * provided by the game itself to avoid such issues.
15 | *
16 | * Example:
17 | *
18 |  * {@code
19 |  * ChunkDataBlock chunkData = ...;
20 |  * ServerWorld    world     = ...;
21 |  * ChunkPos       chunkPos  = ...;
22 |  * world.getServer().execute(() -> chunkData.pasteChunkData(world, chunkPos));
23 |  * }
24 |  * 
25 | * The {@link ChunkCopyAPI} and {@link ChunkData} already take care of this for you, so there is 26 | * no need to use {@link MinecraftServer#execute(Runnable)} when calling those methods.
27 | *
28 | */ 29 | package thecsdev.chunkcopy.api.data; -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/java/thecsdev/chunkcopy/api/config/ConfigKey.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.api.config; 2 | 3 | import com.mojang.brigadier.arguments.ArgumentType; 4 | 5 | import net.minecraft.util.Identifier; 6 | 7 | /** 8 | * A property key for the {@link ChunkCopyConfig}.
9 | * Please put any custom {@link ConfigKey}s in {@link ChunkCopyConfig#KEYS}, 10 | * otherwise they might not work properly. 11 | */ 12 | public /*non final*/ class ConfigKey 13 | { 14 | // ================================================== 15 | public final Identifier keyName; 16 | public final ArgumentType argumentType; 17 | // ================================================== 18 | public ConfigKey(String namespace, String path, ArgumentType argType) 19 | { 20 | this(new Identifier(namespace, path), argType); 21 | } 22 | 23 | public ConfigKey(Identifier name, ArgumentType argType) 24 | { 25 | this.keyName = name; 26 | this.argumentType = argType; 27 | } 28 | // -------------------------------------------------- 29 | @Override 30 | public final int hashCode() 31 | { 32 | int a = keyName.toString().hashCode(); 33 | int b = argumentType.toString().hashCode(); 34 | return a + b; 35 | } 36 | // -------------------------------------------------- 37 | /** 38 | * Override this to define how <T> should 39 | * be converted to {@link String}. 40 | * @param value The object being converted to string. 41 | */ 42 | public String valueToString(T value) { return value.toString(); } 43 | // ================================================== 44 | } -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/java/thecsdev/chunkcopy/api/config/ConfigKey.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.api.config; 2 | 3 | import com.mojang.brigadier.arguments.ArgumentType; 4 | 5 | import net.minecraft.util.Identifier; 6 | 7 | /** 8 | * A property key for the {@link ChunkCopyConfig}.
9 | * Please put any custom {@link ConfigKey}s in {@link ChunkCopyConfig#KEYS}, 10 | * otherwise they might not work properly. 11 | */ 12 | public /*non final*/ class ConfigKey 13 | { 14 | // ================================================== 15 | public final Identifier keyName; 16 | public final ArgumentType argumentType; 17 | // ================================================== 18 | public ConfigKey(String namespace, String path, ArgumentType argType) 19 | { 20 | this(new Identifier(namespace, path), argType); 21 | } 22 | 23 | public ConfigKey(Identifier name, ArgumentType argType) 24 | { 25 | this.keyName = name; 26 | this.argumentType = argType; 27 | } 28 | // -------------------------------------------------- 29 | @Override 30 | public final int hashCode() 31 | { 32 | int a = keyName.toString().hashCode(); 33 | int b = argumentType.toString().hashCode(); 34 | return a + b; 35 | } 36 | // -------------------------------------------------- 37 | /** 38 | * Override this to define how <T> should 39 | * be converted to {@link String}. 40 | * @param value The object being converted to string. 41 | */ 42 | public String valueToString(T value) { return value.toString(); } 43 | // ================================================== 44 | } -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/java/thecsdev/chunkcopy/command/argument/ConfigValueArgumentType.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.command.argument; 2 | 3 | import java.util.concurrent.CompletableFuture; 4 | 5 | import com.mojang.brigadier.StringReader; 6 | import com.mojang.brigadier.arguments.ArgumentType; 7 | import com.mojang.brigadier.context.CommandContext; 8 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 9 | import com.mojang.brigadier.suggestion.Suggestions; 10 | import com.mojang.brigadier.suggestion.SuggestionsBuilder; 11 | 12 | import net.minecraft.util.Identifier; 13 | import thecsdev.chunkcopy.api.config.ChunkCopyConfig; 14 | import thecsdev.chunkcopy.api.config.ConfigKey; 15 | 16 | /** 17 | * An {@link ArgumentType}<{@link String}> that will suggest picking 18 | * appropriate values for {@link ConfigKeyArgumentType}. 19 | */ 20 | public final class ConfigValueArgumentType implements ArgumentType 21 | { 22 | // ================================================== 23 | protected ConfigValueArgumentType() {} 24 | public static ConfigValueArgumentType configStringValue() { return new ConfigValueArgumentType(); } 25 | // ================================================== 26 | @Override 27 | public String parse(StringReader reader) throws CommandSyntaxException { return reader.readString(); } 28 | // -------------------------------------------------- 29 | @Override 30 | public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) 31 | { 32 | try 33 | { 34 | Identifier keyId = context.getArgument("key", Identifier.class); 35 | if(keyId == null) throw new Exception(); 36 | 37 | ConfigKey key = ChunkCopyConfig.getKeyByName(keyId); 38 | return key.argumentType.listSuggestions(context, builder); 39 | } 40 | catch(Exception e) { return ArgumentType.super.listSuggestions(context, builder); } 41 | } 42 | // ================================================== 43 | } 44 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/java/thecsdev/chunkcopy/command/argument/ConfigValueArgumentType.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.command.argument; 2 | 3 | import java.util.concurrent.CompletableFuture; 4 | 5 | import com.mojang.brigadier.StringReader; 6 | import com.mojang.brigadier.arguments.ArgumentType; 7 | import com.mojang.brigadier.context.CommandContext; 8 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 9 | import com.mojang.brigadier.suggestion.Suggestions; 10 | import com.mojang.brigadier.suggestion.SuggestionsBuilder; 11 | 12 | import net.minecraft.util.Identifier; 13 | import thecsdev.chunkcopy.api.config.ChunkCopyConfig; 14 | import thecsdev.chunkcopy.api.config.ConfigKey; 15 | 16 | /** 17 | * An {@link ArgumentType}<{@link String}> that will suggest picking 18 | * appropriate values for {@link ConfigKeyArgumentType}. 19 | */ 20 | @Deprecated 21 | public final class ConfigValueArgumentType implements ArgumentType 22 | { 23 | // ================================================== 24 | protected ConfigValueArgumentType() {} 25 | public static ConfigValueArgumentType configStringValue() { return new ConfigValueArgumentType(); } 26 | // ================================================== 27 | @Override 28 | public String parse(StringReader reader) throws CommandSyntaxException { return reader.readString(); } 29 | // -------------------------------------------------- 30 | @Override 31 | public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) 32 | { 33 | try 34 | { 35 | Identifier keyId = context.getArgument("key", Identifier.class); 36 | if(keyId == null) throw new Exception(); 37 | 38 | ConfigKey key = ChunkCopyConfig.getKeyByName(keyId); 39 | return key.argumentType.listSuggestions(context, builder); 40 | } 41 | catch(Exception e) { return ArgumentType.super.listSuggestions(context, builder); } 42 | } 43 | // ================================================== 44 | } 45 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/java/thecsdev/chunkcopy/command/argument/ConfigKeyArgumentType.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.command.argument; 2 | 3 | import java.util.concurrent.CompletableFuture; 4 | 5 | import com.mojang.brigadier.StringReader; 6 | import com.mojang.brigadier.arguments.ArgumentType; 7 | import com.mojang.brigadier.context.CommandContext; 8 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 9 | import com.mojang.brigadier.suggestion.Suggestions; 10 | import com.mojang.brigadier.suggestion.SuggestionsBuilder; 11 | 12 | import net.minecraft.command.argument.IdentifierArgumentType; 13 | import net.minecraft.util.Identifier; 14 | import thecsdev.chunkcopy.api.config.ChunkCopyConfig; 15 | import thecsdev.chunkcopy.api.config.ConfigKey; 16 | 17 | /** 18 | * An {@link ArgumentType}<{@link Identifier}> that will suggest picking 19 | * a property from a list of {@link ChunkCopyConfig#KEYS}. 20 | */ 21 | public final class ConfigKeyArgumentType implements ArgumentType 22 | { 23 | // ================================================== 24 | private final static IdentifierArgumentType IAT = IdentifierArgumentType.identifier(); 25 | // ================================================== 26 | protected ConfigKeyArgumentType() {} 27 | public static ConfigKeyArgumentType configKeyId() { return new ConfigKeyArgumentType(); } 28 | // ================================================== 29 | @Override 30 | public Identifier parse(StringReader reader) throws CommandSyntaxException { return IAT.parse(reader); } 31 | // -------------------------------------------------- 32 | @Override 33 | public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) 34 | { 35 | //suggest properties 36 | for (ConfigKey configKey : ChunkCopyConfig.KEYS) 37 | builder.suggest(configKey.keyName.toString()); 38 | 39 | //return build 40 | return builder.buildFuture(); 41 | } 42 | // ================================================== 43 | } 44 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/java/thecsdev/chunkcopy/command/argument/ConfigKeyArgumentType.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.command.argument; 2 | 3 | import java.util.concurrent.CompletableFuture; 4 | 5 | import com.mojang.brigadier.StringReader; 6 | import com.mojang.brigadier.arguments.ArgumentType; 7 | import com.mojang.brigadier.context.CommandContext; 8 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 9 | import com.mojang.brigadier.suggestion.Suggestions; 10 | import com.mojang.brigadier.suggestion.SuggestionsBuilder; 11 | 12 | import net.minecraft.command.argument.IdentifierArgumentType; 13 | import net.minecraft.util.Identifier; 14 | import thecsdev.chunkcopy.api.config.ChunkCopyConfig; 15 | import thecsdev.chunkcopy.api.config.ConfigKey; 16 | 17 | /** 18 | * An {@link ArgumentType}<{@link Identifier}> that will suggest picking 19 | * a property from a list of {@link ChunkCopyConfig#KEYS}. 20 | */ 21 | @Deprecated 22 | public final class ConfigKeyArgumentType implements ArgumentType 23 | { 24 | // ================================================== 25 | private final static IdentifierArgumentType IAT = IdentifierArgumentType.identifier(); 26 | // ================================================== 27 | protected ConfigKeyArgumentType() {} 28 | public static ConfigKeyArgumentType configKeyId() { return new ConfigKeyArgumentType(); } 29 | // ================================================== 30 | @Override 31 | public Identifier parse(StringReader reader) throws CommandSyntaxException { return IAT.parse(reader); } 32 | // -------------------------------------------------- 33 | @Override 34 | public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) 35 | { 36 | //suggest properties 37 | for (ConfigKey configKey : ChunkCopyConfig.KEYS) 38 | builder.suggest(configKey.keyName.toString()); 39 | 40 | //return build 41 | return builder.buildFuture(); 42 | } 43 | // ================================================== 44 | } 45 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'fabric-loom' version '0.11-SNAPSHOT' 3 | id 'maven-publish' 4 | } 5 | 6 | sourceCompatibility = JavaVersion.VERSION_17 7 | targetCompatibility = JavaVersion.VERSION_17 8 | 9 | archivesBaseName = project.archives_base_name 10 | version = project.mod_version 11 | group = project.maven_group 12 | 13 | repositories { 14 | // Add repositories to retrieve artifacts from in here. 15 | // You should only use this when depending on other mods because 16 | // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. 17 | // See https://docs.gradle.org/current/userguide/declaring_repositories.html 18 | // for more information about repositories. 19 | } 20 | 21 | dependencies { 22 | // To change the versions see the gradle.properties file 23 | minecraft "com.mojang:minecraft:${project.minecraft_version}" 24 | mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" 25 | modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" 26 | 27 | // Fabric API. This is technically optional, but you probably want it anyway. 28 | modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" 29 | } 30 | 31 | processResources { 32 | inputs.property "version", project.version 33 | 34 | filesMatching("fabric.mod.json") { 35 | expand "version": project.version 36 | } 37 | } 38 | 39 | tasks.withType(JavaCompile).configureEach { 40 | // Minecraft 1.18 (1.18-pre2) upwards uses Java 17. 41 | it.options.release = 17 42 | } 43 | 44 | java { 45 | // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task 46 | // if it is present. 47 | // If you remove this line, sources will not be generated. 48 | withSourcesJar() 49 | } 50 | 51 | jar 52 | { 53 | from("LICENSE") { rename { "LICENSE" } } 54 | } 55 | 56 | // configure the maven publication 57 | publishing { 58 | publications { 59 | mavenJava(MavenPublication) { 60 | from components.java 61 | } 62 | } 63 | 64 | // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. 65 | repositories { 66 | // Add repositories to publish to here. 67 | // Notice: This block does NOT have the same function as the block in the top level. 68 | // The repositories here will be used for publishing your artifact, not for 69 | // retrieving dependencies. 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'fabric-loom' version '0.11-SNAPSHOT' 3 | id 'maven-publish' 4 | } 5 | 6 | sourceCompatibility = JavaVersion.VERSION_17 7 | targetCompatibility = JavaVersion.VERSION_17 8 | 9 | archivesBaseName = project.archives_base_name 10 | version = project.mod_version 11 | group = project.maven_group 12 | 13 | repositories { 14 | // Add repositories to retrieve artifacts from in here. 15 | // You should only use this when depending on other mods because 16 | // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. 17 | // See https://docs.gradle.org/current/userguide/declaring_repositories.html 18 | // for more information about repositories. 19 | } 20 | 21 | dependencies { 22 | // To change the versions see the gradle.properties file 23 | minecraft "com.mojang:minecraft:${project.minecraft_version}" 24 | mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" 25 | modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" 26 | 27 | // Fabric API. This is technically optional, but you probably want it anyway. 28 | modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" 29 | } 30 | 31 | processResources { 32 | inputs.property "version", project.version 33 | 34 | filesMatching("fabric.mod.json") { 35 | expand "version": project.version 36 | } 37 | } 38 | 39 | tasks.withType(JavaCompile).configureEach { 40 | // Minecraft 1.18 (1.18-pre2) upwards uses Java 17. 41 | it.options.release = 17 42 | } 43 | 44 | java { 45 | // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task 46 | // if it is present. 47 | // If you remove this line, sources will not be generated. 48 | withSourcesJar() 49 | } 50 | 51 | jar 52 | { 53 | from("LICENSE") { rename { "LICENSE" } } 54 | } 55 | 56 | // configure the maven publication 57 | publishing { 58 | publications { 59 | mavenJava(MavenPublication) { 60 | from components.java 61 | } 62 | } 63 | 64 | // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. 65 | repositories { 66 | // Add repositories to publish to here. 67 | // Notice: This block does NOT have the same function as the block in the top level. 68 | // The repositories here will be used for publishing your artifact, not for 69 | // retrieving dependencies. 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # -------------------- Eclipse IDE ------------------- 2 | .metadata 3 | bin/ 4 | tmp/ 5 | *.tmp 6 | *.bak 7 | *.swp 8 | *~.nib 9 | local.properties 10 | .settings/ 11 | .loadpath 12 | .recommenders 13 | 14 | # External tool builders 15 | .externalToolBuilders/ 16 | 17 | # Locally stored "Eclipse launch configurations" 18 | *.launch 19 | 20 | # PyDev specific (Python IDE for Eclipse) 21 | *.pydevproject 22 | 23 | # CDT-specific (C/C++ Development Tooling) 24 | .cproject 25 | 26 | # CDT- autotools 27 | .autotools 28 | 29 | # Java annotation processor (APT) 30 | .factorypath 31 | 32 | # PDT-specific (PHP Development Tools) 33 | .buildpath 34 | 35 | # sbteclipse plugin 36 | .target 37 | 38 | # Tern plugin 39 | .tern-project 40 | 41 | # TeXlipse plugin 42 | .texlipse 43 | 44 | # STS (Spring Tool Suite) 45 | .springBeans 46 | 47 | # Code Recommenders 48 | .recommenders/ 49 | 50 | # Annotation Processing 51 | .apt_generated/ 52 | .apt_generated_test/ 53 | 54 | # Scala IDE specific (Scala & Java development for Eclipse) 55 | .cache-main 56 | .scala_dependencies 57 | .worksheet 58 | 59 | # Uncomment this line if you wish to ignore the project description file. 60 | # Typically, this file would be tracked if it contains build/dependency configurations: 61 | #.project 62 | 63 | # ----------------------- Java ----------------------- 64 | # Compiled class file 65 | *.class 66 | 67 | # Log file 68 | *.log 69 | 70 | # BlueJ files 71 | *.ctxt 72 | 73 | # Mobile Tools for Java (J2ME) 74 | .mtj.tmp/ 75 | 76 | # Package Files # 77 | *.jar 78 | *.war 79 | *.nar 80 | *.ear 81 | *.zip 82 | *.tar.gz 83 | *.rar 84 | 85 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 86 | hs_err_pid* 87 | /.gradle/ 88 | /build/ 89 | 90 | # ----------------------- Gradle ----------------------- 91 | .gradle 92 | **/build/ 93 | !src/**/build/ 94 | 95 | # Ignore Gradle GUI config 96 | gradle-app.setting 97 | 98 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 99 | !gradle-wrapper.jar 100 | 101 | # Avoid ignore Gradle wrappper properties 102 | !gradle-wrapper.properties 103 | 104 | # Cache of project 105 | .gradletasknamecache 106 | 107 | # Eclipse Gradle plugin generated files 108 | # Eclipse Core 109 | .project 110 | # JDT-specific (Eclipse Java Development Tools) 111 | .classpath 112 | 113 | # ----------------------- Fabric ----------------------- 114 | run/ 115 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/java/thecsdev/chunkcopy/api/AutoChunkCopy.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.api; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | import thecsdev.chunkcopy.ChunkCopy; 7 | 8 | /** 9 | * This class holds the information about the 10 | * status of auto-copying chunks. 11 | */ 12 | public class AutoChunkCopy 13 | { 14 | // ================================================== 15 | public enum ACCMode { Copying, Pasting } 16 | 17 | @Nullable 18 | private static String FileName = null; 19 | private static ACCMode AutoChunkCopyMode = null; 20 | // ================================================== 21 | /** 22 | * Returns the fileName of where the chunks are 23 | * currently being auto copied or pasted. Returns null if 24 | * {@link AutoChunkCopy} is currently not running. 25 | */ 26 | @Nullable 27 | public static String getFileName() { return AutoChunkCopyMode != null ? FileName : null; } 28 | 29 | /** 30 | * Returns true if auto-copying is currently running and doing anything. 31 | */ 32 | public static boolean isRunning() { return validate() && AutoChunkCopyMode != null && !StringUtils.isAllBlank(FileName); } 33 | public static boolean isCopying() { return isRunning() && AutoChunkCopyMode == ACCMode.Copying; } 34 | public static boolean isPasting() { return isRunning() && AutoChunkCopyMode == ACCMode.Pasting; } 35 | // -------------------------------------------------- 36 | public static boolean start(String fileName, ACCMode mode) 37 | { 38 | //validate instance 39 | if(!validate()) return false; 40 | 41 | //validate fileName with regex 42 | if(!fileName.matches("^[\\w\\-. ]+$")) return false; 43 | 44 | //start 45 | ChunkCopy.LOGGER.info("Started AutoChunkCopy; Mode: '" + mode.name() + "'; File: '" + fileName + "';"); 46 | AutoChunkCopyMode = mode; 47 | FileName = fileName; 48 | return true; 49 | } 50 | 51 | public static void stop() 52 | { 53 | //log if running 54 | if(isRunning()) 55 | ChunkCopy.LOGGER.info("Stopped AutoChunkCopy; Mode: '" + AutoChunkCopyMode.name() + "'; File: '" + FileName + "';"); 56 | 57 | //stop 58 | AutoChunkCopyMode = null; 59 | FileName = null; 60 | } 61 | // ================================================== 62 | public static boolean validate() 63 | { 64 | if(!ChunkCopy.validateInstance() || !ChunkCopy.isClient()) 65 | { 66 | FileName = null; 67 | return false; 68 | } 69 | return true; 70 | } 71 | // ================================================== 72 | } 73 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/java/thecsdev/chunkcopy/api/AutoChunkCopy.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.api; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | import thecsdev.chunkcopy.ChunkCopy; 7 | 8 | /** 9 | * This class holds the information about the 10 | * status of auto-copying chunks. 11 | */ 12 | public class AutoChunkCopy 13 | { 14 | // ================================================== 15 | public enum ACCMode { Copying, Pasting } 16 | 17 | @Nullable 18 | private static String FileName = null; 19 | private static ACCMode AutoChunkCopyMode = null; 20 | // ================================================== 21 | /** 22 | * Returns the fileName of where the chunks are 23 | * currently being auto copied or pasted. Returns null if 24 | * {@link AutoChunkCopy} is currently not running. 25 | */ 26 | @Nullable 27 | public static String getFileName() { return AutoChunkCopyMode != null ? FileName : null; } 28 | 29 | /** 30 | * Returns true if auto-copying is currently running and doing anything. 31 | */ 32 | public static boolean isRunning() { return validate() && AutoChunkCopyMode != null && !StringUtils.isAllBlank(FileName); } 33 | public static boolean isCopying() { return isRunning() && AutoChunkCopyMode == ACCMode.Copying; } 34 | public static boolean isPasting() { return isRunning() && AutoChunkCopyMode == ACCMode.Pasting; } 35 | // -------------------------------------------------- 36 | public static boolean start(String fileName, ACCMode mode) 37 | { 38 | //validate instance 39 | if(!validate()) return false; 40 | 41 | //validate fileName with regex 42 | if(!fileName.matches("^[\\w\\-. ]+$")) return false; 43 | 44 | //start 45 | ChunkCopy.LOGGER.info("Started AutoChunkCopy; Mode: '" + mode.name() + "'; File: '" + fileName + "';"); 46 | AutoChunkCopyMode = mode; 47 | FileName = fileName; 48 | return true; 49 | } 50 | 51 | public static void stop() 52 | { 53 | //log if running 54 | if(isRunning()) 55 | ChunkCopy.LOGGER.info("Stopped AutoChunkCopy; Mode: '" + AutoChunkCopyMode.name() + "'; File: '" + FileName + "';"); 56 | 57 | //stop 58 | AutoChunkCopyMode = null; 59 | FileName = null; 60 | } 61 | // ================================================== 62 | public static boolean validate() 63 | { 64 | if(!ChunkCopy.validateInstance() || !ChunkCopy.isClient()) 65 | { 66 | FileName = null; 67 | return false; 68 | } 69 | return true; 70 | } 71 | // ================================================== 72 | } 73 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/java/thecsdev/chunkcopy/command/argument/CopiedChunksArgumentType.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.command.argument; 2 | 3 | import java.io.File; 4 | import java.util.concurrent.CompletableFuture; 5 | 6 | import com.mojang.brigadier.StringReader; 7 | import com.mojang.brigadier.arguments.ArgumentType; 8 | import com.mojang.brigadier.context.CommandContext; 9 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 10 | import com.mojang.brigadier.suggestion.Suggestions; 11 | import com.mojang.brigadier.suggestion.SuggestionsBuilder; 12 | 13 | import thecsdev.chunkcopy.api.ChunkCopyAPI; 14 | 15 | /** 16 | * An {@link ArgumentType}<{@link String}> that will suggest picking 17 | * from a list of copied chunks. 18 | */ 19 | public final class CopiedChunksArgumentType implements ArgumentType 20 | { 21 | // ================================================== 22 | public static CopiedChunksArgumentType forCopying() { return new CopiedChunksArgumentType(false); } 23 | public static CopiedChunksArgumentType forPasting() { return new CopiedChunksArgumentType(true); } 24 | // ================================================== 25 | public final boolean showDimensions; 26 | protected CopiedChunksArgumentType(boolean showDimensions) { this.showDimensions = showDimensions; } 27 | // ================================================== 28 | @Override 29 | public String parse(StringReader reader) throws CommandSyntaxException 30 | { 31 | if(!showDimensions) return reader.readUnquotedString(); 32 | else return reader.readString(); 33 | } 34 | // -------------------------------------------------- 35 | @Override 36 | public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) 37 | { 38 | try 39 | { 40 | //iterate existing directories and list them 41 | File sfd = ChunkCopyAPI.getSaveFilesDirectory(); 42 | if(sfd.exists()) 43 | for (File dir : sfd.listFiles()) 44 | { 45 | //skip files 46 | if(!dir.isDirectory()) continue; 47 | 48 | //suggest directory 49 | if(!showDimensions) builder.suggest(dir.getName()); 50 | else builder.suggest("\"" + dir.getName() + "\""); 51 | 52 | //suggest dimensions 53 | if(showDimensions) 54 | for(File subDir : dir.listFiles()) 55 | { 56 | //skip files 57 | if(!subDir.isDirectory()) continue; 58 | 59 | for(File subSubDir : subDir.listFiles()) 60 | { 61 | //skip files 62 | if(!subSubDir.isDirectory()) continue; 63 | 64 | //suggest directory 65 | builder.suggest("\"" + dir.getName() + "/" + subDir.getName() + "/" + subSubDir.getName() + "\""); 66 | } 67 | } 68 | } 69 | } 70 | catch (Exception e) {} 71 | 72 | //return 73 | return builder.buildFuture(); 74 | } 75 | // ================================================== 76 | } 77 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/java/thecsdev/chunkcopy/api/data/ChunkDataBlock.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.api.data; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | import net.minecraft.server.world.ServerWorld; 9 | import net.minecraft.util.Identifier; 10 | import net.minecraft.util.math.ChunkPos; 11 | import thecsdev.chunkcopy.api.io.IOUtils; 12 | 13 | /**Important: Please see {@link thecsdev.chunkcopy.api.data}!
14 | *
15 | * A chunk data block contains certain information 16 | * about a world chunk.
17 | *
18 | * Every chunk data block type MUST have the {@link ChunkDataBlockID} attribute, 19 | * and must have a public constructor with no parameters.
20 | *
21 | * Please see also {@link ChunkDataIO}. 22 | */ 23 | public abstract class ChunkDataBlock implements ChunkDataIO 24 | { 25 | // ================================================== 26 | /** 27 | * Constructs a {@link ChunkDataBlock} using it's 28 | * unique {@link Identifier}. 29 | * @param cdbId {@link ChunkDataBlock} {@link Identifier}. 30 | */ 31 | @Nullable 32 | public static ChunkDataBlock fromId(String cdbId) 33 | { 34 | try { return ChunkData.getChunkDataBlockType(cdbId).getConstructor().newInstance(); } 35 | catch (Exception e) { return null; } 36 | } 37 | // ================================================== 38 | /** 39 | * Returns this {@link ChunkDataBlock}'s {@link ChunkDataBlockID}. 40 | */ 41 | public final String getIdentifier() 42 | { 43 | ChunkDataBlockID id = getClass().getAnnotation(ChunkDataBlockID.class); 44 | if(id == null) return "null:null"; 45 | return id.namespace() + ":" + id.path(); 46 | } 47 | // -------------------------------------------------- 48 | /** 49 | * Writes {@link #getIdentifier()} to a byte 50 | * array and then returns the byte array. 51 | * @throws IOException If something goes wrong while writing the identifier to a byte array. 52 | */ 53 | public final byte[] getIdentifierByteArray() throws IOException 54 | { 55 | ByteArrayOutputStream stream = new ByteArrayOutputStream(); 56 | IOUtils.writeString(stream, getIdentifier()); 57 | byte[] bytes = stream.toByteArray(); 58 | stream.close(); 59 | return bytes; 60 | } 61 | // ================================================== 62 | /** 63 | * When pasting data to chunks, it is done server-side. 64 | * This means that clients do not get to know what is 65 | * going on while data is being pasted. To fix this issue, 66 | * {@link #updateClients(ServerWorld, ChunkPos)} notifies 67 | * the clients about the changes that were made.
68 | * Do not call this inside of {@link #pasteData(ServerWorld, ChunkPos)} 69 | * @param world The world where the chunk is located. 70 | * @param chunkPos The {@link ChunkPos} of the chunk in the world. 71 | */ 72 | public abstract void updateClients(ServerWorld world, ChunkPos chunkPos); 73 | // ================================================== 74 | } -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/java/thecsdev/chunkcopy/api/data/ChunkDataBlock.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.api.data; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | import net.minecraft.server.world.ServerWorld; 9 | import net.minecraft.util.Identifier; 10 | import net.minecraft.util.math.ChunkPos; 11 | import thecsdev.chunkcopy.api.io.IOUtils; 12 | 13 | /**Important: Please see {@link thecsdev.chunkcopy.api.data}!
14 | *
15 | * A chunk data block contains certain information 16 | * about a world chunk.
17 | *
18 | * Every chunk data block type MUST have the {@link ChunkDataBlockID} attribute, 19 | * and must have a public constructor with no parameters.
20 | *
21 | * Please see also {@link ChunkDataIO}. 22 | */ 23 | public abstract class ChunkDataBlock implements ChunkDataIO 24 | { 25 | // ================================================== 26 | /** 27 | * Constructs a {@link ChunkDataBlock} using it's 28 | * unique {@link Identifier}. 29 | * @param cdbId {@link ChunkDataBlock} {@link Identifier}. 30 | */ 31 | @Nullable 32 | public static ChunkDataBlock fromId(String cdbId) 33 | { 34 | try { return ChunkData.getChunkDataBlockType(cdbId).getConstructor().newInstance(); } 35 | catch (Exception e) { return null; } 36 | } 37 | // ================================================== 38 | /** 39 | * Returns this {@link ChunkDataBlock}'s {@link ChunkDataBlockID}. 40 | */ 41 | public final String getIdentifier() 42 | { 43 | ChunkDataBlockID id = getClass().getAnnotation(ChunkDataBlockID.class); 44 | if(id == null) return "null:null"; 45 | return id.namespace() + ":" + id.path(); 46 | } 47 | // -------------------------------------------------- 48 | /** 49 | * Writes {@link #getIdentifier()} to a byte 50 | * array and then returns the byte array. 51 | * @throws IOException If something goes wrong while writing the identifier to a byte array. 52 | */ 53 | public final byte[] getIdentifierByteArray() throws IOException 54 | { 55 | ByteArrayOutputStream stream = new ByteArrayOutputStream(); 56 | IOUtils.writeString(stream, getIdentifier()); 57 | byte[] bytes = stream.toByteArray(); 58 | stream.close(); 59 | return bytes; 60 | } 61 | // ================================================== 62 | /** 63 | * When pasting data to chunks, it is done server-side. 64 | * This means that clients do not get to know what is 65 | * going on while data is being pasted. To fix this issue, 66 | * {@link #updateClients(ServerWorld, ChunkPos)} notifies 67 | * the clients about the changes that were made.
68 | * Do not call this inside of {@link #pasteData(ServerWorld, ChunkPos)} 69 | * @param world The world where the chunk is located. 70 | * @param chunkPos The {@link ChunkPos} of the chunk in the world. 71 | */ 72 | public abstract void updateClients(ServerWorld world, ChunkPos chunkPos); 73 | // ================================================== 74 | } -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/java/thecsdev/chunkcopy/api/data/ChunkDataIO.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.api.data; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.OutputStream; 7 | 8 | import net.minecraft.server.world.ServerWorld; 9 | import net.minecraft.util.math.ChunkPos; 10 | import net.minecraft.world.World; 11 | 12 | /** 13 | * Represents a {@link ChunkData} component that can 14 | * be copied from and pasted to world chunks.
15 | *
16 | * Calling order for saving chunk data:
17 | * 1. {@link #copyData(World, ChunkPos)} then
18 | * 2. {@link #writeData(OutputStream)}
19 | *
20 | * Calling order for loading chunk data:
21 | * 1. {@link #readData(InputStream)} then
22 | * 2. {@link #pasteData(ServerWorld, ChunkPos)}. 23 | */ 24 | public interface ChunkDataIO 25 | { 26 | // ================================================== 27 | /** 28 | * Copies data from a World chunk to this {@link ChunkDataIO}.
29 | * Throwing exceptions here may have no effect. 30 | * @param world The world where the chunk is located. 31 | * @param chunkPos The {@link ChunkPos} of the chunk in the world. 32 | */ 33 | public abstract void copyData(World world, ChunkPos chunkPos); 34 | 35 | /** 36 | * Pastes data from this {@link ChunkDataIO} to a world chunk.
37 | * Throwing exceptions here may have no effect. 38 | * @param world The world where the chunk is located. 39 | * @param chunkPos The {@link ChunkPos} of the chunk in the world. 40 | */ 41 | public abstract void pasteData(ServerWorld world, ChunkPos chunkPos); 42 | // ================================================== 43 | /** 44 | * Reads (loads) this {@link ChunkDataIO} from an {@link InputStream}.
45 | * This method will not read the total length of the data. 46 | * @param stream The {@link InputStream} that contains the data. 47 | * @exception IOException If an IOException occurs while reading the data. 48 | */ 49 | public abstract void readData(InputStream stream) throws IOException; 50 | 51 | /** 52 | * Writes (saves) this {@link ChunkDataIO} to an {@link OutputStream}.
53 | * This method will not write the total length of the data. 54 | * @param stream The {@link OutputStream} where the data will be stored. 55 | * @exception IOException If an IOException occurs while writing the data. 56 | */ 57 | public abstract void writeData(OutputStream stream) throws IOException; 58 | // ================================================== 59 | /** 60 | * Converts {@link #writeData(OutputStream)} to a byte array. 61 | * @throws IOException See {@link #writeData(OutputStream)}. 62 | */ 63 | public default byte[] toByteArray() throws IOException 64 | { 65 | ByteArrayOutputStream stream = new ByteArrayOutputStream(); 66 | writeData(stream); 67 | byte[] bytes = stream.toByteArray(); 68 | stream.close(); 69 | return bytes; 70 | } 71 | // ================================================== 72 | } 73 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/java/thecsdev/chunkcopy/api/data/ChunkDataIO.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.api.data; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.OutputStream; 7 | 8 | import net.minecraft.server.world.ServerWorld; 9 | import net.minecraft.util.math.ChunkPos; 10 | import net.minecraft.world.World; 11 | 12 | /** 13 | * Represents a {@link ChunkData} component that can 14 | * be copied from and pasted to world chunks.
15 | *
16 | * Calling order for saving chunk data:
17 | * 1. {@link #copyData(World, ChunkPos)} then
18 | * 2. {@link #writeData(OutputStream)}
19 | *
20 | * Calling order for loading chunk data:
21 | * 1. {@link #readData(InputStream)} then
22 | * 2. {@link #pasteData(ServerWorld, ChunkPos)}. 23 | */ 24 | public interface ChunkDataIO 25 | { 26 | // ================================================== 27 | /** 28 | * Copies data from a World chunk to this {@link ChunkDataIO}.
29 | * Throwing exceptions here may have no effect. 30 | * @param world The world where the chunk is located. 31 | * @param chunkPos The {@link ChunkPos} of the chunk in the world. 32 | */ 33 | public abstract void copyData(World world, ChunkPos chunkPos); 34 | 35 | /** 36 | * Pastes data from this {@link ChunkDataIO} to a world chunk.
37 | * Throwing exceptions here may have no effect. 38 | * @param world The world where the chunk is located. 39 | * @param chunkPos The {@link ChunkPos} of the chunk in the world. 40 | */ 41 | public abstract void pasteData(ServerWorld world, ChunkPos chunkPos); 42 | // ================================================== 43 | /** 44 | * Reads (loads) this {@link ChunkDataIO} from an {@link InputStream}.
45 | * This method will not read the total length of the data. 46 | * @param stream The {@link InputStream} that contains the data. 47 | * @exception IOException If an IOException occurs while reading the data. 48 | */ 49 | public abstract void readData(InputStream stream) throws IOException; 50 | 51 | /** 52 | * Writes (saves) this {@link ChunkDataIO} to an {@link OutputStream}.
53 | * This method will not write the total length of the data. 54 | * @param stream The {@link OutputStream} where the data will be stored. 55 | * @exception IOException If an IOException occurs while writing the data. 56 | */ 57 | public abstract void writeData(OutputStream stream) throws IOException; 58 | // ================================================== 59 | /** 60 | * Converts {@link #writeData(OutputStream)} to a byte array. 61 | * @throws IOException See {@link #writeData(OutputStream)}. 62 | */ 63 | public default byte[] toByteArray() throws IOException 64 | { 65 | ByteArrayOutputStream stream = new ByteArrayOutputStream(); 66 | writeData(stream); 67 | byte[] bytes = stream.toByteArray(); 68 | stream.close(); 69 | return bytes; 70 | } 71 | // ================================================== 72 | } 73 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/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 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/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 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/java/thecsdev/chunkcopy/api/data/block/CDBFillBlocks.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.api.data.block; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.OutputStream; 6 | 7 | import net.minecraft.block.Block; 8 | import net.minecraft.block.BlockState; 9 | import net.minecraft.block.Blocks; 10 | import net.minecraft.server.world.ServerWorld; 11 | import net.minecraft.util.math.ChunkPos; 12 | import net.minecraft.world.World; 13 | import net.minecraft.world.chunk.ChunkSection; 14 | import net.minecraft.world.chunk.WorldChunk; 15 | import thecsdev.chunkcopy.ChunkCopy; 16 | import thecsdev.chunkcopy.api.data.ChunkDataBlock; 17 | import thecsdev.chunkcopy.api.data.ChunkDataBlockID; 18 | import thecsdev.chunkcopy.api.io.IOUtils; 19 | 20 | /** 21 | * A {@link ChunkDataBlock} that contains no information about world chunk blocks. 22 | * It is only used to fill chunks. 23 | */ 24 | @ChunkDataBlockID(namespace = ChunkCopy.ModID, path = "fill_blocks") 25 | public class CDBFillBlocks extends ChunkDataBlock 26 | { 27 | // ================================================== 28 | public BlockState state = Blocks.AIR.getDefaultState(); 29 | // ================================================== 30 | @Override 31 | public void copyData(World world, ChunkPos chunkPos) {} 32 | // -------------------------------------------------- 33 | @Override 34 | public void pasteData(ServerWorld world, ChunkPos chunkPos) 35 | { 36 | WorldChunk chunk = world.getChunk(chunkPos.x, chunkPos.z); 37 | int chunkWidthX = Math.abs(chunkPos.getEndX() - chunkPos.getStartX()); 38 | int chunkWidthZ = Math.abs(chunkPos.getEndZ() - chunkPos.getStartZ()); 39 | 40 | //iterate all block IDs 41 | int x = 0, y = chunk.getBottomY(), z = 0; 42 | 43 | while (y < chunk.getTopY() + 1) 44 | { 45 | //place block 46 | try 47 | { 48 | ChunkSection toChunkSection = chunk.getSection(chunk.getSectionIndex(y)); 49 | toChunkSection.getBlockStateContainer().set(x, y & 0xF, z, state); 50 | } 51 | catch (Exception e) { break; } 52 | 53 | //increment 54 | x++; 55 | if(x > chunkWidthX) 56 | { 57 | z++; x = 0; 58 | if(z > chunkWidthZ) { y++; z = 0; } 59 | } 60 | } 61 | 62 | //mark as needs saving 63 | chunk.setNeedsSaving(true); 64 | } 65 | // -------------------------------------------------- 66 | @Override 67 | public void updateClients(ServerWorld world, ChunkPos chunkPos) 68 | { 69 | //use CDBBlocksLegacy's method of updating clients 70 | new CDBBlocksLegacy().updateClients(world, chunkPos); 71 | } 72 | // ================================================== 73 | @Override 74 | public void readData(InputStream stream) throws IOException 75 | { 76 | state = Block.getStateFromRawId(IOUtils.readVarInt(stream)); 77 | } 78 | // -------------------------------------------------- 79 | @Override 80 | public void writeData(OutputStream stream) throws IOException 81 | { 82 | IOUtils.writeVarInt(stream, Block.getRawIdFromState(state)); 83 | } 84 | // ================================================== 85 | } 86 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/java/thecsdev/chunkcopy/api/data/block/CDBFillBlocks.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.api.data.block; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.OutputStream; 6 | 7 | import net.minecraft.block.Block; 8 | import net.minecraft.block.BlockState; 9 | import net.minecraft.block.Blocks; 10 | import net.minecraft.server.world.ServerWorld; 11 | import net.minecraft.util.math.ChunkPos; 12 | import net.minecraft.world.World; 13 | import net.minecraft.world.chunk.ChunkSection; 14 | import net.minecraft.world.chunk.WorldChunk; 15 | import thecsdev.chunkcopy.ChunkCopy; 16 | import thecsdev.chunkcopy.api.data.ChunkDataBlock; 17 | import thecsdev.chunkcopy.api.data.ChunkDataBlockID; 18 | import thecsdev.chunkcopy.api.io.IOUtils; 19 | 20 | /** 21 | * A {@link ChunkDataBlock} that contains no information about world chunk blocks. 22 | * It is only used to fill chunks. 23 | */ 24 | @ChunkDataBlockID(namespace = ChunkCopy.ModID, path = "fill_blocks") 25 | public class CDBFillBlocks extends ChunkDataBlock 26 | { 27 | // ================================================== 28 | public BlockState state = Blocks.AIR.getDefaultState(); 29 | // ================================================== 30 | @Override 31 | public void copyData(World world, ChunkPos chunkPos) {} 32 | // -------------------------------------------------- 33 | @Override 34 | public void pasteData(ServerWorld world, ChunkPos chunkPos) 35 | { 36 | WorldChunk chunk = world.getChunk(chunkPos.x, chunkPos.z); 37 | int chunkWidthX = Math.abs(chunkPos.getEndX() - chunkPos.getStartX()); 38 | int chunkWidthZ = Math.abs(chunkPos.getEndZ() - chunkPos.getStartZ()); 39 | 40 | //iterate all block IDs 41 | int x = 0, y = chunk.getBottomY(), z = 0; 42 | 43 | while (y < chunk.getTopY() + 1) 44 | { 45 | //place block 46 | try 47 | { 48 | ChunkSection toChunkSection = chunk.getSection(chunk.getSectionIndex(y)); 49 | toChunkSection.getBlockStateContainer().set(x, y & 0xF, z, state); 50 | } 51 | catch (Exception e) { break; } 52 | 53 | //increment 54 | x++; 55 | if(x > chunkWidthX) 56 | { 57 | z++; x = 0; 58 | if(z > chunkWidthZ) { y++; z = 0; } 59 | } 60 | } 61 | 62 | //mark as needs saving 63 | chunk.setShouldSave(true); 64 | } 65 | // -------------------------------------------------- 66 | @Override 67 | public void updateClients(ServerWorld world, ChunkPos chunkPos) 68 | { 69 | //use CDBBlocksLegacy's method of updating clients 70 | new CDBBlocksLegacy().updateClients(world, chunkPos); 71 | } 72 | // ================================================== 73 | @Override 74 | public void readData(InputStream stream) throws IOException 75 | { 76 | state = Block.getStateFromRawId(IOUtils.readVarInt(stream)); 77 | } 78 | // -------------------------------------------------- 79 | @Override 80 | public void writeData(OutputStream stream) throws IOException 81 | { 82 | IOUtils.writeVarInt(stream, Block.getRawIdFromState(state)); 83 | } 84 | // ================================================== 85 | } 86 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/java/thecsdev/chunkcopy/command/argument/CopiedChunksArgumentType.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.command.argument; 2 | 3 | import java.io.File; 4 | import java.util.concurrent.CompletableFuture; 5 | 6 | import com.mojang.brigadier.StringReader; 7 | import com.mojang.brigadier.arguments.ArgumentType; 8 | import com.mojang.brigadier.context.CommandContext; 9 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 10 | import com.mojang.brigadier.suggestion.Suggestions; 11 | import com.mojang.brigadier.suggestion.SuggestionsBuilder; 12 | 13 | import thecsdev.chunkcopy.api.ChunkCopyAPI; 14 | 15 | /** 16 | * An {@link ArgumentType}<{@link String}> that will suggest picking 17 | * from a list of copied chunks. 18 | */ 19 | public final class CopiedChunksArgumentType implements ArgumentType 20 | { 21 | // ================================================== 22 | public final static CopiedChunksArgumentType forCopying = new CopiedChunksArgumentType(false); 23 | public final static CopiedChunksArgumentType forPasting = new CopiedChunksArgumentType(true); 24 | // -------------------------------------------------- 25 | public static CopiedChunksArgumentType forCopying() { return forCopying; } 26 | public static CopiedChunksArgumentType forPasting() { return forPasting; } 27 | // ================================================== 28 | public final boolean showDimensions; 29 | protected CopiedChunksArgumentType(boolean showDimensions) { this.showDimensions = showDimensions; } 30 | // ================================================== 31 | @Override 32 | public String parse(StringReader reader) throws CommandSyntaxException 33 | { 34 | if(!showDimensions) return reader.readUnquotedString(); 35 | else return reader.readString(); 36 | } 37 | // -------------------------------------------------- 38 | @Override 39 | public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) 40 | { 41 | try 42 | { 43 | //iterate existing directories and list them 44 | File sfd = ChunkCopyAPI.getSaveFilesDirectory(); 45 | if(sfd.exists()) 46 | for (File dir : sfd.listFiles()) 47 | { 48 | //skip files 49 | if(!dir.isDirectory()) continue; 50 | 51 | //suggest directory 52 | if(!showDimensions) builder.suggest(dir.getName()); 53 | else builder.suggest("\"" + dir.getName() + "\""); 54 | 55 | //suggest dimensions 56 | if(showDimensions) 57 | for(File subDir : dir.listFiles()) 58 | { 59 | //skip files 60 | if(!subDir.isDirectory()) continue; 61 | 62 | for(File subSubDir : subDir.listFiles()) 63 | { 64 | //skip files 65 | if(!subSubDir.isDirectory()) continue; 66 | 67 | //suggest directory 68 | builder.suggest("\"" + dir.getName() + "/" + subDir.getName() + "/" + subSubDir.getName() + "\""); 69 | } 70 | } 71 | } 72 | } 73 | catch (Exception e) {} 74 | 75 | //return 76 | return builder.buildFuture(); 77 | } 78 | // ================================================== 79 | } 80 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/java/thecsdev/chunkcopy/api/ChunkCopyUtils.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.api; 2 | 3 | import java.util.ArrayList; 4 | 5 | import net.minecraft.entity.Entity; 6 | import net.minecraft.entity.boss.dragon.EnderDragonEntity; 7 | import net.minecraft.entity.player.PlayerEntity; 8 | import net.minecraft.util.math.Box; 9 | import net.minecraft.util.math.ChunkPos; 10 | import net.minecraft.world.World; 11 | import net.minecraft.world.chunk.Chunk; 12 | import net.minecraft.world.chunk.EmptyChunk; 13 | import net.minecraft.world.chunk.WorldChunk; 14 | import thecsdev.chunkcopy.mixin.WorldMixin; 15 | 16 | /** 17 | * Provides utility methods for the {@link ChunkCopyAPI}. 18 | */ 19 | public final class ChunkCopyUtils 20 | { 21 | 22 | // ================================================== 23 | /** 24 | * Returns an {@link ArrayList} of {@link ChunkPos}itions 25 | * of nearby loaded chunks. 26 | * @param world The world where the chunks are located. 27 | * @param chunkPos The central chunk around which to check for loaded chunks. 28 | * @param chunkDistance The maximum distance of loaded chunks. 29 | */ 30 | public static ArrayList getNearbyLoadedChunks(World world, ChunkPos chunkPos, int chunkDistance) 31 | { 32 | //clamp chunkDistance 33 | if(chunkDistance < 1) chunkDistance = 1; 34 | else if(chunkDistance > 8) chunkDistance = 8; 35 | 36 | //define list 37 | ArrayList result = new ArrayList<>(); 38 | 39 | //add chunks 40 | if(chunkDistance == 1) { result.add(chunkPos); } 41 | else if(chunkDistance > 1) 42 | { 43 | chunkDistance--; 44 | for(int chunkX = chunkPos.x - chunkDistance; chunkX < chunkPos.x + chunkDistance; chunkX++) 45 | { 46 | for(int chunkZ = chunkPos.z - chunkDistance; chunkZ < chunkPos.z + chunkDistance; chunkZ++) 47 | { 48 | //check if loaded 49 | if(!world.isChunkLoaded(chunkX, chunkZ)) continue; 50 | WorldChunk chunk = world.getChunk(chunkX, chunkZ); 51 | if(chunk == null || (chunk instanceof EmptyChunk)) continue; 52 | 53 | //add chunk to the list 54 | result.add(new ChunkPos(chunkX, chunkZ)); 55 | } 56 | } 57 | } 58 | 59 | //return 60 | return result; 61 | } 62 | // -------------------------------------------------- 63 | /** 64 | * Returns a {@link Box} that contains a whole world chunk. 65 | * @param world The world where the chunk is located. 66 | * @param chunkPos The {@link ChunkPos} of the chunk in the world. 67 | */ 68 | public static Box getChunkBox(World world, ChunkPos chunkPos) 69 | { 70 | //calculate 71 | Chunk chunk = world.getChunk(chunkPos.getBlockPos(0, 0, 0)); 72 | int chunkWidthX = Math.abs(chunkPos.getEndX() - chunkPos.getStartX()); 73 | int chunkWidthZ = Math.abs(chunkPos.getEndZ() - chunkPos.getStartZ()); 74 | Box chunkBox = new Box( 75 | chunkPos.getBlockPos(0, chunk.getBottomY(), 0), 76 | chunkPos.getBlockPos(chunkWidthX, chunk.getTopY(), chunkWidthZ)); 77 | 78 | //return 79 | return chunkBox; 80 | } 81 | // -------------------------------------------------- 82 | /** 83 | * Returns a list of all {@link Entity}-s present in a world chunk. 84 | * @param world The world where the chunk is located. 85 | * @param chunkPos The {@link ChunkPos} of the chunk in the world. 86 | */ 87 | public static ArrayList getEntitiesInChunk(World world, ChunkPos chunkPos) 88 | { 89 | //define list and chunk box 90 | ArrayList result = new ArrayList<>(); 91 | Box chunkBox = getChunkBox(world, chunkPos); 92 | 93 | //get and add entities 94 | ((WorldMixin)world).getEntityLookup().forEachIntersects(chunkBox, e -> 95 | { 96 | if(!(e instanceof PlayerEntity) && !(e instanceof EnderDragonEntity)) 97 | result.add(e); 98 | }); 99 | 100 | //return list 101 | return result; 102 | } 103 | // ================================================== 104 | } 105 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/java/thecsdev/chunkcopy/api/ChunkCopyUtils.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.api; 2 | 3 | import java.util.ArrayList; 4 | 5 | import net.minecraft.entity.Entity; 6 | import net.minecraft.entity.boss.dragon.EnderDragonEntity; 7 | import net.minecraft.entity.player.PlayerEntity; 8 | import net.minecraft.util.math.Box; 9 | import net.minecraft.util.math.ChunkPos; 10 | import net.minecraft.world.World; 11 | import net.minecraft.world.chunk.Chunk; 12 | import net.minecraft.world.chunk.EmptyChunk; 13 | import net.minecraft.world.chunk.WorldChunk; 14 | import thecsdev.chunkcopy.mixin.WorldMixin; 15 | 16 | /** 17 | * Provides utility methods for the {@link ChunkCopyAPI}. 18 | */ 19 | public final class ChunkCopyUtils 20 | { 21 | 22 | // ================================================== 23 | /** 24 | * Returns an {@link ArrayList} of {@link ChunkPos}itions 25 | * of nearby loaded chunks. 26 | * @param world The world where the chunks are located. 27 | * @param chunkPos The central chunk around which to check for loaded chunks. 28 | * @param chunkDistance The maximum distance of loaded chunks. 29 | */ 30 | public static ArrayList getNearbyLoadedChunks(World world, ChunkPos chunkPos, int chunkDistance) 31 | { 32 | //clamp chunkDistance 33 | if(chunkDistance < 1) chunkDistance = 1; 34 | else if(chunkDistance > 8) chunkDistance = 8; 35 | 36 | //define list 37 | ArrayList result = new ArrayList<>(); 38 | 39 | //add chunks 40 | if(chunkDistance == 1) { result.add(chunkPos); } 41 | else if(chunkDistance > 1) 42 | { 43 | chunkDistance--; 44 | for(int chunkX = chunkPos.x - chunkDistance; chunkX < chunkPos.x + chunkDistance; chunkX++) 45 | { 46 | for(int chunkZ = chunkPos.z - chunkDistance; chunkZ < chunkPos.z + chunkDistance; chunkZ++) 47 | { 48 | //check if loaded 49 | if(!world.isChunkLoaded(chunkX, chunkZ)) continue; 50 | WorldChunk chunk = world.getChunk(chunkX, chunkZ); 51 | if(chunk == null || (chunk instanceof EmptyChunk)) continue; 52 | 53 | //add chunk to the list 54 | result.add(new ChunkPos(chunkX, chunkZ)); 55 | } 56 | } 57 | } 58 | 59 | //return 60 | return result; 61 | } 62 | // -------------------------------------------------- 63 | /** 64 | * Returns a {@link Box} that contains a whole world chunk. 65 | * @param world The world where the chunk is located. 66 | * @param chunkPos The {@link ChunkPos} of the chunk in the world. 67 | */ 68 | public static Box getChunkBox(World world, ChunkPos chunkPos) 69 | { 70 | //calculate 71 | Chunk chunk = world.getChunk(chunkPos.getBlockPos(0, 0, 0)); 72 | int chunkWidthX = Math.abs(chunkPos.getEndX() - chunkPos.getStartX()); 73 | int chunkWidthZ = Math.abs(chunkPos.getEndZ() - chunkPos.getStartZ()); 74 | Box chunkBox = new Box( 75 | chunkPos.getBlockPos(0, chunk.getBottomY(), 0), 76 | chunkPos.getBlockPos(chunkWidthX, chunk.getTopY(), chunkWidthZ)); 77 | 78 | //return 79 | return chunkBox; 80 | } 81 | // -------------------------------------------------- 82 | /** 83 | * Returns a list of all {@link Entity}-s present in a world chunk. 84 | * @param world The world where the chunk is located. 85 | * @param chunkPos The {@link ChunkPos} of the chunk in the world. 86 | */ 87 | public static ArrayList getEntitiesInChunk(World world, ChunkPos chunkPos) 88 | { 89 | //define list and chunk box 90 | ArrayList result = new ArrayList<>(); 91 | Box chunkBox = getChunkBox(world, chunkPos); 92 | 93 | //get and add entities 94 | ((WorldMixin)world).getEntityLookup().forEachIntersects(chunkBox, e -> 95 | { 96 | if(!(e instanceof PlayerEntity) && !(e instanceof EnderDragonEntity)) 97 | result.add(e); 98 | }); 99 | 100 | //return list 101 | return result; 102 | } 103 | // ================================================== 104 | } 105 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/java/thecsdev/chunkcopy/api/data/block/CDBEntitiesLegacy.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.api.data.block; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.OutputStream; 6 | import java.util.ArrayList; 7 | 8 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 9 | 10 | import net.minecraft.entity.Entity; 11 | import net.minecraft.entity.EntityType; 12 | import net.minecraft.nbt.NbtCompound; 13 | import net.minecraft.nbt.NbtHelper; 14 | import net.minecraft.server.world.ServerWorld; 15 | import net.minecraft.util.math.ChunkPos; 16 | import net.minecraft.world.World; 17 | import thecsdev.chunkcopy.ChunkCopy; 18 | import thecsdev.chunkcopy.api.ChunkCopyUtils; 19 | import thecsdev.chunkcopy.api.data.ChunkDataBlock; 20 | import thecsdev.chunkcopy.api.data.ChunkDataBlockID; 21 | import thecsdev.chunkcopy.api.io.IOUtils; 22 | 23 | /** 24 | * A {@link ChunkDataBlock} that contains information about world chunk entities. 25 | */ 26 | @ChunkDataBlockID(namespace = ChunkCopy.ModID, path = "entities_legacy") 27 | public class CDBEntitiesLegacy extends ChunkDataBlock 28 | { 29 | // ================================================== 30 | public final ArrayList EntityNBTs = new ArrayList(); 31 | // ================================================== 32 | @Override 33 | public void copyData(World world, ChunkPos chunkPos) 34 | { 35 | //clear old data 36 | EntityNBTs.clear(); 37 | 38 | //iterate entities 39 | for (Entity entity : ChunkCopyUtils.getEntitiesInChunk(world, chunkPos)) 40 | { 41 | //create nbt for each entity 42 | NbtCompound eNbt = new NbtCompound(); 43 | 44 | //write entity data to the nbt 45 | eNbt.putString("id", EntityType.getId(entity.getType()).toString()); 46 | eNbt = entity.writeNbt(eNbt); 47 | 48 | //add the nbt to EntityNBTs 49 | EntityNBTs.add(eNbt); 50 | } 51 | } 52 | // -------------------------------------------------- 53 | @Override 54 | public void pasteData(ServerWorld world, ChunkPos chunkPos) 55 | { 56 | //clear existing entities in the chunk 57 | for (Entity entity : ChunkCopyUtils.getEntitiesInChunk(world, chunkPos)) 58 | { 59 | if(!entity.isPlayer()) 60 | entity.discard(); 61 | } 62 | 63 | //iterate NBTs 64 | for (NbtCompound eNbt : EntityNBTs) 65 | try 66 | { 67 | //create entity from nbt 68 | Entity entity = EntityType.getEntityFromNbt(eNbt, world).get(); 69 | 70 | //discard old entity if there is one and if it isn't already removed 71 | Entity oldEntity = world.getEntity(entity.getUuid()); 72 | if(oldEntity != null && !oldEntity.isRemoved()) oldEntity.discard(); 73 | 74 | //spawn entity 75 | world.spawnEntity(entity); 76 | } 77 | catch (Exception e) {} 78 | } 79 | // -------------------------------------------------- 80 | @Override 81 | public void updateClients(ServerWorld world, ChunkPos chunkPos) 82 | { 83 | //no need to do this, the game will do this for us. 84 | } 85 | // ================================================== 86 | @Override 87 | public void readData(InputStream stream) throws IOException 88 | { 89 | //clear old data 90 | EntityNBTs.clear(); 91 | 92 | //keep reading until there is nothing left to read 93 | while(stream.available() > 0) 94 | try 95 | { 96 | String nbtString = IOUtils.readString(stream); 97 | NbtCompound eNbt = NbtHelper.fromNbtProviderString(nbtString); 98 | EntityNBTs.add(eNbt); 99 | } 100 | catch (CommandSyntaxException e) { throw new IOException("Invalid or corrupted Entity NBT data."); } 101 | catch (Exception e) { break; } 102 | } 103 | // -------------------------------------------------- 104 | @Override 105 | public void writeData(OutputStream stream) throws IOException 106 | { 107 | //iterate all entity NBTs 108 | for (NbtCompound eNbt : EntityNBTs) 109 | //write entity nbt 110 | IOUtils.writeString(stream, NbtHelper.toNbtProviderString(eNbt)); 111 | } 112 | // ================================================== 113 | } 114 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/java/thecsdev/chunkcopy/api/data/block/CDBEntitiesLegacy.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.api.data.block; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.OutputStream; 6 | import java.util.ArrayList; 7 | 8 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 9 | 10 | import net.minecraft.entity.Entity; 11 | import net.minecraft.entity.EntityType; 12 | import net.minecraft.nbt.NbtCompound; 13 | import net.minecraft.nbt.NbtHelper; 14 | import net.minecraft.server.world.ServerWorld; 15 | import net.minecraft.util.math.ChunkPos; 16 | import net.minecraft.world.World; 17 | import thecsdev.chunkcopy.ChunkCopy; 18 | import thecsdev.chunkcopy.api.ChunkCopyUtils; 19 | import thecsdev.chunkcopy.api.data.ChunkDataBlock; 20 | import thecsdev.chunkcopy.api.data.ChunkDataBlockID; 21 | import thecsdev.chunkcopy.api.io.IOUtils; 22 | 23 | /** 24 | * A {@link ChunkDataBlock} that contains information about world chunk entities. 25 | */ 26 | @ChunkDataBlockID(namespace = ChunkCopy.ModID, path = "entities_legacy") 27 | public class CDBEntitiesLegacy extends ChunkDataBlock 28 | { 29 | // ================================================== 30 | public final ArrayList EntityNBTs = new ArrayList(); 31 | // ================================================== 32 | @Override 33 | public void copyData(World world, ChunkPos chunkPos) 34 | { 35 | //clear old data 36 | EntityNBTs.clear(); 37 | 38 | //iterate entities 39 | for (Entity entity : ChunkCopyUtils.getEntitiesInChunk(world, chunkPos)) 40 | { 41 | //create nbt for each entity 42 | NbtCompound eNbt = new NbtCompound(); 43 | 44 | //write entity data to the nbt 45 | eNbt.putString("id", EntityType.getId(entity.getType()).toString()); 46 | eNbt = entity.writeNbt(eNbt); 47 | 48 | //add the nbt to EntityNBTs 49 | EntityNBTs.add(eNbt); 50 | } 51 | } 52 | // -------------------------------------------------- 53 | @Override 54 | public void pasteData(ServerWorld world, ChunkPos chunkPos) 55 | { 56 | //clear existing entities in the chunk 57 | for (Entity entity : ChunkCopyUtils.getEntitiesInChunk(world, chunkPos)) 58 | { 59 | if(!entity.isPlayer()) 60 | entity.discard(); 61 | } 62 | 63 | //iterate NBTs 64 | for (NbtCompound eNbt : EntityNBTs) 65 | try 66 | { 67 | //create entity from nbt 68 | Entity entity = EntityType.getEntityFromNbt(eNbt, world).get(); 69 | 70 | //discard old entity if there is one and if it isn't already removed 71 | Entity oldEntity = world.getEntity(entity.getUuid()); 72 | if(oldEntity != null && !oldEntity.isRemoved()) oldEntity.discard(); 73 | 74 | //spawn entity 75 | world.spawnEntity(entity); 76 | } 77 | catch (Exception e) {} 78 | } 79 | // -------------------------------------------------- 80 | @Override 81 | public void updateClients(ServerWorld world, ChunkPos chunkPos) 82 | { 83 | //no need to do this, the game will do this for us. 84 | } 85 | // ================================================== 86 | @Override 87 | public void readData(InputStream stream) throws IOException 88 | { 89 | //clear old data 90 | EntityNBTs.clear(); 91 | 92 | //keep reading until there is nothing left to read 93 | while(stream.available() > 0) 94 | try 95 | { 96 | String nbtString = IOUtils.readString(stream); 97 | NbtCompound eNbt = NbtHelper.fromNbtProviderString(nbtString); 98 | EntityNBTs.add(eNbt); 99 | } 100 | catch (CommandSyntaxException e) { throw new IOException("Invalid or corrupted Entity NBT data."); } 101 | catch (Exception e) { break; } 102 | } 103 | // -------------------------------------------------- 104 | @Override 105 | public void writeData(OutputStream stream) throws IOException 106 | { 107 | //iterate all entity NBTs 108 | for (NbtCompound eNbt : EntityNBTs) 109 | //write entity nbt 110 | IOUtils.writeString(stream, NbtHelper.toNbtProviderString(eNbt)); 111 | } 112 | // ================================================== 113 | } 114 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/java/thecsdev/chunkcopy/api/data/block/CDBChunkSections.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.api.data.block; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.io.OutputStream; 8 | import java.util.ArrayList; 9 | 10 | import io.netty.buffer.Unpooled; 11 | import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; 12 | import net.minecraft.network.PacketByteBuf; 13 | import net.minecraft.server.world.ServerWorld; 14 | import net.minecraft.util.math.ChunkPos; 15 | import net.minecraft.world.World; 16 | import net.minecraft.world.chunk.Chunk; 17 | import net.minecraft.world.chunk.ChunkSection; 18 | import thecsdev.chunkcopy.ChunkCopy; 19 | import thecsdev.chunkcopy.api.data.ChunkDataBlock; 20 | import thecsdev.chunkcopy.api.data.ChunkDataBlockID; 21 | import thecsdev.chunkcopy.api.io.IOUtils; 22 | import thecsdev.chunkcopy.api.io.Tuple; 23 | 24 | /** 25 | * A {@link ChunkDataBlock} that contains information about world {@link ChunkSection}s. 26 | */ 27 | @ChunkDataBlockID(namespace = ChunkCopy.ModID, path = "chunk_sections") 28 | public class CDBChunkSections extends ChunkDataBlock 29 | { 30 | // ================================================== 31 | /** 32 | * Stores {@link ChunkSection} data. The {@link Integer} is 33 | * {@link ChunkSection#getYOffset()}, and the {@link PacketByteBuf} 34 | * is the {@link ChunkSection} data. 35 | */ 36 | public final ArrayList> ChunkSectionData = new ArrayList>(); 37 | // ================================================== 38 | @Override 39 | public void copyData(World world, ChunkPos chunkPos) 40 | { 41 | //clear old data 42 | ChunkSectionData.clear(); 43 | 44 | Chunk chunk = world.getChunk(chunkPos.x, chunkPos.z); 45 | for (ChunkSection chunkSection : chunk.getSectionArray()) 46 | { 47 | PacketByteBuf pbb = PacketByteBufs.create(); 48 | chunkSection.toPacket(pbb); 49 | ChunkSectionData.add(new Tuple(chunkSection.getYOffset(), pbb)); 50 | } 51 | } 52 | // -------------------------------------------------- 53 | @Override 54 | public void pasteData(ServerWorld world, ChunkPos chunkPos) 55 | { 56 | Chunk chunk = world.getChunk(chunkPos.x, chunkPos.z); 57 | for (Tuple pbb : ChunkSectionData) 58 | { 59 | ChunkSection cs = chunk.getSection(chunk.getSectionIndex(pbb.Item1)); 60 | cs.fromPacket(pbb.Item2); 61 | } 62 | chunk.setShouldSave(true); 63 | } 64 | // -------------------------------------------------- 65 | @Override 66 | public void updateClients(ServerWorld world, ChunkPos chunkPos) 67 | { 68 | //use CDBBlocksLegacy's method of updating clients 69 | CDBBlocksLegacy.updateClientsB(world, chunkPos); 70 | } 71 | // ================================================== 72 | @Override 73 | public void readData(InputStream stream) throws IOException 74 | { 75 | //clear old data 76 | ChunkSectionData.clear(); 77 | 78 | //keep reading until there is nothing left to read 79 | while(stream.available() > 0) 80 | { 81 | int len = IOUtils.readVarInt(stream); 82 | byte[] pbbBytes = stream.readNBytes(len); 83 | 84 | ByteArrayInputStream pbbStream = new ByteArrayInputStream(pbbBytes); 85 | int offsetY = IOUtils.readVarInt(pbbStream); 86 | PacketByteBuf pbb = PacketByteBufs.copy(Unpooled.copiedBuffer(IOUtils.readByteArray(pbbStream))); 87 | pbbStream.close(); 88 | 89 | ChunkSectionData.add(new Tuple(offsetY, pbb)); 90 | } 91 | } 92 | // -------------------------------------------------- 93 | @Override 94 | public void writeData(OutputStream stream) throws IOException 95 | { 96 | //iterate all chunk sections 97 | for (Tuple pbb : ChunkSectionData) 98 | { 99 | //handle a separate stream for each tuple 100 | ByteArrayOutputStream pbbStream = new ByteArrayOutputStream(); 101 | byte[] pbbCsBytes = pbb.Item2.getWrittenBytes(); 102 | 103 | IOUtils.writeVarInt(pbbStream, pbb.Item1); 104 | IOUtils.writeByteArray(pbbStream, pbbCsBytes); 105 | 106 | //write each stream 107 | byte[] pbbBytes = pbbStream.toByteArray(); 108 | IOUtils.writeByteArray(stream, pbbBytes); 109 | pbbStream.close(); 110 | } 111 | } 112 | // ================================================== 113 | } 114 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/java/thecsdev/chunkcopy/api/data/block/CDBChunkSections.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.api.data.block; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.io.OutputStream; 8 | import java.util.ArrayList; 9 | 10 | import io.netty.buffer.Unpooled; 11 | import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; 12 | import net.minecraft.network.PacketByteBuf; 13 | import net.minecraft.server.world.ServerWorld; 14 | import net.minecraft.util.math.ChunkPos; 15 | import net.minecraft.world.World; 16 | import net.minecraft.world.chunk.Chunk; 17 | import net.minecraft.world.chunk.ChunkSection; 18 | import thecsdev.chunkcopy.ChunkCopy; 19 | import thecsdev.chunkcopy.api.data.ChunkDataBlock; 20 | import thecsdev.chunkcopy.api.data.ChunkDataBlockID; 21 | import thecsdev.chunkcopy.api.io.IOUtils; 22 | import thecsdev.chunkcopy.api.io.Tuple; 23 | 24 | /** 25 | * A {@link ChunkDataBlock} that contains information about world {@link ChunkSection}s. 26 | */ 27 | @ChunkDataBlockID(namespace = ChunkCopy.ModID, path = "chunk_sections") 28 | public class CDBChunkSections extends ChunkDataBlock 29 | { 30 | // ================================================== 31 | /** 32 | * Stores {@link ChunkSection} data. The {@link Integer} is 33 | * {@link ChunkSection#getYOffset()}, and the {@link PacketByteBuf} 34 | * is the {@link ChunkSection} data. 35 | */ 36 | public final ArrayList> ChunkSectionData = new ArrayList>(); 37 | // ================================================== 38 | @Override 39 | public void copyData(World world, ChunkPos chunkPos) 40 | { 41 | //clear old data 42 | ChunkSectionData.clear(); 43 | 44 | Chunk chunk = world.getChunk(chunkPos.x, chunkPos.z); 45 | for (ChunkSection chunkSection : chunk.getSectionArray()) 46 | { 47 | PacketByteBuf pbb = PacketByteBufs.create(); 48 | chunkSection.toPacket(pbb); 49 | ChunkSectionData.add(new Tuple(chunkSection.getYOffset(), pbb)); 50 | } 51 | } 52 | // -------------------------------------------------- 53 | @Override 54 | public void pasteData(ServerWorld world, ChunkPos chunkPos) 55 | { 56 | Chunk chunk = world.getChunk(chunkPos.x, chunkPos.z); 57 | for (Tuple pbb : ChunkSectionData) 58 | { 59 | ChunkSection cs = chunk.getSection(chunk.getSectionIndex(pbb.Item1)); 60 | cs.fromPacket(pbb.Item2); 61 | } 62 | chunk.setNeedsSaving(true); 63 | } 64 | // -------------------------------------------------- 65 | @Override 66 | public void updateClients(ServerWorld world, ChunkPos chunkPos) 67 | { 68 | //use CDBBlocksLegacy's method of updating clients 69 | new CDBBlocksLegacy().updateClients(world, chunkPos); 70 | } 71 | // ================================================== 72 | @Override 73 | public void readData(InputStream stream) throws IOException 74 | { 75 | //clear old data 76 | ChunkSectionData.clear(); 77 | 78 | //keep reading until there is nothing left to read 79 | while(stream.available() > 0) 80 | { 81 | int len = IOUtils.readVarInt(stream); 82 | byte[] pbbBytes = stream.readNBytes(len); 83 | 84 | ByteArrayInputStream pbbStream = new ByteArrayInputStream(pbbBytes); 85 | int offsetY = IOUtils.readVarInt(pbbStream); 86 | PacketByteBuf pbb = PacketByteBufs.copy(Unpooled.copiedBuffer(IOUtils.readByteArray(pbbStream))); 87 | pbbStream.close(); 88 | 89 | ChunkSectionData.add(new Tuple(offsetY, pbb)); 90 | } 91 | } 92 | // -------------------------------------------------- 93 | @Override 94 | public void writeData(OutputStream stream) throws IOException 95 | { 96 | //iterate all chunk sections 97 | for (Tuple pbb : ChunkSectionData) 98 | { 99 | //handle a separate stream for each tuple 100 | ByteArrayOutputStream pbbStream = new ByteArrayOutputStream(); 101 | byte[] pbbCsBytes = pbb.Item2.getWrittenBytes(); 102 | 103 | IOUtils.writeVarInt(pbbStream, pbb.Item1); 104 | IOUtils.writeByteArray(pbbStream, pbbCsBytes); 105 | 106 | //write each stream 107 | byte[] pbbBytes = pbbStream.toByteArray(); 108 | IOUtils.writeByteArray(stream, pbbBytes); 109 | pbbStream.close(); 110 | } 111 | } 112 | // ================================================== 113 | } 114 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/java/thecsdev/chunkcopy/api/config/ChunkCopyConfig.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.api.config; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileOutputStream; 6 | import java.io.IOException; 7 | import java.util.HashSet; 8 | import java.util.Properties; 9 | 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | import com.mojang.brigadier.StringReader; 13 | import com.mojang.brigadier.arguments.BoolArgumentType; 14 | 15 | import net.minecraft.util.Identifier; 16 | import thecsdev.chunkcopy.ChunkCopy; 17 | 18 | /** 19 | * Manages the mod's configuration.
20 | * STILL UNDER CONSTRUCTION... 21 | */ 22 | public final class ChunkCopyConfig 23 | { 24 | // ================================================== 25 | public static final ConfigKey PASTE_ENTITIES = new ConfigKey(ChunkCopy.getModID(), "paste_entities", BoolArgumentType.bool()); 26 | // ================================================== 27 | /** 28 | * The main {@link Properties} object that holds all of the mod's properties. 29 | */ 30 | private static final Properties PROPERTIES = new Properties(); 31 | // -------------------------------------------------- 32 | /** 33 | * Contains the property keys for the {@link ChunkCopyConfig}. 34 | */ 35 | public static final HashSet> KEYS = new HashSet>(); 36 | // ================================================== 37 | /** 38 | * Returns the file where the {@link ChunkCopyConfig} is saved and loaded. 39 | */ 40 | public static File getPropertiesFile() 41 | { 42 | return new File(ChunkCopy.getRunDirectory().getAbsolutePath() + 43 | "/config/" + ChunkCopy.ModID + ".properties"); 44 | } 45 | // -------------------------------------------------- 46 | /** 47 | * Saves the config properties to it's save file. 48 | */ 49 | public static boolean saveConfig() 50 | { 51 | FileOutputStream fos = null; 52 | try 53 | { 54 | File file = getPropertiesFile(); 55 | file.getParentFile().mkdirs(); 56 | file.createNewFile(); 57 | 58 | fos = new FileOutputStream(file); 59 | PROPERTIES.store(fos, ChunkCopy.ModName + " config"); 60 | 61 | return true; 62 | } 63 | catch (IOException e) { return false; } 64 | finally 65 | { 66 | if(fos != null) 67 | try { fos.close(); } catch(Exception e) {} 68 | } 69 | } 70 | // -------------------------------------------------- 71 | /** 72 | * Loads the config properties from it's save file. 73 | */ 74 | public static boolean loadConfig() 75 | { 76 | FileInputStream fis = null; 77 | try 78 | { 79 | File file = getPropertiesFile(); 80 | file.getParentFile().mkdirs(); 81 | file.createNewFile(); 82 | 83 | fis = new FileInputStream(file); 84 | PROPERTIES.load(fis); 85 | 86 | return true; 87 | } 88 | catch (IOException e) { return false; } 89 | finally 90 | { 91 | if(fis != null) 92 | try { fis.close(); } catch(Exception e) {} 93 | } 94 | } 95 | // -------------------------------------------------- 96 | /** 97 | * Returns a {@link ConfigKey} from the {@link #KEYS} 98 | * list using it's name (aka {@link Identifier}). 99 | */ 100 | @Nullable 101 | public static ConfigKey getKeyByName(Identifier keyName) 102 | { 103 | try { return KEYS.stream().filter(i -> i.keyName.compareTo(keyName) == 0).findFirst().get(); } 104 | catch(Exception e) { return null; } 105 | } 106 | // ================================================== 107 | /** 108 | * Gets the value of a property. 109 | * @param key The property key. 110 | * @param defaultValue The value that will be returned if the key 111 | * isn't listed or the value is undefined. 112 | */ 113 | public static T get(ConfigKey key, T defaultValue) 114 | { 115 | try 116 | { 117 | String value = PROPERTIES.getProperty(key.keyName.toString()); 118 | StringReader sr = new StringReader(value); 119 | return key.argumentType.parse(sr); 120 | } 121 | catch(Exception e) { return defaultValue; } 122 | } 123 | 124 | /** 125 | * Sets the value of a property. 126 | * @param key The property key. 127 | * @param value The value that the property will be set to. 128 | */ 129 | public static void set(ConfigKey key, T value) 130 | { 131 | PROPERTIES.setProperty(key.keyName.toString(), key.valueToString(value)); 132 | } 133 | // ================================================== 134 | } -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/java/thecsdev/chunkcopy/api/config/ChunkCopyConfig.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.api.config; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileOutputStream; 6 | import java.io.IOException; 7 | import java.util.HashSet; 8 | import java.util.Properties; 9 | 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | import com.mojang.brigadier.StringReader; 13 | import com.mojang.brigadier.arguments.BoolArgumentType; 14 | 15 | import net.minecraft.util.Identifier; 16 | import thecsdev.chunkcopy.ChunkCopy; 17 | 18 | /** 19 | * Manages the mod's configuration.
20 | * STILL UNDER CONSTRUCTION... 21 | */ 22 | public final class ChunkCopyConfig 23 | { 24 | // ================================================== 25 | public static final ConfigKey PASTE_ENTITIES = new ConfigKey(ChunkCopy.getModID(), "paste_entities", BoolArgumentType.bool()); 26 | // ================================================== 27 | /** 28 | * The main {@link Properties} object that holds all of the mod's properties. 29 | */ 30 | private static final Properties PROPERTIES = new Properties(); 31 | // -------------------------------------------------- 32 | /** 33 | * Contains the property keys for the {@link ChunkCopyConfig}. 34 | */ 35 | public static final HashSet> KEYS = new HashSet>(); 36 | // ================================================== 37 | /** 38 | * Returns the file where the {@link ChunkCopyConfig} is saved and loaded. 39 | */ 40 | public static File getPropertiesFile() 41 | { 42 | return new File(ChunkCopy.getRunDirectory().getAbsolutePath() + 43 | "/config/" + ChunkCopy.ModID + ".properties"); 44 | } 45 | // -------------------------------------------------- 46 | /** 47 | * Saves the config properties to it's save file. 48 | */ 49 | public static boolean saveConfig() 50 | { 51 | FileOutputStream fos = null; 52 | try 53 | { 54 | File file = getPropertiesFile(); 55 | file.getParentFile().mkdirs(); 56 | file.createNewFile(); 57 | 58 | fos = new FileOutputStream(file); 59 | PROPERTIES.store(fos, ChunkCopy.ModName + " config"); 60 | 61 | return true; 62 | } 63 | catch (IOException e) { return false; } 64 | finally 65 | { 66 | if(fos != null) 67 | try { fos.close(); } catch(Exception e) {} 68 | } 69 | } 70 | // -------------------------------------------------- 71 | /** 72 | * Loads the config properties from it's save file. 73 | */ 74 | public static boolean loadConfig() 75 | { 76 | FileInputStream fis = null; 77 | try 78 | { 79 | File file = getPropertiesFile(); 80 | file.getParentFile().mkdirs(); 81 | file.createNewFile(); 82 | 83 | fis = new FileInputStream(file); 84 | PROPERTIES.load(fis); 85 | 86 | return true; 87 | } 88 | catch (IOException e) { return false; } 89 | finally 90 | { 91 | if(fis != null) 92 | try { fis.close(); } catch(Exception e) {} 93 | } 94 | } 95 | // -------------------------------------------------- 96 | /** 97 | * Returns a {@link ConfigKey} from the {@link #KEYS} 98 | * list using it's name (aka {@link Identifier}). 99 | */ 100 | @Nullable 101 | public static ConfigKey getKeyByName(Identifier keyName) 102 | { 103 | try { return KEYS.stream().filter(i -> i.keyName.compareTo(keyName) == 0).findFirst().get(); } 104 | catch(Exception e) { return null; } 105 | } 106 | // ================================================== 107 | /** 108 | * Gets the value of a property. 109 | * @param key The property key. 110 | * @param defaultValue The value that will be returned if the key 111 | * isn't listed or the value is undefined. 112 | */ 113 | public static T get(ConfigKey key, T defaultValue) 114 | { 115 | try 116 | { 117 | String value = PROPERTIES.getProperty(key.keyName.toString()); 118 | StringReader sr = new StringReader(value); 119 | return key.argumentType.parse(sr); 120 | } 121 | catch(Exception e) { return defaultValue; } 122 | } 123 | 124 | /** 125 | * Sets the value of a property. 126 | * @param key The property key. 127 | * @param value The value that the property will be set to. 128 | */ 129 | public static void set(ConfigKey key, T value) 130 | { 131 | PROPERTIES.setProperty(key.keyName.toString(), key.valueToString(value)); 132 | } 133 | // ================================================== 134 | } -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/java/thecsdev/chunkcopy/api/io/IOUtils.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.api.io; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.io.OutputStream; 8 | import java.util.stream.Stream; 9 | import java.util.zip.GZIPInputStream; 10 | import java.util.zip.GZIPOutputStream; 11 | 12 | import thecsdev.chunkcopy.api.ChunkCopyAPI; 13 | 14 | /** 15 | * A utility class for {@link ChunkCopyAPI}'s IO based operations. 16 | */ 17 | public class IOUtils 18 | { 19 | // ================================================== 20 | /** 21 | * Reads an LEB-128 Variable Length Quantity integer from a stream.
22 | * More info can be found here: https://wiki.vg/Protocol#VarInt_and_VarLong 23 | * @param stream The {@link InputStream} to read an integer from. 24 | * @throws IOException If an {@link IOException} occurs while reading an integer. 25 | */ 26 | public static int readVarInt(InputStream stream) throws IOException 27 | { 28 | int value = 0; 29 | int length = 0; 30 | byte currentByte; 31 | 32 | while (true) 33 | { 34 | int nextByte = stream.read(); 35 | if(nextByte < 0) break; //throw new IOException("End of stream."); --nah 36 | 37 | currentByte = (byte)nextByte; 38 | value |= (currentByte & 0x7F) << (length * 7); 39 | 40 | length += 1; 41 | if (length > 5) { throw new IOException("VarInt is too big"); } 42 | 43 | if ((currentByte & 0x80) != 0x80) { break; } 44 | } 45 | return value; 46 | } 47 | //--------------------------------------------------- 48 | /** 49 | * Writes an LEB-128 Variable Length Quantity integer to a stream.
50 | * More info can be found here: https://wiki.vg/Protocol#VarInt_and_VarLong 51 | * @throws IOException If an {@link IOException} occurs while writing an integer. 52 | */ 53 | public static void writeVarInt(OutputStream stream, int value) throws IOException 54 | { 55 | while (true) 56 | { 57 | if ((value & ~0x7F) == 0) 58 | { 59 | stream.write(value); 60 | return; 61 | } 62 | 63 | stream.write((value & 0x7F) | 0x80); 64 | // Note: >>> means that the sign bit is shifted with the rest of the number 65 | // rather than being left alone 66 | value >>>= 7; 67 | } 68 | } 69 | // ================================================== 70 | /** 71 | * Reads a {@link String} from an {@link InputStream}. 72 | * @param stream The {@link InputStream} to read a {@link String} from. 73 | */ 74 | public static String readString(InputStream stream) throws IOException 75 | { 76 | int length = readVarInt(stream); 77 | return new String(stream.readNBytes(length), "UTF-8"); 78 | } 79 | //--------------------------------------------------- 80 | /** 81 | * Writes a {@link String} to an {@link OutputStream}. 82 | * @param stream The {@link OutputStream} to write a {@link String} to. 83 | * @param value The {@link String} to write. 84 | */ 85 | public static void writeString(OutputStream stream, String value) throws IOException 86 | { 87 | byte[] bytes = value.getBytes("UTF-8"); 88 | writeVarInt(stream, bytes.length); 89 | stream.write(bytes); 90 | } 91 | // ================================================== 92 | public static byte[] readByteArray(InputStream stream) throws IOException 93 | { 94 | int len = readVarInt(stream); 95 | return stream.readNBytes(len); 96 | } 97 | // -------------------------------------------------- 98 | public static void writeByteArray(OutputStream stream, byte[] bytes) throws IOException 99 | { 100 | writeVarInt(stream, bytes.length); 101 | stream.write(bytes); 102 | } 103 | // ================================================== 104 | /** 105 | * Compresses a byte array using the GZip compression algorithm. 106 | * @param bytes The bytes (data) to compress. 107 | * @throws IOException If an {@link IOException} occurs while compressing the bytes. 108 | */ 109 | public static byte[] gzipCompressBytes(byte[] bytes) throws IOException 110 | { 111 | ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); 112 | GZIPOutputStream gzip = new GZIPOutputStream(bytesOut); 113 | gzip.write(bytes); 114 | gzip.close(); 115 | bytes = bytesOut.toByteArray(); 116 | bytesOut.close(); 117 | return bytes; 118 | } 119 | // -------------------------------------------------- 120 | /** 121 | * Decompresses a byte array using the GZip compression algorithm. 122 | * @param bytes The bytes (data) to decompress. 123 | * @throws IOException If an {@link IOException} occurs while decompressing the bytes. 124 | */ 125 | public static byte[] gzipDecompressBytes(byte[] bytes) throws IOException 126 | { 127 | ByteArrayInputStream bytesIn = new ByteArrayInputStream(bytes); 128 | GZIPInputStream gzipIn = new GZIPInputStream(bytesIn); 129 | bytes = gzipIn.readAllBytes(); 130 | gzipIn.close(); 131 | bytesIn.close(); 132 | return bytes; 133 | } 134 | // ================================================== 135 | /** 136 | * Returns true if a class has a constructor with no parameters. 137 | */ 138 | public static boolean classHasParameterlessConstructor(Class clazz) 139 | { 140 | return Stream.of(clazz.getConstructors()).anyMatch((c) -> c.getParameterCount() == 0); 141 | } 142 | // ================================================== 143 | } 144 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/java/thecsdev/chunkcopy/api/io/IOUtils.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.api.io; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.io.OutputStream; 8 | import java.util.stream.Stream; 9 | import java.util.zip.GZIPInputStream; 10 | import java.util.zip.GZIPOutputStream; 11 | 12 | import thecsdev.chunkcopy.api.ChunkCopyAPI; 13 | 14 | /** 15 | * A utility class for {@link ChunkCopyAPI}'s IO based operations. 16 | */ 17 | public class IOUtils 18 | { 19 | // ================================================== 20 | /** 21 | * Reads an LEB-128 Variable Length Quantity integer from a stream.
22 | * More info can be found here: https://wiki.vg/Protocol#VarInt_and_VarLong 23 | * @param stream The {@link InputStream} to read an integer from. 24 | * @throws IOException If an {@link IOException} occurs while reading an integer. 25 | */ 26 | public static int readVarInt(InputStream stream) throws IOException 27 | { 28 | int value = 0; 29 | int length = 0; 30 | byte currentByte; 31 | 32 | while (true) 33 | { 34 | int nextByte = stream.read(); 35 | if(nextByte < 0) break; //throw new IOException("End of stream."); --nah 36 | 37 | currentByte = (byte)nextByte; 38 | value |= (currentByte & 0x7F) << (length * 7); 39 | 40 | length += 1; 41 | if (length > 5) { throw new IOException("VarInt is too big"); } 42 | 43 | if ((currentByte & 0x80) != 0x80) { break; } 44 | } 45 | return value; 46 | } 47 | //--------------------------------------------------- 48 | /** 49 | * Writes an LEB-128 Variable Length Quantity integer to a stream.
50 | * More info can be found here: https://wiki.vg/Protocol#VarInt_and_VarLong 51 | * @throws IOException If an {@link IOException} occurs while writing an integer. 52 | */ 53 | public static void writeVarInt(OutputStream stream, int value) throws IOException 54 | { 55 | while (true) 56 | { 57 | if ((value & ~0x7F) == 0) 58 | { 59 | stream.write(value); 60 | return; 61 | } 62 | 63 | stream.write((value & 0x7F) | 0x80); 64 | // Note: >>> means that the sign bit is shifted with the rest of the number 65 | // rather than being left alone 66 | value >>>= 7; 67 | } 68 | } 69 | // ================================================== 70 | /** 71 | * Reads a {@link String} from an {@link InputStream}. 72 | * @param stream The {@link InputStream} to read a {@link String} from. 73 | */ 74 | public static String readString(InputStream stream) throws IOException 75 | { 76 | int length = readVarInt(stream); 77 | return new String(stream.readNBytes(length), "UTF-8"); 78 | } 79 | //--------------------------------------------------- 80 | /** 81 | * Writes a {@link String} to an {@link OutputStream}. 82 | * @param stream The {@link OutputStream} to write a {@link String} to. 83 | * @param value The {@link String} to write. 84 | */ 85 | public static void writeString(OutputStream stream, String value) throws IOException 86 | { 87 | byte[] bytes = value.getBytes("UTF-8"); 88 | writeVarInt(stream, bytes.length); 89 | stream.write(bytes); 90 | } 91 | // ================================================== 92 | public static byte[] readByteArray(InputStream stream) throws IOException 93 | { 94 | int len = readVarInt(stream); 95 | return stream.readNBytes(len); 96 | } 97 | // -------------------------------------------------- 98 | public static void writeByteArray(OutputStream stream, byte[] bytes) throws IOException 99 | { 100 | writeVarInt(stream, bytes.length); 101 | stream.write(bytes); 102 | } 103 | // ================================================== 104 | /** 105 | * Compresses a byte array using the GZip compression algorithm. 106 | * @param bytes The bytes (data) to compress. 107 | * @throws IOException If an {@link IOException} occurs while compressing the bytes. 108 | */ 109 | public static byte[] gzipCompressBytes(byte[] bytes) throws IOException 110 | { 111 | ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); 112 | GZIPOutputStream gzip = new GZIPOutputStream(bytesOut); 113 | gzip.write(bytes); 114 | gzip.close(); 115 | bytes = bytesOut.toByteArray(); 116 | bytesOut.close(); 117 | return bytes; 118 | } 119 | // -------------------------------------------------- 120 | /** 121 | * Decompresses a byte array using the GZip compression algorithm. 122 | * @param bytes The bytes (data) to decompress. 123 | * @throws IOException If an {@link IOException} occurs while decompressing the bytes. 124 | */ 125 | public static byte[] gzipDecompressBytes(byte[] bytes) throws IOException 126 | { 127 | ByteArrayInputStream bytesIn = new ByteArrayInputStream(bytes); 128 | GZIPInputStream gzipIn = new GZIPInputStream(bytesIn); 129 | bytes = gzipIn.readAllBytes(); 130 | gzipIn.close(); 131 | bytesIn.close(); 132 | return bytes; 133 | } 134 | // ================================================== 135 | /** 136 | * Returns true if a class has a constructor with no parameters. 137 | */ 138 | public static boolean classHasParameterlessConstructor(Class clazz) 139 | { 140 | return Stream.of(clazz.getConstructors()).anyMatch((c) -> c.getParameterCount() == 0); 141 | } 142 | // ================================================== 143 | } 144 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/java/thecsdev/chunkcopy/api/data/block/CDBBlocksLegacy.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.api.data.block; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.OutputStream; 6 | import java.util.ArrayList; 7 | import java.util.BitSet; 8 | 9 | import net.minecraft.block.Block; 10 | import net.minecraft.block.BlockState; 11 | import net.minecraft.network.packet.s2c.play.ChunkDataS2CPacket; 12 | import net.minecraft.server.world.ServerWorld; 13 | import net.minecraft.util.math.BlockPos; 14 | import net.minecraft.util.math.ChunkPos; 15 | import net.minecraft.world.World; 16 | import net.minecraft.world.chunk.ChunkSection; 17 | import net.minecraft.world.chunk.WorldChunk; 18 | import net.minecraft.world.chunk.light.LightingProvider; 19 | import thecsdev.chunkcopy.ChunkCopy; 20 | import thecsdev.chunkcopy.api.data.ChunkDataBlock; 21 | import thecsdev.chunkcopy.api.data.ChunkDataBlockID; 22 | import thecsdev.chunkcopy.api.io.IOUtils; 23 | 24 | /** 25 | * A legacy {@link ChunkDataBlock} that contains information about world chunk blocks.
26 | *
27 | * Obsolete because of how im-performant (slow) it is. Use {@link CDBChunkSections} instead. 28 | */ 29 | @ChunkDataBlockID(namespace = ChunkCopy.ModID, path = "blocks_legacy") 30 | public class CDBBlocksLegacy extends ChunkDataBlock 31 | { 32 | // ================================================== 33 | /** 34 | * Defines the bottom Y level of the chunk. 35 | * This is the Y level of bedrock. 36 | */ 37 | public int StartY = 0; 38 | 39 | /** 40 | * The array of copied blocks. 41 | */ 42 | public final ArrayList BlockIDs = new ArrayList(); 43 | // ================================================== 44 | @Deprecated(forRemoval = true, since = "v2.0.0") 45 | @Override 46 | public void copyData(World world, ChunkPos chunkPos) 47 | { 48 | WorldChunk chunk = world.getChunk(chunkPos.x, chunkPos.z); 49 | int chunkWidthX = Math.abs(chunkPos.getEndX() - chunkPos.getStartX()); 50 | int chunkWidthZ = Math.abs(chunkPos.getEndZ() - chunkPos.getStartZ()); 51 | 52 | //Start Y 53 | StartY = chunk.getBottomY(); 54 | 55 | //Block IDs 56 | BlockIDs.clear(); 57 | int x = 0, y = chunk.getBottomY(), z = 0; 58 | while(y < chunk.getTopY() + 1) 59 | { 60 | //handle block 61 | BlockPos blockPos = chunk.getPos().getBlockPos(x, y, z); 62 | BlockState blockState = chunk.getBlockState(blockPos); 63 | BlockIDs.add(Block.getRawIdFromState(blockState)); 64 | 65 | //increment 66 | x++; 67 | if(x > chunkWidthX) 68 | { 69 | z++; x = 0; 70 | if(z > chunkWidthZ) { y++; z = 0; } 71 | } 72 | } 73 | } 74 | // -------------------------------------------------- 75 | @Deprecated(forRemoval = true, since = "v2.0.0") 76 | @Override 77 | public void pasteData(ServerWorld world, ChunkPos chunkPos) 78 | { 79 | WorldChunk chunk = world.getChunk(chunkPos.x, chunkPos.z); 80 | int chunkWidthX = Math.abs(chunkPos.getEndX() - chunkPos.getStartX()); 81 | int chunkWidthZ = Math.abs(chunkPos.getEndZ() - chunkPos.getStartZ()); 82 | 83 | //iterate all block IDs 84 | int x = 0, y = StartY, z = 0; 85 | for (int blockID : BlockIDs) 86 | { 87 | //break if too high 88 | if(y > chunk.getTopY()) break; 89 | 90 | //handle block 91 | try 92 | { 93 | do 94 | { 95 | //ignore blocks below bedrock and above build limit 96 | if(y < chunk.getBottomY() || y > chunk.getTopY()) 97 | break; 98 | 99 | //get state, section, and local coords 100 | BlockState state = Block.getStateFromRawId(blockID); 101 | if(state.hasBlockEntity()) break; 102 | 103 | ChunkSection toChunkSection = chunk.getSection(chunk.getSectionIndex(y)); 104 | toChunkSection.setBlockState(x, y & 0xF, z, state); 105 | } 106 | while(false); 107 | } 108 | catch (Exception e) { break; } 109 | 110 | //increment 111 | x++; 112 | if(x > chunkWidthX) 113 | { 114 | z++; x = 0; 115 | if(z > chunkWidthZ) { y++; z = 0; } 116 | } 117 | } 118 | 119 | //mark as needs saving 120 | chunk.setNeedsSaving(true); 121 | } 122 | // -------------------------------------------------- 123 | @Override 124 | public void updateClients(ServerWorld world, ChunkPos chunkPos) 125 | { 126 | ChunkDataS2CPacket chunkData = makeMeAChunkDataPacketPls(world, chunkPos); 127 | world.getPlayers().forEach(p -> p.networkHandler.sendPacket(chunkData)); 128 | } 129 | // ================================================== 130 | @Override 131 | public void readData(InputStream stream) throws IOException 132 | { 133 | //read StartY 134 | StartY = IOUtils.readVarInt(stream); 135 | 136 | //read blocks 137 | BlockIDs.clear(); 138 | while(stream.available() > 0) 139 | { 140 | try { BlockIDs.add(IOUtils.readVarInt(stream)); } 141 | catch(IOException e) {} 142 | } 143 | } 144 | // -------------------------------------------------- 145 | @Override 146 | public void writeData(OutputStream stream) throws IOException 147 | { 148 | //write StartY 149 | IOUtils.writeVarInt(stream, StartY); 150 | 151 | //write blocks 152 | for (Integer blockId : BlockIDs) { IOUtils.writeVarInt(stream, blockId); } 153 | } 154 | // ================================================== 155 | //i didn't know what else to name this method so whatever 156 | private static ChunkDataS2CPacket makeMeAChunkDataPacketPls(World world, ChunkPos chunkPos) 157 | { 158 | WorldChunk wchunk = world.getChunk(chunkPos.x, chunkPos.z); 159 | LightingProvider lp = world.getLightingProvider(); 160 | BitSet skyBits = new BitSet(0); 161 | BitSet blockBits = new BitSet(0); 162 | return new ChunkDataS2CPacket(wchunk, lp, skyBits, blockBits, true); 163 | } 164 | // ================================================== 165 | } 166 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/java/thecsdev/chunkcopy/api/data/block/CDBEntityBlocksLegacy.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.api.data.block; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.io.OutputStream; 8 | import java.util.ArrayList; 9 | 10 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 11 | 12 | import net.minecraft.block.Block; 13 | import net.minecraft.block.BlockState; 14 | import net.minecraft.block.entity.BlockEntity; 15 | import net.minecraft.nbt.NbtCompound; 16 | import net.minecraft.nbt.NbtHelper; 17 | import net.minecraft.server.world.ServerWorld; 18 | import net.minecraft.util.math.BlockPos; 19 | import net.minecraft.util.math.ChunkPos; 20 | import net.minecraft.world.World; 21 | import net.minecraft.world.chunk.WorldChunk; 22 | import thecsdev.chunkcopy.ChunkCopy; 23 | import thecsdev.chunkcopy.api.data.ChunkDataBlock; 24 | import thecsdev.chunkcopy.api.data.ChunkDataBlockID; 25 | import thecsdev.chunkcopy.api.io.IOUtils; 26 | 27 | /** 28 | * A {@link ChunkDataBlock} that contains information about world chunk entity blocks. 29 | */ 30 | @ChunkDataBlockID(namespace = ChunkCopy.ModID, path = "entity_blocks_legacy") 31 | public class CDBEntityBlocksLegacy extends ChunkDataBlock 32 | { 33 | // ================================================== 34 | public final ArrayList BlockEntities = new ArrayList(); 35 | // ================================================== 36 | @Override 37 | public void copyData(World world, ChunkPos chunkPos) 38 | { 39 | //clear old data 40 | BlockEntities.clear(); 41 | 42 | //paste new data 43 | WorldChunk chunk = world.getChunk(chunkPos.x, chunkPos.z); 44 | for (BlockPos eBlockPos : chunk.getBlockEntityPositions()) 45 | { 46 | BlockState eBlockState = chunk.getBlockState(eBlockPos); 47 | BlockEntity eBlock = chunk.getBlockEntity(eBlockPos); 48 | 49 | CDBEntityBlock cdbBlock = new CDBEntityBlock(); 50 | cdbBlock.x = eBlockPos.getX(); 51 | cdbBlock.y = eBlockPos.getY(); 52 | cdbBlock.z = eBlockPos.getZ(); 53 | cdbBlock.blockId = Block.getRawIdFromState(eBlockState); 54 | cdbBlock.nbtData = eBlock.createNbtWithIdentifyingData(); 55 | 56 | BlockEntities.add(cdbBlock); 57 | } 58 | } 59 | // -------------------------------------------------- 60 | @Override 61 | public void pasteData(ServerWorld world, ChunkPos chunkPos) 62 | { 63 | //iterate entity blocks 64 | WorldChunk chunk = world.getChunk(chunkPos.x, chunkPos.z); 65 | for (CDBEntityBlock cdbBlock : BlockEntities) 66 | { 67 | BlockPos eBlockPos = new BlockPos(cdbBlock.x, cdbBlock.y, cdbBlock.z); 68 | BlockState eBlockState = Block.getStateFromRawId(cdbBlock.blockId); 69 | 70 | if(!eBlockState.isAir() && cdbBlock.nbtData != null) 71 | { 72 | chunk.setBlockState(eBlockPos, eBlockState, false); 73 | chunk.setBlockEntity(BlockEntity.createFromNbt(eBlockPos, eBlockState, cdbBlock.nbtData)); 74 | } 75 | } 76 | 77 | //mark chunk as needs saving 78 | chunk.setShouldSave(true); 79 | } 80 | // -------------------------------------------------- 81 | @Override 82 | public void updateClients(ServerWorld world, ChunkPos chunkPos) 83 | { 84 | //no need to do this, chunk.setBlockEntity(...) will do this for us. 85 | } 86 | // ================================================== 87 | @Override 88 | public void readData(InputStream stream) throws IOException 89 | { 90 | //clear old data 91 | BlockEntities.clear(); 92 | 93 | //keep reading chunks 94 | while(stream.available() > 0) 95 | { 96 | int len = IOUtils.readVarInt(stream); 97 | byte[] bytes = stream.readNBytes(len); 98 | 99 | CDBEntityBlock cdbBlock = new CDBEntityBlock(); 100 | cdbBlock.readByteArray(bytes); 101 | BlockEntities.add(cdbBlock); 102 | } 103 | } 104 | // -------------------------------------------------- 105 | @Override 106 | public void writeData(OutputStream stream) throws IOException 107 | { 108 | //iterate each copied entity block 109 | for (CDBEntityBlock cdbBlock : BlockEntities) 110 | { 111 | //write 112 | byte[] bytes = cdbBlock.toByteArray(); 113 | IOUtils.writeVarInt(stream, bytes.length); 114 | stream.write(bytes); 115 | } 116 | } 117 | // ================================================== 118 | /** 119 | * A class that contains information 120 | * about a copied entity block. 121 | */ 122 | public class CDBEntityBlock 123 | { 124 | // --------------------------------- 125 | public int x, y, z; 126 | public int blockId; 127 | public NbtCompound nbtData; 128 | // --------------------------------- 129 | public byte[] toByteArray() throws IOException 130 | { 131 | if(nbtData == null) nbtData = new NbtCompound(); 132 | 133 | ByteArrayOutputStream stream = new ByteArrayOutputStream(); 134 | IOUtils.writeVarInt(stream, x); 135 | IOUtils.writeVarInt(stream, y); 136 | IOUtils.writeVarInt(stream, z); 137 | IOUtils.writeVarInt(stream, blockId); 138 | IOUtils.writeString(stream, NbtHelper.toNbtProviderString(nbtData)); 139 | 140 | byte[] bytes = stream.toByteArray(); 141 | stream.close(); 142 | return bytes; 143 | } 144 | // --------------------------------- 145 | public void readByteArray(byte[] bytes) throws IOException 146 | { 147 | ByteArrayInputStream stream = new ByteArrayInputStream(bytes); 148 | x = IOUtils.readVarInt(stream); 149 | y = IOUtils.readVarInt(stream); 150 | z = IOUtils.readVarInt(stream); 151 | blockId = IOUtils.readVarInt(stream); 152 | try { nbtData = NbtHelper.fromNbtProviderString(IOUtils.readString(stream)); } 153 | catch(CommandSyntaxException e) { throw new IOException("Invalid or corrupted BlockEntity NBT data."); } 154 | } 155 | // --------------------------------- 156 | } 157 | // ================================================== 158 | } 159 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/java/thecsdev/chunkcopy/api/data/block/CDBEntityBlocksLegacy.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.api.data.block; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.io.OutputStream; 8 | import java.util.ArrayList; 9 | 10 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 11 | 12 | import net.minecraft.block.Block; 13 | import net.minecraft.block.BlockState; 14 | import net.minecraft.block.entity.BlockEntity; 15 | import net.minecraft.nbt.NbtCompound; 16 | import net.minecraft.nbt.NbtHelper; 17 | import net.minecraft.server.world.ServerWorld; 18 | import net.minecraft.util.math.BlockPos; 19 | import net.minecraft.util.math.ChunkPos; 20 | import net.minecraft.world.World; 21 | import net.minecraft.world.chunk.WorldChunk; 22 | import thecsdev.chunkcopy.ChunkCopy; 23 | import thecsdev.chunkcopy.api.data.ChunkDataBlock; 24 | import thecsdev.chunkcopy.api.data.ChunkDataBlockID; 25 | import thecsdev.chunkcopy.api.io.IOUtils; 26 | 27 | /** 28 | * A {@link ChunkDataBlock} that contains information about world chunk entity blocks. 29 | */ 30 | @ChunkDataBlockID(namespace = ChunkCopy.ModID, path = "entity_blocks_legacy") 31 | public class CDBEntityBlocksLegacy extends ChunkDataBlock 32 | { 33 | // ================================================== 34 | public final ArrayList BlockEntities = new ArrayList(); 35 | // ================================================== 36 | @Override 37 | public void copyData(World world, ChunkPos chunkPos) 38 | { 39 | //clear old data 40 | BlockEntities.clear(); 41 | 42 | //paste new data 43 | WorldChunk chunk = world.getChunk(chunkPos.x, chunkPos.z); 44 | for (BlockPos eBlockPos : chunk.getBlockEntityPositions()) 45 | { 46 | BlockState eBlockState = chunk.getBlockState(eBlockPos); 47 | BlockEntity eBlock = chunk.getBlockEntity(eBlockPos); 48 | 49 | CDBEntityBlock cdbBlock = new CDBEntityBlock(); 50 | cdbBlock.x = eBlockPos.getX(); 51 | cdbBlock.y = eBlockPos.getY(); 52 | cdbBlock.z = eBlockPos.getZ(); 53 | cdbBlock.blockId = Block.getRawIdFromState(eBlockState); 54 | cdbBlock.nbtData = eBlock.createNbtWithIdentifyingData(); 55 | 56 | BlockEntities.add(cdbBlock); 57 | } 58 | } 59 | // -------------------------------------------------- 60 | @Override 61 | public void pasteData(ServerWorld world, ChunkPos chunkPos) 62 | { 63 | //iterate entity blocks 64 | WorldChunk chunk = world.getChunk(chunkPos.x, chunkPos.z); 65 | for (CDBEntityBlock cdbBlock : BlockEntities) 66 | { 67 | BlockPos eBlockPos = new BlockPos(cdbBlock.x, cdbBlock.y, cdbBlock.z); 68 | BlockState eBlockState = Block.getStateFromRawId(cdbBlock.blockId); 69 | 70 | if(!eBlockState.isAir() && cdbBlock.nbtData != null) 71 | { 72 | chunk.setBlockState(eBlockPos, eBlockState, false); 73 | chunk.setBlockEntity(BlockEntity.createFromNbt(eBlockPos, eBlockState, cdbBlock.nbtData)); 74 | } 75 | } 76 | 77 | //mark chunk as needs saving 78 | chunk.setNeedsSaving(true); 79 | } 80 | // -------------------------------------------------- 81 | @Override 82 | public void updateClients(ServerWorld world, ChunkPos chunkPos) 83 | { 84 | //no need to do this, chunk.setBlockEntity(...) will do this for us. 85 | } 86 | // ================================================== 87 | @Override 88 | public void readData(InputStream stream) throws IOException 89 | { 90 | //clear old data 91 | BlockEntities.clear(); 92 | 93 | //keep reading chunks 94 | while(stream.available() > 0) 95 | { 96 | int len = IOUtils.readVarInt(stream); 97 | byte[] bytes = stream.readNBytes(len); 98 | 99 | CDBEntityBlock cdbBlock = new CDBEntityBlock(); 100 | cdbBlock.readByteArray(bytes); 101 | BlockEntities.add(cdbBlock); 102 | } 103 | } 104 | // -------------------------------------------------- 105 | @Override 106 | public void writeData(OutputStream stream) throws IOException 107 | { 108 | //iterate each copied entity block 109 | for (CDBEntityBlock cdbBlock : BlockEntities) 110 | { 111 | //write 112 | byte[] bytes = cdbBlock.toByteArray(); 113 | IOUtils.writeVarInt(stream, bytes.length); 114 | stream.write(bytes); 115 | } 116 | } 117 | // ================================================== 118 | /** 119 | * A class that contains information 120 | * about a copied entity block. 121 | */ 122 | public class CDBEntityBlock 123 | { 124 | // --------------------------------- 125 | public int x, y, z; 126 | public int blockId; 127 | public NbtCompound nbtData; 128 | // --------------------------------- 129 | public byte[] toByteArray() throws IOException 130 | { 131 | if(nbtData == null) nbtData = new NbtCompound(); 132 | 133 | ByteArrayOutputStream stream = new ByteArrayOutputStream(); 134 | IOUtils.writeVarInt(stream, x); 135 | IOUtils.writeVarInt(stream, y); 136 | IOUtils.writeVarInt(stream, z); 137 | IOUtils.writeVarInt(stream, blockId); 138 | IOUtils.writeString(stream, NbtHelper.toNbtProviderString(nbtData)); 139 | 140 | byte[] bytes = stream.toByteArray(); 141 | stream.close(); 142 | return bytes; 143 | } 144 | // --------------------------------- 145 | public void readByteArray(byte[] bytes) throws IOException 146 | { 147 | ByteArrayInputStream stream = new ByteArrayInputStream(bytes); 148 | x = IOUtils.readVarInt(stream); 149 | y = IOUtils.readVarInt(stream); 150 | z = IOUtils.readVarInt(stream); 151 | blockId = IOUtils.readVarInt(stream); 152 | try { nbtData = NbtHelper.fromNbtProviderString(IOUtils.readString(stream)); } 153 | catch(CommandSyntaxException e) { throw new IOException("Invalid or corrupted BlockEntity NBT data."); } 154 | } 155 | // --------------------------------- 156 | } 157 | // ================================================== 158 | } 159 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/java/thecsdev/chunkcopy/server/command/ChunkCopyServerCommand.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.server.command; 2 | 3 | import java.util.ArrayList; 4 | 5 | import net.minecraft.block.BlockState; 6 | import net.minecraft.server.command.ServerCommandSource; 7 | import net.minecraft.server.world.ServerWorld; 8 | import net.minecraft.text.LiteralText; 9 | import net.minecraft.util.math.ChunkPos; 10 | import thecsdev.chunkcopy.api.AutoChunkCopy.ACCMode; 11 | import thecsdev.chunkcopy.api.AutoChunkCopy; 12 | import thecsdev.chunkcopy.api.ChunkCopyAPI; 13 | import thecsdev.chunkcopy.api.ChunkCopyUtils; 14 | import thecsdev.chunkcopy.command.ChunkCopyCommand; 15 | 16 | public final class ChunkCopyServerCommand extends ChunkCopyCommand 17 | { 18 | // ================================================== 19 | @Override 20 | public String getCommandName() { return "chunkcopysrv"; } 21 | // -------------------------------------------------- 22 | @Override 23 | protected boolean canCopy(ServerCommandSource cs) { return isOpAndHuman(cs); } 24 | // -------------------------------------------------- 25 | @Override 26 | protected boolean canPaste(ServerCommandSource cs) { return isOpAndHuman(cs); } 27 | // -------------------------------------------------- 28 | @Override 29 | protected boolean canConfig(ServerCommandSource cs) { return cs.hasPermissionLevel(4); } 30 | // ================================================== 31 | protected void execMain(ServerCommandSource cs) 32 | { 33 | String feedback = "[Chunk Copy] Only operator players can execute this command so " 34 | + "that the mod can know where you wish to copy/paste chunks."; 35 | cs.sendFeedback(new LiteralText(feedback), false); 36 | } 37 | // -------------------------------------------------- 38 | @Override 39 | protected void copy(ServerCommandSource commandSource, String fileName, int chunkDistance) 40 | { 41 | try 42 | { 43 | //obtain chunks 44 | ServerWorld world = commandSource.getWorld(); 45 | ChunkPos chunkPos = commandSource.getPlayer().getChunkPos(); 46 | ArrayList loadedChunks = ChunkCopyUtils.getNearbyLoadedChunks(world, chunkPos, chunkDistance); 47 | 48 | //copy chunks 49 | int affectedChunks = 0; 50 | for (ChunkPos cp : loadedChunks) 51 | { 52 | ChunkCopyAPI.saveChunkDataIO(world, cp, fileName); 53 | affectedChunks++; 54 | } 55 | 56 | //send feedback 57 | String feedback = String.format("[Chunk Copy] Copied %d chunks to '%s'.", affectedChunks, fileName); 58 | commandSource.sendFeedback(new LiteralText(feedback), true); 59 | } 60 | catch (Exception e) { handleException(commandSource, e); return; } 61 | } 62 | // -------------------------------------------------- 63 | @Override 64 | protected void paste(ServerCommandSource commandSource, String fileName, int chunkDistance) 65 | { 66 | //check if file exists 67 | if(!ChunkCopyAPI.getSaveFileDirectory(fileName).exists()) 68 | { 69 | String feedback = String.format("[Chunk Copy] Unable to paste chunks from '%s', file not found.", fileName); 70 | commandSource.sendFeedback(new LiteralText(feedback), true); 71 | return; 72 | } 73 | 74 | try 75 | { 76 | //obtain chunks 77 | ServerWorld world = commandSource.getWorld(); 78 | ChunkPos chunkPos = commandSource.getPlayer().getChunkPos(); 79 | ArrayList loadedChunks = ChunkCopyUtils.getNearbyLoadedChunks(world, chunkPos, chunkDistance); 80 | 81 | //paste chunks 82 | int affectedChunks = 0; 83 | for (ChunkPos cp : loadedChunks) 84 | { 85 | if(ChunkCopyAPI.loadChunkDataIO(world, cp, fileName)) 86 | affectedChunks++; 87 | } 88 | 89 | //send feedback 90 | String feedback = String.format("[Chunk Copy] Pasted %d chunks from '%s'.", affectedChunks, fileName); 91 | commandSource.sendFeedback(new LiteralText(feedback), true); 92 | } 93 | catch (Exception e) { handleException(commandSource, e); return; } 94 | } 95 | // -------------------------------------------------- 96 | @Override 97 | protected void fill(ServerCommandSource commandSource, int chunkDistance, BlockState block) 98 | { 99 | try 100 | { 101 | //obtain chunks 102 | ServerWorld world = commandSource.getWorld(); 103 | ChunkPos chunkPos = commandSource.getPlayer().getChunkPos(); 104 | ArrayList loadedChunks = ChunkCopyUtils.getNearbyLoadedChunks(world, chunkPos, chunkDistance); 105 | 106 | //fill chunks 107 | int affectedChunks = 0; 108 | for (ChunkPos cp : loadedChunks) 109 | { 110 | ChunkCopyAPI.fillChunkBlocks(world, cp, block); 111 | affectedChunks++; 112 | } 113 | 114 | //send feedback 115 | String bn = block.getBlock().getName().getString(); 116 | String feedback = String.format("[Chunk Copy] Filled %d chunks with '%s'.", affectedChunks, bn); 117 | commandSource.sendFeedback(new LiteralText(feedback), true); 118 | } 119 | catch (Exception e) { handleException(commandSource, e); return; } 120 | } 121 | // -------------------------------------------------- 122 | @Override 123 | protected void autoChunkCopyStart(ServerCommandSource commandSource, String fileName, ACCMode accMode) 124 | { 125 | autoChunkCopyStop(commandSource); 126 | } 127 | 128 | @Override 129 | protected void autoChunkCopyStop(ServerCommandSource commandSource) 130 | { 131 | //send feedback 132 | String feedback = "[Chunk Copy] AutoChunkCopy is not available server-side."; 133 | commandSource.sendFeedback(new LiteralText(feedback), false); 134 | AutoChunkCopy.stop(); 135 | } 136 | // ================================================== 137 | private static boolean isOpAndHuman(ServerCommandSource src) 138 | { 139 | try { return src.getPlayer().hasPermissionLevel(4); } 140 | catch (Exception e) { return false; } 141 | } 142 | // -------------------------------------------------- 143 | /** 144 | * Sends exception feedback. 145 | */ 146 | private void handleException(ServerCommandSource source, Exception e) 147 | { 148 | String feedback = String.format( 149 | "[Chunk Copy] An exception was thrown while executing the command: %s", 150 | "\n" + getExceptionMessage(e)); 151 | source.sendFeedback(new LiteralText(feedback), true); 152 | } 153 | // ================================================== 154 | } 155 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/java/thecsdev/chunkcopy/ChunkCopy.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy; 2 | 3 | import java.io.File; 4 | 5 | import org.jetbrains.annotations.Nullable; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import net.fabricmc.api.EnvType; 10 | import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents; 11 | import net.minecraft.util.math.ChunkPos; 12 | import thecsdev.chunkcopy.api.AutoChunkCopy; 13 | import thecsdev.chunkcopy.api.ChunkCopyAPI; 14 | import thecsdev.chunkcopy.api.config.ChunkCopyConfig; 15 | import thecsdev.chunkcopy.api.data.ChunkData; 16 | import thecsdev.chunkcopy.api.data.block.CDBChunkSections; 17 | import thecsdev.chunkcopy.api.data.block.CDBEntitiesLegacy; 18 | import thecsdev.chunkcopy.api.data.block.CDBEntityBlocksLegacy; 19 | import thecsdev.chunkcopy.client.ChunkCopyClient; 20 | import thecsdev.chunkcopy.command.ChunkCopyCommand; 21 | import thecsdev.chunkcopy.server.ChunkCopyServer; 22 | 23 | /** 24 | * The main ChunkCopy class. This class 25 | * contains vital information about the mod. 26 | */ 27 | public abstract class ChunkCopy 28 | { 29 | // ================================================== 30 | private static ChunkCopy Instance = null; 31 | // -------------------------------------------------- 32 | public static final Logger LOGGER = LoggerFactory.getLogger(getModID()); 33 | // -------------------------------------------------- 34 | public static final String ModName = "Chunk Copy"; 35 | public static final String ModID = "chunkcopy"; 36 | public static final int FileVersion = 759; 37 | // ================================================== 38 | public ChunkCopy() 39 | { 40 | //check if there already is an instance 41 | if(validateInstance()) 42 | throw new RuntimeException("An instance of ChunkCopy already exists."); 43 | 44 | //define Instance 45 | Instance = this; 46 | 47 | //log stuff 48 | LOGGER.info("Initializing '" + getModName() + "' as '" + getClass().getSimpleName() + "'."); 49 | 50 | //register config keys and load the config -- work in progress 51 | ChunkCopyConfig.KEYS.add(ChunkCopyConfig.PASTE_ENTITIES); 52 | //ChunkCopyConfig.loadConfig(); 53 | 54 | //handle API registrations 55 | ChunkData.registerChunkDataBlockType(CDBChunkSections.class); 56 | ChunkData.registerChunkDataBlockType(CDBEntityBlocksLegacy.class); 57 | ChunkData.registerChunkDataBlockType(CDBEntitiesLegacy.class); 58 | 59 | //register auto-paste handler 60 | ServerChunkEvents.CHUNK_LOAD.register((sWorld, sChunk) -> 61 | { 62 | //check if auto-copy is pasting 63 | if(!AutoChunkCopy.isPasting()) return; 64 | final ChunkPos scPos = sChunk.getPos(); 65 | 66 | //convert the action into a task 67 | final Runnable task = () -> 68 | { 69 | try 70 | { 71 | //paste data into the chunk 72 | final String fileName = AutoChunkCopy.getFileName(); 73 | ChunkCopyAPI.loadChunkDataIO(sWorld, sChunk.getPos(), fileName); 74 | } 75 | catch(Exception exc) {} 76 | }; 77 | 78 | //run the task 79 | new Thread(() -> 80 | { 81 | try 82 | { 83 | //wait a bit for the chunk to be fully ready 84 | Thread.sleep(500); 85 | 86 | //make sure the chunk is fully ready 87 | while(!sWorld.isChunkLoaded(scPos.x, scPos.z)) 88 | Thread.sleep(100); 89 | 90 | //run the task on this thread (pasting will be on the main server thread) 91 | task.run(); 92 | } 93 | catch (Exception e) {} 94 | }).start(); 95 | }); 96 | } 97 | // -------------------------------------------------- 98 | public static String getModName() { return ModName; } 99 | public static String getModID() { return ModID; } 100 | @Nullable public static ChunkCopy getInstance() { return Instance; } 101 | // -------------------------------------------------- 102 | /** 103 | * Returns true if the {@link #Instance} is valid. This 104 | * should always return true. If it doesn't, the mod 105 | * probably hasn't been initialized yet. 106 | */ 107 | public static boolean validateInstance() 108 | { 109 | if(Instance != null && (Instance instanceof ChunkCopyClient || Instance instanceof ChunkCopyServer)) 110 | return true; 111 | else return false; 112 | } 113 | // -------------------------------------------------- 114 | /** 115 | * Returns the currently running {@link EnvType}. 116 | * @throws RuntimeException If the mod hasn't been initialized yet. 117 | */ 118 | public static EnvType getEnviroment() 119 | { 120 | //check if initialized 121 | if(!validateInstance()) 122 | throw new RuntimeException("Uninitialized mod."); 123 | 124 | //return 125 | if(Instance instanceof ChunkCopyClient) return EnvType.CLIENT; 126 | else if(Instance instanceof ChunkCopyServer) return EnvType.SERVER; 127 | else throw new RuntimeException("If you are reading this, something went terribly wrong."); 128 | } 129 | // -------------------------------------------------- 130 | /** 131 | * Returns the directory where this mod 132 | * saves and loads it's data. 133 | */ 134 | public static File getModSavesDirectory() 135 | { 136 | File runDir = getRunDirectory(); 137 | return new File(runDir.getAbsolutePath() + "/mods/" + ModID + "/"); 138 | } 139 | // -------------------------------------------------- 140 | /** 141 | * Returns the directory where Minecraft 142 | * is currently running. 143 | */ 144 | public static File getRunDirectory() { return new File(System.getProperty("user.dir")); } 145 | // -------------------------------------------------- 146 | /** 147 | * Returns true if {@link #getEnviroment()} returns {@link EnvType#CLIENT}. 148 | * @throws RuntimeException See {@link #getEnviroment()}. 149 | */ 150 | public static boolean isServer() { return getEnviroment() == EnvType.SERVER; } 151 | 152 | /** 153 | * Returns true if {@link #getEnviroment()} returns {@link EnvType#SERVER}. 154 | * @throws RuntimeException See {@link #getEnviroment()}. 155 | */ 156 | public static boolean isClient() { return getEnviroment() == EnvType.CLIENT; } 157 | // ================================================== 158 | /** 159 | * Returns the registered {@link ChunkCopyCommand}. 160 | * Will return null if the mod hasn't been initialized yet. 161 | */ 162 | @Nullable 163 | public abstract ChunkCopyCommand getCommand(); 164 | // ================================================== 165 | } 166 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/java/thecsdev/chunkcopy/server/command/ChunkCopyServerCommand.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.server.command; 2 | 3 | import java.util.ArrayList; 4 | 5 | import net.minecraft.block.BlockState; 6 | import net.minecraft.server.command.ServerCommandSource; 7 | import net.minecraft.server.world.ServerWorld; 8 | import net.minecraft.text.Text; 9 | import net.minecraft.util.math.ChunkPos; 10 | import thecsdev.chunkcopy.api.AutoChunkCopy; 11 | import thecsdev.chunkcopy.api.AutoChunkCopy.ACCMode; 12 | import thecsdev.chunkcopy.api.ChunkCopyAPI; 13 | import thecsdev.chunkcopy.api.ChunkCopyUtils; 14 | import thecsdev.chunkcopy.command.ChunkCopyCommand; 15 | 16 | public final class ChunkCopyServerCommand extends ChunkCopyCommand 17 | { 18 | // ================================================== 19 | @Override 20 | public String getCommandName() { return "chunkcopysrv"; } 21 | // -------------------------------------------------- 22 | @Override 23 | protected boolean canChunkCopy(ServerCommandSource cs) { return cs.hasPermissionLevel(4); } 24 | // -------------------------------------------------- 25 | @Override 26 | protected boolean canCopy(ServerCommandSource cs) { return isOpAndHuman(cs); } 27 | // -------------------------------------------------- 28 | @Override 29 | protected boolean canPaste(ServerCommandSource cs) { return isOpAndHuman(cs); } 30 | // -------------------------------------------------- 31 | @Override 32 | protected boolean canConfig(ServerCommandSource cs) { return cs.hasPermissionLevel(4); } 33 | // ================================================== 34 | protected void execMain(ServerCommandSource cs) 35 | { 36 | String feedback = "[Chunk Copy] Only operator players can execute this command so " 37 | + "that the mod can know where you wish to copy/paste chunks."; 38 | cs.sendFeedback(Text.literal(feedback), false); 39 | } 40 | // -------------------------------------------------- 41 | @Override 42 | protected void copy(ServerCommandSource commandSource, String fileName, int chunkDistance) 43 | { 44 | try 45 | { 46 | //obtain chunks 47 | ServerWorld world = commandSource.getWorld(); 48 | ChunkPos chunkPos = commandSource.getPlayer().getChunkPos(); 49 | ArrayList loadedChunks = ChunkCopyUtils.getNearbyLoadedChunks(world, chunkPos, chunkDistance); 50 | 51 | //copy chunks 52 | int affectedChunks = 0; 53 | for (ChunkPos cp : loadedChunks) 54 | { 55 | ChunkCopyAPI.saveChunkDataIO(world, cp, fileName); 56 | affectedChunks++; 57 | } 58 | 59 | //send feedback 60 | String feedback = String.format("[Chunk Copy] Copied %d chunks to '%s'.", affectedChunks, fileName); 61 | commandSource.sendFeedback(Text.literal(feedback), true); 62 | } 63 | catch (Exception e) { handleException(commandSource, e); return; } 64 | } 65 | // -------------------------------------------------- 66 | @Override 67 | protected void paste(ServerCommandSource commandSource, String fileName, int chunkDistance) 68 | { 69 | //check if file exists 70 | if(!ChunkCopyAPI.getSaveFileDirectory(fileName).exists()) 71 | { 72 | String feedback = String.format("[Chunk Copy] Unable to paste chunks from '%s', file not found.", fileName); 73 | commandSource.sendFeedback(Text.literal(feedback), true); 74 | return; 75 | } 76 | 77 | try 78 | { 79 | //obtain chunks 80 | ServerWorld world = commandSource.getWorld(); 81 | ChunkPos chunkPos = commandSource.getPlayer().getChunkPos(); 82 | ArrayList loadedChunks = ChunkCopyUtils.getNearbyLoadedChunks(world, chunkPos, chunkDistance); 83 | 84 | //paste chunks 85 | int affectedChunks = 0; 86 | for (ChunkPos cp : loadedChunks) 87 | { 88 | if(ChunkCopyAPI.loadChunkDataIO(world, cp, fileName)) 89 | affectedChunks++; 90 | } 91 | 92 | //send feedback 93 | String feedback = String.format("[Chunk Copy] Pasted %d chunks from '%s'.", affectedChunks, fileName); 94 | commandSource.sendFeedback(Text.literal(feedback), true); 95 | } 96 | catch (Exception e) { handleException(commandSource, e); return; } 97 | } 98 | // -------------------------------------------------- 99 | @Override 100 | protected void fill(ServerCommandSource commandSource, int chunkDistance, BlockState block) 101 | { 102 | try 103 | { 104 | //obtain chunks 105 | ServerWorld world = commandSource.getWorld(); 106 | ChunkPos chunkPos = commandSource.getPlayer().getChunkPos(); 107 | ArrayList loadedChunks = ChunkCopyUtils.getNearbyLoadedChunks(world, chunkPos, chunkDistance); 108 | 109 | //fill chunks 110 | int affectedChunks = 0; 111 | for (ChunkPos cp : loadedChunks) 112 | { 113 | ChunkCopyAPI.fillChunkBlocks(world, cp, block); 114 | affectedChunks++; 115 | } 116 | 117 | //send feedback 118 | String bn = block.getBlock().getName().getString(); 119 | String feedback = String.format("[Chunk Copy] Filled %d chunks with '%s'.", affectedChunks, bn); 120 | commandSource.sendFeedback(Text.literal(feedback), true); 121 | } 122 | catch (Exception e) { handleException(commandSource, e); return; } 123 | } 124 | // -------------------------------------------------- 125 | @Override 126 | protected void autoChunkCopyStart(ServerCommandSource commandSource, String fileName, ACCMode accMode) 127 | { 128 | autoChunkCopyStop(commandSource); 129 | } 130 | 131 | @Override 132 | protected void autoChunkCopyStop(ServerCommandSource commandSource) 133 | { 134 | //send feedback 135 | String feedback = "[Chunk Copy] AutoChunkCopy is not available server-side."; 136 | commandSource.sendFeedback(Text.literal(feedback), false); 137 | AutoChunkCopy.stop(); 138 | } 139 | // ================================================== 140 | private static boolean isOpAndHuman(ServerCommandSource src) 141 | { 142 | try { return src.getPlayer().hasPermissionLevel(4); } 143 | catch (Exception e) { return false; } 144 | } 145 | // -------------------------------------------------- 146 | /** 147 | * Sends exception feedback. 148 | */ 149 | private void handleException(ServerCommandSource source, Exception e) 150 | { 151 | String feedback = String.format( 152 | "[Chunk Copy] An exception was thrown while executing the command: %s", 153 | "\n" + getExceptionMessage(e)); 154 | source.sendFeedback(Text.literal(feedback), true); 155 | } 156 | // ================================================== 157 | } 158 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/java/thecsdev/chunkcopy/api/data/block/CDBBlocksLegacy.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.api.data.block; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.OutputStream; 6 | import java.util.ArrayList; 7 | 8 | import net.minecraft.block.Block; 9 | import net.minecraft.block.BlockState; 10 | import net.minecraft.network.packet.s2c.play.ChunkDataS2CPacket; 11 | import net.minecraft.server.world.ServerWorld; 12 | import net.minecraft.util.math.BlockPos; 13 | import net.minecraft.util.math.ChunkPos; 14 | import net.minecraft.world.World; 15 | import net.minecraft.world.chunk.ChunkSection; 16 | import net.minecraft.world.chunk.WorldChunk; 17 | import net.minecraft.world.chunk.light.LightingProvider; 18 | import thecsdev.chunkcopy.ChunkCopy; 19 | import thecsdev.chunkcopy.api.data.ChunkDataBlock; 20 | import thecsdev.chunkcopy.api.data.ChunkDataBlockID; 21 | import thecsdev.chunkcopy.api.io.IOUtils; 22 | 23 | /** 24 | * A legacy {@link ChunkDataBlock} that contains information about world chunk blocks.
25 | *
26 | * Obsolete because of how im-performant (slow) it is. Use {@link CDBChunkSections} instead. 27 | */ 28 | @ChunkDataBlockID(namespace = ChunkCopy.ModID, path = "blocks_legacy") 29 | public class CDBBlocksLegacy extends ChunkDataBlock 30 | { 31 | // ================================================== 32 | /** 33 | * Defines the bottom Y level of the chunk. 34 | * This is the Y level of bedrock. 35 | */ 36 | public int StartY = 0; 37 | 38 | /** 39 | * The array of copied blocks. 40 | */ 41 | public final ArrayList BlockIDs = new ArrayList(); 42 | // ================================================== 43 | @Deprecated(forRemoval = true, since = "v2.0.0") 44 | @Override 45 | public void copyData(World world, ChunkPos chunkPos) 46 | { 47 | WorldChunk chunk = world.getChunk(chunkPos.x, chunkPos.z); 48 | int chunkWidthX = Math.abs(chunkPos.getEndX() - chunkPos.getStartX()); 49 | int chunkWidthZ = Math.abs(chunkPos.getEndZ() - chunkPos.getStartZ()); 50 | 51 | //Start Y 52 | StartY = chunk.getBottomY(); 53 | 54 | //Block IDs 55 | BlockIDs.clear(); 56 | int x = 0, y = chunk.getBottomY(), z = 0; 57 | while(y < chunk.getTopY() + 1) 58 | { 59 | //handle block 60 | BlockPos blockPos = chunk.getPos().getBlockPos(x, y, z); 61 | BlockState blockState = chunk.getBlockState(blockPos); 62 | BlockIDs.add(Block.getRawIdFromState(blockState)); 63 | 64 | //increment 65 | x++; 66 | if(x > chunkWidthX) 67 | { 68 | z++; x = 0; 69 | if(z > chunkWidthZ) { y++; z = 0; } 70 | } 71 | } 72 | } 73 | // -------------------------------------------------- 74 | @Deprecated(forRemoval = true, since = "v2.0.0") 75 | @Override 76 | public void pasteData(ServerWorld world, ChunkPos chunkPos) 77 | { 78 | WorldChunk chunk = world.getChunk(chunkPos.x, chunkPos.z); 79 | int chunkWidthX = Math.abs(chunkPos.getEndX() - chunkPos.getStartX()); 80 | int chunkWidthZ = Math.abs(chunkPos.getEndZ() - chunkPos.getStartZ()); 81 | 82 | //iterate all block IDs 83 | int x = 0, y = StartY, z = 0; 84 | for (int blockID : BlockIDs) 85 | { 86 | //break if too high 87 | if(y > chunk.getTopY()) break; 88 | 89 | //handle block 90 | try 91 | { 92 | do 93 | { 94 | //ignore blocks below bedrock and above build limit 95 | if(y < chunk.getBottomY() || y > chunk.getTopY()) 96 | break; 97 | 98 | //get state, section, and local coords 99 | BlockState state = Block.getStateFromRawId(blockID); 100 | if(state.hasBlockEntity()) break; 101 | 102 | ChunkSection toChunkSection = chunk.getSection(chunk.getSectionIndex(y)); 103 | toChunkSection.setBlockState(x, y & 0xF, z, state); 104 | } 105 | while(false); 106 | } 107 | catch (Exception e) { break; } 108 | 109 | //increment 110 | x++; 111 | if(x > chunkWidthX) 112 | { 113 | z++; x = 0; 114 | if(z > chunkWidthZ) { y++; z = 0; } 115 | } 116 | } 117 | 118 | //mark as needs saving 119 | chunk.setShouldSave(true); 120 | } 121 | // -------------------------------------------------- 122 | @Override 123 | public void updateClients(ServerWorld world, ChunkPos chunkPos) { updateClientsB(world, chunkPos); } 124 | 125 | public static void updateClientsB(ServerWorld world, ChunkPos chunkPos) 126 | { 127 | //update chunk lighting 128 | updateChunkLighting(world, chunkPos); 129 | 130 | //create and send a chunk data packet to players 131 | ChunkDataS2CPacket chunkData = makeMeAChunkDataPacketPls(world, chunkPos); 132 | world.getPlayers().forEach(p -> p.networkHandler.sendPacket(chunkData)); 133 | } 134 | 135 | public static void updateChunkLighting(ServerWorld world, ChunkPos chunkPos) 136 | { 137 | LightingProvider light = world.getLightingProvider(); 138 | WorldChunk chunk = (WorldChunk)world.getChunk(chunkPos.x, chunkPos.z); 139 | 140 | int chunkWidthX = Math.abs(chunkPos.getEndX() - chunkPos.getStartX()); 141 | int chunkWidthZ = Math.abs(chunkPos.getEndZ() - chunkPos.getStartZ()); 142 | int y = chunk.getTopY(); 143 | 144 | for(int x = 0; x < chunkWidthX; x++) 145 | for(int z = 0; z < chunkWidthZ; z++) 146 | { 147 | BlockPos pos = chunkPos.getBlockPos(x, y, z); 148 | light.checkBlock(pos); 149 | } 150 | } 151 | // ================================================== 152 | @Override 153 | public void readData(InputStream stream) throws IOException 154 | { 155 | //read StartY 156 | StartY = IOUtils.readVarInt(stream); 157 | 158 | //read blocks 159 | BlockIDs.clear(); 160 | while(stream.available() > 0) 161 | { 162 | try { BlockIDs.add(IOUtils.readVarInt(stream)); } 163 | catch(IOException e) {} 164 | } 165 | } 166 | // -------------------------------------------------- 167 | @Override 168 | public void writeData(OutputStream stream) throws IOException 169 | { 170 | //write StartY 171 | IOUtils.writeVarInt(stream, StartY); 172 | 173 | //write blocks 174 | for (Integer blockId : BlockIDs) { IOUtils.writeVarInt(stream, blockId); } 175 | } 176 | // ================================================== 177 | //i didn't know what else to name this method so whatever 178 | private static ChunkDataS2CPacket makeMeAChunkDataPacketPls(World world, ChunkPos chunkPos) 179 | { 180 | WorldChunk wchunk = world.getChunk(chunkPos.x, chunkPos.z); 181 | LightingProvider lp = world.getLightingProvider(); 182 | //BitSet skyBits = new BitSet(0); 183 | //BitSet blockBits = new BitSet(0); 184 | return new ChunkDataS2CPacket(wchunk, lp, null, null, true); 185 | } 186 | // ================================================== 187 | } 188 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/java/thecsdev/chunkcopy/ChunkCopy.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy; 2 | 3 | import java.io.File; 4 | 5 | import org.jetbrains.annotations.Nullable; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import net.fabricmc.api.EnvType; 10 | import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents; 11 | import net.minecraft.util.math.ChunkPos; 12 | import thecsdev.chunkcopy.api.AutoChunkCopy; 13 | import thecsdev.chunkcopy.api.ChunkCopyAPI; 14 | import thecsdev.chunkcopy.api.config.ChunkCopyConfig; 15 | import thecsdev.chunkcopy.api.data.ChunkData; 16 | import thecsdev.chunkcopy.api.data.block.CDBChunkSections; 17 | import thecsdev.chunkcopy.api.data.block.CDBEntitiesLegacy; 18 | import thecsdev.chunkcopy.api.data.block.CDBEntityBlocksLegacy; 19 | import thecsdev.chunkcopy.client.ChunkCopyClient; 20 | import thecsdev.chunkcopy.command.ChunkCopyCommand; 21 | import thecsdev.chunkcopy.server.ChunkCopyServer; 22 | 23 | /** 24 | * The main ChunkCopy class. This class 25 | * contains vital information about the mod. 26 | */ 27 | public abstract class ChunkCopy 28 | { 29 | // ================================================== 30 | private static ChunkCopy Instance = null; 31 | // -------------------------------------------------- 32 | public static final Logger LOGGER = LoggerFactory.getLogger(getModID()); 33 | // -------------------------------------------------- 34 | public static final String ModName = "Chunk Copy"; 35 | public static final String ModID = "chunkcopy"; 36 | public static final int FileVersion = 757; 37 | // ================================================== 38 | public ChunkCopy() 39 | { 40 | //check if there already is an instance 41 | if(validateInstance()) 42 | throw new RuntimeException("An instance of ChunkCopy already exists."); 43 | 44 | //define Instance 45 | Instance = this; 46 | 47 | //log stuff 48 | LOGGER.info("Initializing '" + getModName() + "' as '" + getClass().getSimpleName() + "'."); 49 | 50 | //register config keys and load the config -- work in progress 51 | ChunkCopyConfig.KEYS.add(ChunkCopyConfig.PASTE_ENTITIES); 52 | //ChunkCopyConfig.loadConfig(); 53 | 54 | //handle API registrations 55 | ChunkData.registerChunkDataBlockType(CDBChunkSections.class); 56 | ChunkData.registerChunkDataBlockType(CDBEntityBlocksLegacy.class); 57 | ChunkData.registerChunkDataBlockType(CDBEntitiesLegacy.class); 58 | 59 | //register auto-paste handler 60 | ServerChunkEvents.CHUNK_LOAD.register((sWorld, sChunk) -> 61 | { 62 | //check if auto-copy is pasting 63 | if(!AutoChunkCopy.isPasting()) return; 64 | final ChunkPos scPos = sChunk.getPos(); 65 | 66 | //convert the action into a task 67 | final Runnable task = () -> 68 | { 69 | try 70 | { 71 | //paste data into the chunk 72 | final String fileName = AutoChunkCopy.getFileName(); 73 | ChunkCopyAPI.loadChunkDataIO(sWorld, sChunk.getPos(), fileName); 74 | } 75 | catch(Exception exc) {} 76 | }; 77 | 78 | //run the task 79 | new Thread(() -> 80 | { 81 | try 82 | { 83 | //wait a bit for the chunk to be fully ready 84 | Thread.sleep(500); 85 | 86 | //make sure the chunk is fully ready 87 | while(!sWorld.isChunkLoaded(scPos.x, scPos.z)) 88 | Thread.sleep(100); 89 | 90 | //run the task on this thread (pasting will be on the main server thread) 91 | task.run(); 92 | } 93 | catch (Exception e) {} 94 | }).start(); 95 | }); 96 | } 97 | // -------------------------------------------------- 98 | public static String getModName() { return ModName; } 99 | public static String getModID() { return ModID; } 100 | @Nullable public static ChunkCopy getInstance() { return Instance; } 101 | // -------------------------------------------------- 102 | /** 103 | * Returns true if the {@link #Instance} is valid. This 104 | * should always return true. If it doesn't, the mod 105 | * probably hasn't been initialized yet. 106 | */ 107 | public static boolean validateInstance() 108 | { 109 | if(Instance != null && (Instance instanceof ChunkCopyClient || Instance instanceof ChunkCopyServer)) 110 | return true; 111 | else return false; 112 | } 113 | // -------------------------------------------------- 114 | /** 115 | * Returns the currently running {@link EnvType}. 116 | * @throws RuntimeException If the mod hasn't been initialized yet. 117 | */ 118 | public static EnvType getEnviroment() 119 | { 120 | //check if initialized 121 | if(!validateInstance()) 122 | throw new RuntimeException("Uninitialized mod."); 123 | 124 | //return 125 | if(Instance instanceof ChunkCopyClient) return EnvType.CLIENT; 126 | else if(Instance instanceof ChunkCopyServer) return EnvType.SERVER; 127 | else throw new RuntimeException("If you are reading this, something went terribly wrong."); 128 | } 129 | // -------------------------------------------------- 130 | /** 131 | * Returns the directory where this mod 132 | * saves and loads it's data. 133 | */ 134 | public static File getModSavesDirectory() 135 | { 136 | File runDir = getRunDirectory(); 137 | return new File(runDir.getAbsolutePath() + "/mods/" + ModID + "/"); 138 | } 139 | // -------------------------------------------------- 140 | /** 141 | * Returns the directory where Minecraft 142 | * is currently running. 143 | */ 144 | public static File getRunDirectory() { return new File(System.getProperty("user.dir")); } 145 | // -------------------------------------------------- 146 | /** 147 | * Returns true if {@link #getEnviroment()} returns {@link EnvType#CLIENT}. 148 | * @throws RuntimeException See {@link #getEnviroment()}. 149 | */ 150 | public static boolean isServer() { return getEnviroment() == EnvType.SERVER; } 151 | 152 | /** 153 | * Returns true if {@link #getEnviroment()} returns {@link EnvType#SERVER}. 154 | * @throws RuntimeException See {@link #getEnviroment()}. 155 | */ 156 | public static boolean isClient() { return getEnviroment() == EnvType.CLIENT; } 157 | 158 | /** 159 | * Returns true if {@link #isClient()} and if client is in single player. 160 | * @throws RuntimeException See {@link #getEnviroment()}. 161 | */ 162 | public static boolean isInSinglePlayer() { return isClient() && net.minecraft.client.MinecraftClient.getInstance().isInSingleplayer(); } 163 | // ================================================== 164 | /** 165 | * Returns the registered {@link ChunkCopyCommand}. 166 | * Will return null if the mod hasn't been initialized yet. 167 | */ 168 | @Nullable 169 | public abstract ChunkCopyCommand getCommand(); 170 | // ================================================== 171 | } 172 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/java/thecsdev/chunkcopy/client/command/ChunkCopyClientCommand.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.client.command; 2 | 3 | import java.util.ArrayList; 4 | 5 | import net.fabricmc.fabric.api.client.command.v1.FabricClientCommandSource; 6 | import net.minecraft.block.BlockState; 7 | import net.minecraft.client.MinecraftClient; 8 | import net.minecraft.client.world.ClientWorld; 9 | import net.minecraft.server.world.ServerWorld; 10 | import net.minecraft.text.TranslatableText; 11 | import net.minecraft.util.math.ChunkPos; 12 | import thecsdev.chunkcopy.api.AutoChunkCopy; 13 | import thecsdev.chunkcopy.api.ChunkCopyAPI; 14 | import thecsdev.chunkcopy.api.ChunkCopyUtils; 15 | import thecsdev.chunkcopy.api.AutoChunkCopy.ACCMode; 16 | import thecsdev.chunkcopy.command.ChunkCopyCommand; 17 | 18 | public final class ChunkCopyClientCommand extends ChunkCopyCommand 19 | { 20 | // ================================================== 21 | @Override 22 | public String getCommandName() { return "chunkcopy"; } 23 | // -------------------------------------------------- 24 | @Override 25 | protected boolean canCopy(FabricClientCommandSource cs) { return true; } 26 | // -------------------------------------------------- 27 | @Override 28 | protected boolean canPaste(FabricClientCommandSource cs) 29 | { 30 | if(!cs.hasPermissionLevel(4)) return false; 31 | else if(!net.minecraft.client.MinecraftClient.getInstance().isInSingleplayer()) return false; 32 | else return true; 33 | } 34 | // -------------------------------------------------- 35 | @Override 36 | protected boolean canConfig(FabricClientCommandSource cs) { return true; } 37 | // ================================================== 38 | @Override 39 | protected void execMain(FabricClientCommandSource cs) 40 | { 41 | cs.sendFeedback(new TranslatableText("chunkcopy.feedback.syntax.copypaste")); 42 | } 43 | // -------------------------------------------------- 44 | @Override 45 | protected void copy(FabricClientCommandSource commandSource, String fileName, int chunkDistance) 46 | { 47 | copy(commandSource, fileName, chunkDistance, true); 48 | } 49 | 50 | public void copy(FabricClientCommandSource commandSource, String fileName, int chunkDistance, boolean sendFeedback) 51 | { 52 | //obtain chunks 53 | ClientWorld world = commandSource.getWorld(); 54 | ChunkPos chunkPos = commandSource.getPlayer().getChunkPos(); 55 | ArrayList loadedChunks = ChunkCopyUtils.getNearbyLoadedChunks(world, chunkPos, chunkDistance); 56 | 57 | //copy chunks 58 | int affectedChunks = 0; 59 | try 60 | { 61 | for (ChunkPos cp : loadedChunks) 62 | { 63 | ChunkCopyAPI.saveChunkDataIO(world, cp, fileName); 64 | affectedChunks++; 65 | } 66 | } 67 | catch (Exception e) { handleException(commandSource, e); return; } 68 | 69 | //send feedback 70 | if(sendFeedback) 71 | commandSource.sendFeedback(new TranslatableText("chunkcopy.feedback.copied", affectedChunks, fileName)); 72 | } 73 | // -------------------------------------------------- 74 | @Override 75 | protected void paste(FabricClientCommandSource commandSource, String fileName, int chunkDistance) 76 | { 77 | paste(commandSource, fileName, chunkDistance, true); 78 | } 79 | 80 | protected void paste(FabricClientCommandSource commandSource, String fileName, int chunkDistance, boolean sendFeedback) 81 | { 82 | //check if in singleplayer 83 | MinecraftClient mc = MinecraftClient.getInstance(); 84 | if(!requireSingleplayer(commandSource)) return; 85 | 86 | //check if file exists 87 | if(!ChunkCopyAPI.getSaveFileDirectory(fileName).exists()) 88 | { 89 | commandSource.sendFeedback(new TranslatableText("chunkcopy.feedback.paste_file_not_found", 90 | new Object[] { fileName })); 91 | return; 92 | } 93 | 94 | //obtain chunks 95 | ServerWorld world = mc.getServer().getWorld(mc.world.getRegistryKey()); 96 | ChunkPos chunkPos = commandSource.getPlayer().getChunkPos(); 97 | ArrayList loadedChunks = ChunkCopyUtils.getNearbyLoadedChunks(world, chunkPos, chunkDistance); 98 | 99 | //paste chunks 100 | int affectedChunks = 0; 101 | try 102 | { 103 | for (ChunkPos cp : loadedChunks) 104 | { 105 | if(ChunkCopyAPI.loadChunkDataIO(world, cp, fileName)) 106 | affectedChunks++; 107 | } 108 | } 109 | catch (Exception e) { handleException(commandSource, e); return; } 110 | 111 | //send feedback 112 | if(sendFeedback) 113 | commandSource.sendFeedback(new TranslatableText("chunkcopy.feedback.pasted", affectedChunks, fileName)); 114 | } 115 | // -------------------------------------------------- 116 | @Override 117 | protected void fill(FabricClientCommandSource commandSource, int chunkDistance, BlockState block) 118 | { 119 | MinecraftClient mc = MinecraftClient.getInstance(); 120 | if(!requireSingleplayer(commandSource)) return; 121 | 122 | //obtain chunks 123 | ServerWorld world = mc.getServer().getWorld(mc.world.getRegistryKey()); 124 | ChunkPos chunkPos = commandSource.getPlayer().getChunkPos(); 125 | ArrayList loadedChunks = ChunkCopyUtils.getNearbyLoadedChunks(world, chunkPos, chunkDistance); 126 | 127 | //fill chunks 128 | int affectedChunks = 0; 129 | try 130 | { 131 | for (ChunkPos cp : loadedChunks) 132 | { 133 | ChunkCopyAPI.fillChunkBlocks(world, cp, block); 134 | affectedChunks++; 135 | } 136 | } 137 | catch (Exception e) { handleException(commandSource, e); return; } 138 | 139 | //send feedback 140 | String bn = block.getBlock().getName().getString(); 141 | commandSource.sendFeedback(new TranslatableText("chunkcopy.feedback.filled", affectedChunks, bn)); 142 | } 143 | // -------------------------------------------------- 144 | @Override 145 | protected void autoChunkCopyStart(FabricClientCommandSource commandSource, String fileName, ACCMode accMode) 146 | { 147 | //start auto chunk copy 148 | AutoChunkCopy.start(fileName, accMode); 149 | 150 | 151 | //send feedback 152 | if(accMode == ACCMode.Copying) 153 | { 154 | copy(commandSource, fileName, 8, false); 155 | commandSource.sendFeedback(new TranslatableText("chunkcopy.feedback.autochunkcopy.start_copying", fileName)); 156 | } 157 | else if(accMode == ACCMode.Pasting) 158 | { 159 | paste(commandSource, fileName, 8, false); 160 | commandSource.sendFeedback(new TranslatableText("chunkcopy.feedback.autochunkcopy.start_pasting", fileName)); 161 | } 162 | } 163 | 164 | @Override 165 | protected void autoChunkCopyStop(FabricClientCommandSource commandSource) 166 | { 167 | AutoChunkCopy.stop(); 168 | 169 | //send feedback 170 | commandSource.sendFeedback(new TranslatableText("chunkcopy.feedback.autochunkcopy.stop")); 171 | } 172 | // ================================================== 173 | /** 174 | * Returns false and sends feedback 175 | * if not in singleplayer. 176 | */ 177 | private boolean requireSingleplayer(FabricClientCommandSource cmdSrc) 178 | { 179 | //check singleplayer 180 | MinecraftClient mc = MinecraftClient.getInstance(); 181 | if(!mc.isInSingleplayer()) 182 | { 183 | cmdSrc.sendFeedback(new TranslatableText("chunkcopy.feedback.require_singleplayer")); 184 | return false; 185 | } 186 | return true; 187 | } 188 | // -------------------------------------------------- 189 | /** 190 | * Sends exception feedback. 191 | */ 192 | private void handleException(FabricClientCommandSource source, Exception e) 193 | { 194 | source.sendFeedback(new TranslatableText("chunkcopy.feedback.command_exception", 195 | new Object[] { "\n" + getExceptionMessage(e) })); 196 | } 197 | // ================================================== 198 | } 199 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/java/thecsdev/chunkcopy/client/command/ChunkCopyClientCommand.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.client.command; 2 | 3 | import java.util.ArrayList; 4 | 5 | import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; 6 | import net.minecraft.block.BlockState; 7 | import net.minecraft.client.MinecraftClient; 8 | import net.minecraft.client.world.ClientWorld; 9 | import net.minecraft.server.world.ServerWorld; 10 | import net.minecraft.text.Text; 11 | import net.minecraft.util.math.ChunkPos; 12 | import thecsdev.chunkcopy.api.AutoChunkCopy; 13 | import thecsdev.chunkcopy.api.AutoChunkCopy.ACCMode; 14 | import thecsdev.chunkcopy.api.ChunkCopyAPI; 15 | import thecsdev.chunkcopy.api.ChunkCopyUtils; 16 | import thecsdev.chunkcopy.command.ChunkCopyCommand; 17 | 18 | public final class ChunkCopyClientCommand extends ChunkCopyCommand 19 | { 20 | // ================================================== 21 | @Override 22 | public String getCommandName() { return "chunkcopy"; } 23 | // -------------------------------------------------- 24 | @Override 25 | protected boolean canChunkCopy(FabricClientCommandSource cs) { return true; } 26 | // -------------------------------------------------- 27 | @Override 28 | protected boolean canCopy(FabricClientCommandSource cs) { return true; } 29 | // -------------------------------------------------- 30 | @Override 31 | protected boolean canPaste(FabricClientCommandSource cs) 32 | { 33 | if(!cs.hasPermissionLevel(4)) return false; 34 | else if(!net.minecraft.client.MinecraftClient.getInstance().isInSingleplayer()) return false; 35 | else return true; 36 | } 37 | // -------------------------------------------------- 38 | @Override 39 | protected boolean canConfig(FabricClientCommandSource cs) { return true; } 40 | // ================================================== 41 | @Override 42 | protected void execMain(FabricClientCommandSource cs) 43 | { 44 | cs.sendFeedback(Text.translatable("chunkcopy.feedback.syntax.copypaste")); 45 | } 46 | // -------------------------------------------------- 47 | @Override 48 | protected void copy(FabricClientCommandSource commandSource, String fileName, int chunkDistance) 49 | { 50 | copy(commandSource, fileName, chunkDistance, true); 51 | } 52 | 53 | public void copy(FabricClientCommandSource commandSource, String fileName, int chunkDistance, boolean sendFeedback) 54 | { 55 | //obtain chunks 56 | ClientWorld world = commandSource.getWorld(); 57 | ChunkPos chunkPos = commandSource.getPlayer().getChunkPos(); 58 | ArrayList loadedChunks = ChunkCopyUtils.getNearbyLoadedChunks(world, chunkPos, chunkDistance); 59 | 60 | //copy chunks 61 | int affectedChunks = 0; 62 | try 63 | { 64 | for (ChunkPos cp : loadedChunks) 65 | { 66 | ChunkCopyAPI.saveChunkDataIO(world, cp, fileName); 67 | affectedChunks++; 68 | } 69 | } 70 | catch (Exception e) { handleException(commandSource, e); return; } 71 | 72 | //send feedback 73 | if(sendFeedback) 74 | { 75 | commandSource.sendFeedback(Text.translatable("chunkcopy.feedback.copied", affectedChunks, fileName)); 76 | } 77 | } 78 | // -------------------------------------------------- 79 | @Override 80 | protected void paste(FabricClientCommandSource commandSource, String fileName, int chunkDistance) 81 | { 82 | paste(commandSource, fileName, chunkDistance, true); 83 | } 84 | 85 | protected void paste(FabricClientCommandSource commandSource, String fileName, int chunkDistance, boolean sendFeedback) 86 | { 87 | //check if in singleplayer 88 | MinecraftClient mc = MinecraftClient.getInstance(); 89 | if(!requireSingleplayer(commandSource)) return; 90 | 91 | //check if file exists 92 | if(!ChunkCopyAPI.getSaveFileDirectory(fileName).exists()) 93 | { 94 | commandSource.sendFeedback(Text.translatable("chunkcopy.feedback.paste_file_not_found", 95 | new Object[] { fileName })); 96 | return; 97 | } 98 | 99 | //obtain chunks 100 | ServerWorld world = mc.getServer().getWorld(mc.world.getRegistryKey()); 101 | ChunkPos chunkPos = commandSource.getPlayer().getChunkPos(); 102 | ArrayList loadedChunks = ChunkCopyUtils.getNearbyLoadedChunks(world, chunkPos, chunkDistance); 103 | 104 | //paste chunks 105 | int affectedChunks = 0; 106 | try 107 | { 108 | for (ChunkPos cp : loadedChunks) 109 | { 110 | if(ChunkCopyAPI.loadChunkDataIO(world, cp, fileName)) 111 | affectedChunks++; 112 | } 113 | } 114 | catch (Exception e) { handleException(commandSource, e); return; } 115 | 116 | //send feedback 117 | if(sendFeedback) 118 | commandSource.sendFeedback(Text.translatable("chunkcopy.feedback.pasted", affectedChunks, fileName)); 119 | } 120 | // -------------------------------------------------- 121 | @Override 122 | protected void fill(FabricClientCommandSource commandSource, int chunkDistance, BlockState block) 123 | { 124 | MinecraftClient mc = MinecraftClient.getInstance(); 125 | if(!requireSingleplayer(commandSource)) return; 126 | 127 | //obtain chunks 128 | ServerWorld world = mc.getServer().getWorld(mc.world.getRegistryKey()); 129 | ChunkPos chunkPos = commandSource.getPlayer().getChunkPos(); 130 | ArrayList loadedChunks = ChunkCopyUtils.getNearbyLoadedChunks(world, chunkPos, chunkDistance); 131 | 132 | //fill chunks 133 | int affectedChunks = 0; 134 | try 135 | { 136 | for (ChunkPos cp : loadedChunks) 137 | { 138 | ChunkCopyAPI.fillChunkBlocks(world, cp, block); 139 | affectedChunks++; 140 | } 141 | } 142 | catch (Exception e) { handleException(commandSource, e); return; } 143 | 144 | //send feedback 145 | String bn = block.getBlock().getName().getString(); 146 | commandSource.sendFeedback(Text.translatable("chunkcopy.feedback.filled", affectedChunks, bn)); 147 | } 148 | // -------------------------------------------------- 149 | @Override 150 | protected void autoChunkCopyStart(FabricClientCommandSource commandSource, String fileName, ACCMode accMode) 151 | { 152 | //start auto chunk copy 153 | AutoChunkCopy.start(fileName, accMode); 154 | 155 | 156 | //send feedback 157 | if(accMode == ACCMode.Copying) 158 | { 159 | copy(commandSource, fileName, 8, false); 160 | commandSource.sendFeedback(Text.translatable("chunkcopy.feedback.autochunkcopy.start_copying", fileName)); 161 | } 162 | else if(accMode == ACCMode.Pasting) 163 | { 164 | paste(commandSource, fileName, 8, false); 165 | commandSource.sendFeedback(Text.translatable("chunkcopy.feedback.autochunkcopy.start_pasting", fileName)); 166 | } 167 | } 168 | 169 | @Override 170 | protected void autoChunkCopyStop(FabricClientCommandSource commandSource) 171 | { 172 | AutoChunkCopy.stop(); 173 | 174 | //send feedback 175 | commandSource.sendFeedback(Text.translatable("chunkcopy.feedback.autochunkcopy.stop")); 176 | } 177 | // ================================================== 178 | /** 179 | * Returns false and sends feedback 180 | * if not in singleplayer. 181 | */ 182 | private boolean requireSingleplayer(FabricClientCommandSource cmdSrc) 183 | { 184 | //check singleplayer 185 | MinecraftClient mc = MinecraftClient.getInstance(); 186 | if(!mc.isInSingleplayer()) 187 | { 188 | cmdSrc.sendFeedback(Text.translatable("chunkcopy.feedback.require_singleplayer")); 189 | return false; 190 | } 191 | return true; 192 | } 193 | // -------------------------------------------------- 194 | /** 195 | * Sends exception feedback. 196 | */ 197 | private void handleException(FabricClientCommandSource source, Exception e) 198 | { 199 | source.sendFeedback(Text.translatable("chunkcopy.feedback.command_exception", 200 | new Object[] { "\n" + getExceptionMessage(e) })); 201 | } 202 | // ================================================== 203 | } 204 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.19/src/main/java/thecsdev/chunkcopy/api/ChunkCopyAPI.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.api; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.File; 5 | import java.io.IOException; 6 | 7 | import org.apache.commons.io.FileUtils; 8 | 9 | import net.minecraft.block.BlockState; 10 | import net.minecraft.block.Blocks; 11 | import net.minecraft.server.world.ServerWorld; 12 | import net.minecraft.util.math.ChunkPos; 13 | import net.minecraft.world.World; 14 | import net.minecraft.world.chunk.EmptyChunk; 15 | import net.minecraft.world.chunk.WorldChunk; 16 | import thecsdev.chunkcopy.ChunkCopy; 17 | import thecsdev.chunkcopy.api.data.ChunkData; 18 | import thecsdev.chunkcopy.api.data.block.CDBFillBlocks; 19 | import thecsdev.chunkcopy.api.io.IOUtils; 20 | 21 | /** 22 | * The main API implementation for the {@link ChunkCopy} mod.
23 | */ 24 | public final class ChunkCopyAPI 25 | { 26 | // ================================================== 27 | public static final String FILE_EXTENSION = ".bin"; 28 | // ================================================== 29 | /** 30 | * Returns the directory where all copied 31 | * chunk save files are stored. 32 | */ 33 | public static File getSaveFilesDirectory() 34 | { 35 | return new File(ChunkCopy.getModSavesDirectory().getAbsolutePath() + "/savedChunks/"); 36 | } 37 | 38 | /** 39 | * Returns the directory path to a save file. 40 | * @param fileName - The name of the save file. 41 | */ 42 | public static File getSaveFileDirectory(String fileName) 43 | { 44 | fileName = fileName.replaceFirst("\\/.*", ""); //discard alternate pattern 45 | return new File(getSaveFilesDirectory().getAbsolutePath() + "/" + fileName + "/"); 46 | } 47 | // -------------------------------------------------- 48 | /** 49 | * Returns the save file for a specific world chunk. 50 | * @throws IOException For invalid fileName syntax. 51 | * @param world The world where the chunk is located. 52 | * @param chunkPos The {@link ChunkPos} of the chunk in the world. 53 | * @param fileName The directory where the chunk is or will be saved to. 54 | */ 55 | public static File getChunkSaveFile(World world, ChunkPos chunkPos, String fileName) throws IOException 56 | { 57 | //get world id 58 | String worldIdNamespace = null; 59 | String worldIdPath = null; 60 | 61 | //regex syntax check 62 | IOException e = new IOException("Invalid fileName syntax."); 63 | if(!fileName.matches("[a-zA-Z0-9_\\/]*")) throw e; //handle regular fileName 64 | 65 | if(fileName.contains("/")) //handle custom dimension definition 66 | { 67 | //regex check 68 | if(!fileName.matches("[a-zA-Z0-9_]{1,}\\/[a-zA-Z0-9_]{1,}\\/[a-zA-Z0-9_]{1,}")) throw e; 69 | 70 | //split and assign values 71 | String[] fnS = fileName.split("\\/"); 72 | worldIdNamespace = fnS[1]; 73 | worldIdPath = fnS[2]; 74 | } 75 | else 76 | { 77 | worldIdNamespace = world.getRegistryKey().getValue().getNamespace(); 78 | worldIdPath = world.getRegistryKey().getValue().getPath(); 79 | } 80 | 81 | //construct path 82 | String a = getSaveFileDirectory(fileName).getAbsolutePath() + "/"; 83 | String b = worldIdNamespace + "/" + worldIdPath + "/"; 84 | String c = chunkPos.x + "_" + chunkPos.z + FILE_EXTENSION; 85 | String chunkFileStr = a + b + c; 86 | 87 | //return file 88 | return new File(chunkFileStr); 89 | } 90 | // ================================================== 91 | /** 92 | * Copies chunk data using {@link #copyChunkData(World, ChunkPos, boolean)} 93 | * and then saves it to it's save file. 94 | * @param world The world where the chunk is located. 95 | * @param chunkPos The {@link ChunkPos} of the chunk in the world. 96 | * @param fileName The directory where the chunk data will be saved to. 97 | * @throws IOException If an {@link IOException} occurs while saving. 98 | */ 99 | public static void saveChunkDataIO(World world, ChunkPos chunkPos, String fileName) throws IOException 100 | { 101 | //make sure the chunk isn't null or empty 102 | WorldChunk chunk = world.getChunk(chunkPos.x, chunkPos.z); 103 | if(chunk == null || (chunk instanceof EmptyChunk)) return; 104 | 105 | //prepare the file 106 | File file = getChunkSaveFile(world, chunkPos, fileName); 107 | file.getParentFile().mkdirs(); 108 | 109 | //write 110 | byte[] chunkData = copyChunkData(world, chunkPos, true); 111 | FileUtils.writeByteArrayToFile(file, chunkData); 112 | } 113 | // -------------------------------------------------- 114 | /** 115 | * Loads chunk data from a chunk's save file and then pastes it 116 | * using {@link #pasteChunkData(byte[], ServerWorld, ChunkPos, boolean)}. 117 | * @param world The world where the chunk is located. 118 | * @param chunkPos The {@link ChunkPos} of the chunk in the world. 119 | * @param fileName The directory where the chunk data will be loaded from. 120 | * @return True if the chunk save file exists and was loaded. 121 | * @throws IOException If an {@link IOException} occurs while loading. 122 | */ 123 | public static boolean loadChunkDataIO(ServerWorld world, ChunkPos chunkPos, String fileName) throws IOException 124 | { 125 | //get the file 126 | File file = getChunkSaveFile(world, chunkPos, fileName); 127 | if(!file.exists()) return false; 128 | 129 | //read 130 | byte[] chunkData = FileUtils.readFileToByteArray(getChunkSaveFile(world, chunkPos, fileName)); 131 | pasteChunkData(chunkData, world, chunkPos, true); 132 | return true; 133 | } 134 | // ================================================== 135 | /** 136 | * Copies all chunk data from a world chunk to {@link ChunkData}. 137 | * @param world The world where the chunk is located. 138 | * @param chunkPos The {@link ChunkPos} of the chunk in the world. 139 | * @param useCompression Whether or not to compress the bytes using gZip compression. 140 | * @throws IOException If an IOException occurs while writing data to the byte array. 141 | */ 142 | public static byte[] copyChunkData(World world, ChunkPos chunkPos, boolean useCompression) 143 | throws IOException 144 | { 145 | ChunkData chunkData = new ChunkData(); 146 | chunkData.copyData(world, chunkPos); 147 | 148 | byte[] bytes = chunkData.toByteArray(); 149 | if(useCompression) bytes = IOUtils.gzipCompressBytes(bytes); 150 | return bytes; 151 | } 152 | // -------------------------------------------------- 153 | /** 154 | * Pastes all chunk data from {@link ChunkData} to a world chunk. 155 | * @param data The chunk data to paste. 156 | * @param world The world where the chunk is located. 157 | * @param chunkPos The {@link ChunkPos} of the chunk in the world. 158 | * @param isCompressed Whether or not the bytes were compressed using gZip compression. 159 | * @throws IOException If an IOException occurs while reading data from the byte array. 160 | */ 161 | public static void pasteChunkData(byte[] data, ServerWorld world, ChunkPos chunkPos, boolean isCompressed) 162 | throws IOException 163 | { 164 | if(isCompressed) data = IOUtils.gzipDecompressBytes(data); 165 | 166 | ByteArrayInputStream stream = new ByteArrayInputStream(data); 167 | ChunkData chunkData = new ChunkData(); 168 | chunkData.readData(stream); 169 | stream.close(); 170 | chunkData.pasteData(world, chunkPos); 171 | } 172 | // -------------------------------------------------- 173 | /** 174 | * Fills an entire world chunk with a specific {@link BlockState}. 175 | */ 176 | public static void fillChunkBlocks(ServerWorld world, ChunkPos chunkPos, BlockState block) 177 | { 178 | CDBFillBlocks f = new CDBFillBlocks(); 179 | f.state = block; 180 | f.pasteData(world, chunkPos); 181 | f.updateClients(world, chunkPos); 182 | } 183 | 184 | /** 185 | * Same as {@link #fillChunkBlocks(ServerWorld, ChunkPos, BlockState)}, 186 | * but the {@link BlockState} is {@link Blocks#AIR}. 187 | */ 188 | public static void clearChunkBlocks(ServerWorld world, ChunkPos chunkPos) 189 | { 190 | fillChunkBlocks(world, chunkPos, Blocks.AIR.getDefaultState()); 191 | } 192 | // ================================================== 193 | } 194 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /chunkcopy-fabric-1.18.2/src/main/java/thecsdev/chunkcopy/command/ChunkCopyCommand.java: -------------------------------------------------------------------------------- 1 | package thecsdev.chunkcopy.command; 2 | 3 | import com.mojang.brigadier.CommandDispatcher; 4 | import com.mojang.brigadier.arguments.ArgumentType; 5 | import com.mojang.brigadier.arguments.IntegerArgumentType; 6 | import com.mojang.brigadier.builder.LiteralArgumentBuilder; 7 | import com.mojang.brigadier.builder.RequiredArgumentBuilder; 8 | import com.mojang.brigadier.context.CommandContext; 9 | 10 | import net.fabricmc.api.EnvType; 11 | import net.minecraft.block.BlockState; 12 | import net.minecraft.block.Blocks; 13 | import net.minecraft.command.CommandSource; 14 | import net.minecraft.command.argument.BlockStateArgument; 15 | import net.minecraft.command.argument.BlockStateArgumentType; 16 | import thecsdev.chunkcopy.ChunkCopy; 17 | import thecsdev.chunkcopy.api.AutoChunkCopy; 18 | import thecsdev.chunkcopy.api.AutoChunkCopy.ACCMode; 19 | import thecsdev.chunkcopy.command.argument.CopiedChunksArgumentType; 20 | 21 | /** 22 | * The {@link ChunkCopy} command. 23 | */ 24 | public abstract class ChunkCopyCommand 25 | { 26 | // ================================================== 27 | protected static final IntegerArgumentType ChunkDistArg = IntegerArgumentType.integer(1, 8); 28 | // ================================================== 29 | public void register(CommandDispatcher dispatcher) 30 | { 31 | //register 32 | dispatcher.register(literal(getCommandName()).executes(arg -> exec(arg)) 33 | //copying 34 | .then(literal("copy").requires(arg -> canCopy(arg)) 35 | .then(argument("fileName", CopiedChunksArgumentType.forCopying()) 36 | .executes(arg -> exec_copy_fileName(arg)) 37 | .then(argument("chunkDistance", ChunkDistArg) 38 | .executes(arg -> exec_copy_fileName_chunkDistance(arg))))) 39 | 40 | //pasting 41 | .then(literal("paste").requires(arg -> canPaste(arg)) 42 | .then(argument("fileName", CopiedChunksArgumentType.forPasting()) 43 | .executes(arg -> exec_paste_fileName(arg)) 44 | .then(argument("chunkDistance", ChunkDistArg) 45 | .executes(arg -> exec_paste_fileName_chunkDistance(arg))))) 46 | 47 | //filling 48 | .then(literal("fill").requires(arg -> canPaste(arg)) 49 | .then(argument("chunkDistance", ChunkDistArg) 50 | .then(argument("blockState", BlockStateArgumentType.blockState()) 51 | .executes(arg -> exec_fill_chunkDistance_block(arg))))) 52 | 53 | //clearing 54 | .then(literal("clear").requires(arg -> canPaste(arg)) 55 | .then(argument("chunkDistance", ChunkDistArg) 56 | .executes(arg -> exec_clear_chunkDistance(arg)))) 57 | 58 | //config 59 | /*.then(literal("settings").requires(arg -> canConfig(arg)) 60 | .then(argument("key", ConfigKeyArgumentType.configKeyId()) 61 | .then(argument("value", ConfigValueArgumentType.configStringValue()) 62 | .executes(arg -> exec_config_key_value(arg)) 63 | )))*/ 64 | 65 | //auto-copying 66 | .then(literal("auto").requires(arg -> AutoChunkCopy.validate()) 67 | .then(literal("copy").requires(arg -> canCopy(arg)) 68 | .then(argument("fileName", CopiedChunksArgumentType.forCopying()) 69 | .executes(arg -> exec_autoChunkCopy_start_fileName(arg, ACCMode.Copying)))) 70 | .then(literal("paste").requires(arg -> canPaste(arg)) 71 | .then(argument("fileName", CopiedChunksArgumentType.forPasting()) 72 | .executes(arg -> exec_autoChunkCopy_start_fileName(arg, ACCMode.Pasting)))) 73 | .then(literal("stop") 74 | .executes(arg -> exec_autoChunkCopy_stop(arg))) 75 | ) 76 | ); 77 | } 78 | // -------------------------------------------------- 79 | private int exec(CommandContext cs) { execMain(cs.getSource()); return 1; } 80 | // --------------- 81 | private int exec_copy_fileName(CommandContext cs) 82 | { 83 | copy(cs.getSource(), cs.getArgument("fileName", String.class), 8); 84 | return 1; 85 | } 86 | 87 | private int exec_copy_fileName_chunkDistance(CommandContext cs) 88 | { 89 | copy(cs.getSource(), cs.getArgument("fileName", String.class), cs.getArgument("chunkDistance", Integer.class)); 90 | return 1; 91 | } 92 | // --------------- 93 | private int exec_paste_fileName(CommandContext cs) 94 | { 95 | paste(cs.getSource(), cs.getArgument("fileName", String.class), 8); 96 | return 1; 97 | } 98 | 99 | private int exec_paste_fileName_chunkDistance(CommandContext cs) 100 | { 101 | paste(cs.getSource(), cs.getArgument("fileName", String.class), cs.getArgument("chunkDistance", Integer.class)); 102 | return 1; 103 | } 104 | // --------------- 105 | private int exec_fill_chunkDistance_block(CommandContext cs) 106 | { 107 | fill(cs.getSource(), cs.getArgument("chunkDistance", Integer.class), 108 | cs.getArgument("blockState", BlockStateArgument.class).getBlockState()); 109 | return 1; 110 | } 111 | 112 | private int exec_clear_chunkDistance(CommandContext cs) 113 | { 114 | fill(cs.getSource(), cs.getArgument("chunkDistance", Integer.class), 115 | Blocks.AIR.getDefaultState()); 116 | return 1; 117 | } 118 | // --------------- 119 | private int exec_autoChunkCopy_start_fileName(CommandContext cs, ACCMode accMode) 120 | { 121 | autoChunkCopyStart(cs.getSource(), cs.getArgument("fileName", String.class), accMode); 122 | return 1; 123 | } 124 | 125 | private int exec_autoChunkCopy_stop(CommandContext cs) 126 | { 127 | autoChunkCopyStop(cs.getSource()); 128 | return 1; 129 | } 130 | // --------------- 131 | /*private int exec_config_key_value(CommandContext cs) 132 | { 133 | return 1; 134 | }*/ 135 | // ================================================== 136 | /** 137 | * The name of the command. Must be constant! 138 | */ 139 | public abstract String getCommandName(); 140 | // -------------------------------------------------- 141 | /** 142 | * Returns true if a {@link CommandSource} can 143 | * execute copying commands. 144 | * @param commandSource The command executor. 145 | */ 146 | protected abstract boolean canCopy(CS commandSource); 147 | 148 | /** 149 | * Returns true if a {@link CommandSource} can 150 | * execute pasting commands (ex. paste, fill, clear). 151 | * @param commandSource The command executor. 152 | */ 153 | protected abstract boolean canPaste(CS commandSource); 154 | 155 | /** 156 | * Returns true if a {@link CommandSource} can 157 | * access and modify the mod config. 158 | */ 159 | protected abstract boolean canConfig(CS commandSource); 160 | // -------------------------------------------------- 161 | /** 162 | * Used to make a command syntax require a 163 | * specific {@link EnvType}. 164 | * @param env The required {@link EnvType}. 165 | */ 166 | protected final boolean requireEnv(EnvType env) 167 | { 168 | try { return ChunkCopy.getEnviroment() == env; } 169 | catch (Exception e) { return false; } 170 | } 171 | // -------------------------------------------------- 172 | protected abstract void execMain(CS commandSource); 173 | 174 | protected abstract void copy(CS commandSource, String fileName, int chunkDistance); 175 | protected abstract void paste(CS commandSource, String fileName, int chunkDistance); 176 | protected abstract void fill(CS commandSource, int chunkDistance, BlockState block); 177 | protected final void clear(CS commandSource, int chunkDistance) { fill(commandSource, chunkDistance, Blocks.AIR.getDefaultState()); } 178 | 179 | protected abstract void autoChunkCopyStart(CS commandSource, String fileName, ACCMode accMode); 180 | protected abstract void autoChunkCopyStop(CS commandSource); 181 | // ================================================== 182 | /** 183 | * Creates a literal argument builder. 184 | * 185 | * @param name the literal name 186 | * @return the created argument builder 187 | */ 188 | public LiteralArgumentBuilder literal(String name) { return LiteralArgumentBuilder.literal(name); } 189 | // -------------------------------------------------- 190 | /** 191 | * Creates a required argument builder. 192 | * 193 | * @param name the name of the argument 194 | * @param type the type of the argument 195 | * @param the type of the parsed argument value 196 | * @return the created argument builder 197 | */ 198 | public RequiredArgumentBuilder argument(String name, ArgumentType type) 199 | { 200 | return RequiredArgumentBuilder.argument(name, type); 201 | } 202 | // ================================================== 203 | protected static String getExceptionMessage(Throwable e) 204 | { 205 | StringBuilder sb = new StringBuilder(); 206 | sb.append(e.getClass().getCanonicalName() + ": " + e.getMessage() + "\n"); 207 | for (StackTraceElement ste : e.getStackTrace()) 208 | { 209 | if(!ste.getClassName().contains("thecsdev")) continue; 210 | sb.append(ste.toString() + "\n"); 211 | break; 212 | } 213 | return sb.toString().trim(); 214 | } 215 | // ================================================== 216 | } 217 | --------------------------------------------------------------------------------