├── versions ├── mainProject ├── mapping-1.18.2-1.19.2.txt ├── 1.19.3 │ ├── gradle.properties │ └── .factorypath ├── 1.17.1 │ ├── gradle.properties │ └── .factorypath ├── 1.19.2 │ ├── gradle.properties │ └── .factorypath ├── 1.18.2 │ ├── gradle.properties │ └── .factorypath ├── 1.19.4 │ ├── gradle.properties │ └── .factorypath ├── 1.20.1 │ ├── gradle.properties │ └── .factorypath └── 1.20.2 │ ├── gradle.properties │ └── .factorypath ├── jitpack.yml ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── src └── main │ ├── resources │ ├── assets │ │ └── intricarpet │ │ │ └── icon.png │ ├── intricarpet.mixins.json │ └── fabric.mod.json │ └── java │ └── me │ └── lntricate │ └── intricarpet │ ├── interfaces │ ├── IChunkMap.java │ └── IServerPlayer.java │ ├── PreLaunch.java │ ├── mixins │ ├── ExplosionDamageAccessor.java │ ├── logger │ │ ├── ServerLevelMixin.java │ │ └── ExplosionLogHelperMixin.java │ ├── interactions │ │ ├── ProjectileMixin.java │ │ ├── EntitySelectorMixin.java │ │ ├── ServerPlayerMixin.java │ │ ├── NaturalSpawnerMixin.java │ │ ├── ServerChunkCacheMixin.java │ │ ├── ChunkMapMixin.java │ │ ├── EntityMixin.java │ │ └── ServerGamePacketListenerImplMixin.java │ └── OptimizedExplosionMixin.java │ ├── Rules.java │ ├── logging │ ├── LoggerRegistry.java │ └── logHelpers │ │ └── ExplosionLogHelper.java │ ├── helpers │ ├── ExplosionHelper.java │ └── OptimizedExplosion.java │ ├── IntricarpetMod.java │ ├── interactions │ └── Interaction.java │ └── commands │ └── InteractionCommand.java ├── .github ├── workflows │ ├── gradle.yml │ ├── matrix_includes.json │ ├── scripts │ │ └── summary.py │ ├── matrix_prep.yml │ ├── build.yml │ └── release.yml └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── .gitignore ├── gradle.properties ├── settings.gradle ├── README.md ├── gradlew.bat ├── common.gradle ├── LICENSE └── gradlew /versions/mainProject: -------------------------------------------------------------------------------- 1 | 1.17.1 2 | -------------------------------------------------------------------------------- /jitpack.yml: -------------------------------------------------------------------------------- 1 | before_install: 2 | - sdk install java 17.0.1-open 3 | - sdk use java 17.0.1-open 4 | -------------------------------------------------------------------------------- /versions/mapping-1.18.2-1.19.2.txt: -------------------------------------------------------------------------------- 1 | net.minecraft.network.chat.BaseComponent net.minecraft.network.chat.Component 2 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lntricate1/intricarpet/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/resources/assets/intricarpet/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lntricate1/intricarpet/HEAD/src/main/resources/assets/intricarpet/icon.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /.github/workflows/gradle.yml: -------------------------------------------------------------------------------- 1 | name: Dev Builds 2 | 3 | on: 4 | push: 5 | paths: 6 | - "*.gradle" 7 | - "gradle.properties" 8 | - "src/**" 9 | - "versions/**" 10 | - ".github/**" 11 | pull_request: 12 | 13 | 14 | jobs: 15 | build: 16 | uses: ./.github/workflows/build.yml 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # gradle 2 | 3 | .gradle/ 4 | build/ 5 | out/ 6 | classes/ 7 | 8 | # eclipse 9 | 10 | *.launch 11 | 12 | # idea 13 | 14 | .idea/ 15 | *.iml 16 | *.ipr 17 | *.iws 18 | 19 | # vscode 20 | 21 | .settings/ 22 | .vscode/ 23 | bin/ 24 | .classpath 25 | .project 26 | 27 | # macos 28 | 29 | *.DS_Store 30 | 31 | # fabric 32 | 33 | run/ 34 | -------------------------------------------------------------------------------- /.github/workflows/matrix_includes.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "subproject_dir": "1.14.4" 4 | }, 5 | { 6 | "subproject_dir": "1.15.2" 7 | }, 8 | { 9 | "subproject_dir": "1.16.5" 10 | }, 11 | { 12 | "subproject_dir": "1.17.1" 13 | }, 14 | { 15 | "subproject_dir": "1.18.2" 16 | }, 17 | { 18 | "subproject_dir": "1.19.x" 19 | } 20 | ] 21 | -------------------------------------------------------------------------------- /src/main/java/me/lntricate/intricarpet/interfaces/IChunkMap.java: -------------------------------------------------------------------------------- 1 | package me.lntricate.intricarpet.interfaces; 2 | 3 | import me.lntricate.intricarpet.interactions.Interaction; 4 | import net.minecraft.world.level.ChunkPos; 5 | 6 | public interface IChunkMap 7 | { 8 | public boolean anyPlayerCloseWithInteraction(ChunkPos chunkPos, Interaction interaction); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/me/lntricate/intricarpet/PreLaunch.java: -------------------------------------------------------------------------------- 1 | package me.lntricate.intricarpet; 2 | 3 | import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint; 4 | import com.llamalad7.mixinextras.MixinExtrasBootstrap; 5 | 6 | public class PreLaunch implements PreLaunchEntrypoint 7 | { 8 | @Override 9 | public void onPreLaunch() 10 | { 11 | MixinExtrasBootstrap.init(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Motivation 11 | 12 | Why do you want this feature? What problem do you want to solve? How can the suggested feature help with that? 13 | 14 | ## Description 15 | 16 | Describe the feature you want, as detailed as possible 17 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Gradle Properties 2 | org.gradle.jvmargs=-Xmx4G 3 | org.gradle.parallel=true 4 | 5 | # Fabric Properties 6 | # https://fabricmc.net/versions.html 7 | loader_version=0.14.19 8 | 9 | # Mod Properties 10 | mod_id = intricarpet 11 | mod_name = IntriCarpet 12 | mod_version = 2.0.2 13 | maven_group = me.lntricate 14 | archives_base_name = intricarpet 15 | 16 | # Global Dependencies 17 | -------------------------------------------------------------------------------- /src/main/java/me/lntricate/intricarpet/interfaces/IServerPlayer.java: -------------------------------------------------------------------------------- 1 | package me.lntricate.intricarpet.interfaces; 2 | 3 | import java.util.Map; 4 | 5 | import me.lntricate.intricarpet.interactions.Interaction; 6 | 7 | public interface IServerPlayer 8 | { 9 | public boolean getInteraction(Interaction key); 10 | public Map getInteractions(); 11 | public void setInteraction(Interaction key, boolean value); 12 | } 13 | -------------------------------------------------------------------------------- /versions/1.19.3/gradle.properties: -------------------------------------------------------------------------------- 1 | # Fabric Properties 2 | # check these on https://fabricmc.net/versions.html?&version=1.18.2 3 | minecraft_version=1.19.3 4 | yarn_mappings=1.19.3+build.5 5 | 6 | # Fabric Mod Metadata 7 | minecraft_dependency=1.19.3 8 | carpet_dependency=>=1.4.96 9 | 10 | # Build Information 11 | # The target mc versions for the mod during mod publishing, separated with \n 12 | game_versions=1.19.3 13 | 14 | # Dependencies 15 | carpet_version=1.19.3-1.4.96+v230201 16 | -------------------------------------------------------------------------------- /versions/1.17.1/gradle.properties: -------------------------------------------------------------------------------- 1 | # Fabric Properties 2 | # check these on https://fabricmc.net/versions.html?&version=1.17.1 3 | minecraft_version=1.17.1 4 | yarn_mappings=1.17.1+build.65 5 | 6 | # Fabric Mod Metadata 7 | minecraft_dependency=1.17.x 8 | carpet_dependency=>=1.4.57 9 | 10 | # Build Information 11 | # The target mc versions for the mod during mod publishing, separated with \n 12 | game_versions=1.17.1 13 | 14 | # Dependencies 15 | carpet_version=1.17.1-1.4.57+v220119 16 | -------------------------------------------------------------------------------- /versions/1.19.2/gradle.properties: -------------------------------------------------------------------------------- 1 | # Fabric Properties 2 | # check these on https://fabricmc.net/versions.html?&version=1.18.2 3 | minecraft_version=1.19.2 4 | yarn_mappings=1.19.2+build.28 5 | 6 | # Fabric Mod Metadata 7 | minecraft_dependency=1.19.2 8 | carpet_dependency=>=1.4.84 9 | 10 | # Build Information 11 | # The target mc versions for the mod during mod publishing, separated with \n 12 | game_versions=1.19.2 13 | 14 | # Dependencies 15 | carpet_version=1.19.2-1.4.84+v221018 16 | -------------------------------------------------------------------------------- /versions/1.18.2/gradle.properties: -------------------------------------------------------------------------------- 1 | # Fabric Properties 2 | # check these on https://fabricmc.net/versions.html?&version=1.18.2 3 | minecraft_version=1.18.2 4 | yarn_mappings=1.18.2+build.4 5 | 6 | # Fabric Mod Metadata 7 | minecraft_dependency=1.18.x 8 | carpet_dependency=>=1.4.69 9 | 10 | # Build Information 11 | # The target mc versions for the mod during mod publishing, separated with \n 12 | game_versions=1.18.2 13 | 14 | # Dependencies 15 | # fabric_api_version=0.59.1+1.18.2 16 | carpet_version=1.18.2-1.4.69+v220331 17 | -------------------------------------------------------------------------------- /versions/1.19.4/gradle.properties: -------------------------------------------------------------------------------- 1 | # Fabric Properties 2 | # check these on https://fabricmc.net/versions.html?&version=1.19.4 3 | minecraft_version=1.19.4 4 | yarn_mappings=1.19.4+build.2 5 | 6 | # Fabric Mod Metadata 7 | minecraft_dependency=1.19.4 8 | carpet_dependency=>=1.4.100 9 | 10 | # Build Information 11 | # The target mc versions for the mod during mod publishing, separated with \n 12 | game_versions=1.19.4 13 | 14 | # Dependencies 15 | # fabric_api_version=0.75.3+1.19.4 16 | carpet_version=1.19.4-1.4.100+v230314 17 | -------------------------------------------------------------------------------- /versions/1.20.1/gradle.properties: -------------------------------------------------------------------------------- 1 | # Fabric Properties 2 | # check these on https://fabricmc.net/versions.html?&version=1.19.4 3 | minecraft_version=1.20.1 4 | yarn_mappings=1.20.1+build.10 5 | 6 | # Fabric Mod Metadata 7 | minecraft_dependency=1.20.1 8 | carpet_dependency=>=1.4.112 9 | 10 | # Build Information 11 | # The target mc versions for the mod during mod publishing, separated with \n 12 | game_versions=1.20.1 13 | 14 | # Dependencies 15 | # fabric_api_version=0.75.3+1.19.4 16 | carpet_version=1.20-1.4.112+v230608 17 | -------------------------------------------------------------------------------- /versions/1.20.2/gradle.properties: -------------------------------------------------------------------------------- 1 | # Fabric Properties 2 | # check these on https://fabricmc.net/versions.html?&version=1.19.4 3 | minecraft_version=1.20.2 4 | yarn_mappings=1.20.2+build.4 5 | 6 | # Fabric Mod Metadata 7 | minecraft_dependency=1.20.2 8 | carpet_dependency=>=1.4.119 9 | 10 | # Build Information 11 | # The target mc versions for the mod during mod publishing, separated with \n 12 | game_versions=1.20.2 13 | 14 | # Dependencies 15 | # fabric_api_version=0.75.3+1.19.4 16 | carpet_version=1.20.2-1.4.119+v230928 17 | -------------------------------------------------------------------------------- /src/main/java/me/lntricate/intricarpet/mixins/ExplosionDamageAccessor.java: -------------------------------------------------------------------------------- 1 | package me.lntricate.intricarpet.mixins; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.gen.Accessor; 5 | 6 | import net.minecraft.world.entity.Entity; 7 | import net.minecraft.world.level.Explosion; 8 | import net.minecraft.world.level.ExplosionDamageCalculator; 9 | 10 | @Mixin(Explosion.class) 11 | public interface ExplosionDamageAccessor 12 | { 13 | @Accessor 14 | ExplosionDamageCalculator getDamageCalculator(); 15 | 16 | @Accessor 17 | Entity getSource(); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/me/lntricate/intricarpet/Rules.java: -------------------------------------------------------------------------------- 1 | package me.lntricate.intricarpet; 2 | 3 | import carpet.settings.Rule; 4 | 5 | public class Rules 6 | { 7 | @Rule( 8 | desc = "Enables /interaction command for controlling the effects of players on the environment", 9 | category = {"COMMAND", "intricarpet"}, 10 | options = {"true", "false", "ops"} 11 | ) 12 | public static String commandInteraction = "ops"; 13 | 14 | @Rule( 15 | desc = "Enables edge case fixes in optimizedTNT, at the cost of a bit less optimization", 16 | category = {"COMMAND", "intricarpet"} 17 | ) 18 | public static boolean optimizedTNTEdgeCases = false; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/resources/intricarpet.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "me.lntricate.intricarpet.mixins", 5 | "compatibilityLevel": "JAVA_8", 6 | "mixins": [ 7 | "OptimizedExplosionMixin", 8 | 9 | "logger.ExplosionLogHelperMixin", 10 | "logger.ServerLevelMixin", 11 | 12 | "interactions.ChunkMapMixin", 13 | "interactions.EntityMixin", 14 | "interactions.EntitySelectorMixin", 15 | "interactions.NaturalSpawnerMixin", 16 | "interactions.ProjectileMixin", 17 | "interactions.ServerChunkCacheMixin", 18 | "interactions.ServerGamePacketListenerImplMixin", 19 | "interactions.ServerPlayerMixin" 20 | ], 21 | "client": [ 22 | ], 23 | "injectors": { 24 | "defaultRequire": 1 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/me/lntricate/intricarpet/mixins/logger/ServerLevelMixin.java: -------------------------------------------------------------------------------- 1 | package me.lntricate.intricarpet.mixins.logger; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.injection.Inject; 5 | import org.spongepowered.asm.mixin.injection.At; 6 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 7 | 8 | import me.lntricate.intricarpet.logging.logHelpers.ExplosionLogHelper; 9 | import net.minecraft.server.level.ServerLevel; 10 | 11 | @Mixin(ServerLevel.class) 12 | public class ServerLevelMixin 13 | { 14 | @Inject(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/entity/PersistentEntitySectionManager;tick()V")) 15 | private void afterEntities(CallbackInfo ci) 16 | { 17 | ExplosionLogHelper.afterEntities(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "${id}", 4 | "version": "${version}", 5 | 6 | "name": "${name}", 7 | "description": "A carpet extension useful for TNT tech.", 8 | "authors": [ 9 | "lntricate" 10 | ], 11 | "contact": { 12 | "sources": "https://github.com/lntricate1/intricarpet" 13 | }, 14 | 15 | "icon": "assets/${id}/icon.png", 16 | 17 | "environment": "*", 18 | "entrypoints": { 19 | "main": [ 20 | "me.lntricate.${id}.IntricarpetMod" 21 | ], 22 | "preLaunch": [ 23 | "me.lntricate.${id}.PreLaunch" 24 | ] 25 | }, 26 | "mixins": [ 27 | "${id}.mixins.json" 28 | ], 29 | 30 | "depends": { 31 | "fabricloader": ">=0.11.4", 32 | "minecraft": "${minecraft_dependency}", 33 | "carpet": "${carpet_dependency}" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/me/lntricate/intricarpet/logging/LoggerRegistry.java: -------------------------------------------------------------------------------- 1 | package me.lntricate.intricarpet.logging; 2 | 3 | import carpet.logging.Logger; 4 | 5 | public class LoggerRegistry 6 | { 7 | public static boolean __explosions; 8 | 9 | public static void registerLoggers() 10 | { 11 | carpet.logging.LoggerRegistry.registerLogger("explosions", standardLogger("explosions", "brief", new String[]{"compact", "brief", "full"}, true)); 12 | } 13 | 14 | static Logger standardLogger(String logName, String def, String [] options, boolean strictOptions) 15 | { 16 | try 17 | { 18 | return new Logger(carpet.logging.LoggerRegistry.class.getField("__"+logName), logName, def, options, strictOptions); 19 | } 20 | catch(NoSuchFieldException e) 21 | { 22 | throw new RuntimeException("Failed to create logger "+logName); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/me/lntricate/intricarpet/mixins/interactions/ProjectileMixin.java: -------------------------------------------------------------------------------- 1 | package me.lntricate.intricarpet.mixins.interactions; 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.CallbackInfoReturnable; 7 | 8 | import me.lntricate.intricarpet.interactions.Interaction; 9 | import me.lntricate.intricarpet.interfaces.IServerPlayer; 10 | import net.minecraft.world.entity.Entity; 11 | import net.minecraft.world.entity.projectile.Projectile; 12 | 13 | @Mixin(Projectile.class) 14 | public class ProjectileMixin 15 | { 16 | @Inject(method = "canHitEntity", at = @At("HEAD"), cancellable = true) 17 | private void canHitEntity(Entity entity, CallbackInfoReturnable cir) 18 | { 19 | if(entity instanceof IServerPlayer player && !player.getInteraction(Interaction.ENTITIES)) 20 | cir.setReturnValue(false); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Something doesn't seem correct and it might be a bug 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Description 11 | 12 | A clear and concise description of what the bug is. It's a Minecraft crash, an unexpected behavior, or something not right. 13 | 14 | If applicable, add screenshots to help explain your problem. 15 | 16 | ## To Reproduce 17 | 18 | Steps to reproduce the behavior: 19 | 20 | 1. Go to '...' 21 | 2. Click on '....' 22 | 3. Scroll down to '....' 23 | 4. ... 24 | 25 | What you expect to see: '...' 26 | 27 | What actually happens: '...' 28 | 29 | ## Environment 30 | 31 | Describe the environment to reproduce this bug: 32 | 33 | - Minecraft version: '...' 34 | - TemplateMod version: '...' 35 | - Other related mod versions: '...' 36 | - ... 37 | 38 | ## Log 39 | 40 | If it's a crash, send the corresponding Minecraft log in the `logs` folder, or crash report in the `crash-reports`, as attachment here. 41 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { 4 | name = 'Fabric' 5 | url = 'https://maven.fabricmc.net/' 6 | } 7 | maven { 8 | name = 'Jitpack' 9 | url = "https://jitpack.io" 10 | } 11 | mavenCentral() 12 | gradlePluginPortal() 13 | } 14 | resolutionStrategy { 15 | eachPlugin { 16 | switch (requested.id.id) { 17 | case "com.replaymod.preprocess": { 18 | useModule("com.github.Fallen-Breath:preprocessor:${requested.version}") 19 | break 20 | } 21 | } 22 | } 23 | } 24 | } 25 | 26 | def versions = Arrays.asList( 27 | // "1.14.4", 28 | // "1.15.2", 29 | // "1.16.5", 30 | "1.17.1", 31 | "1.18.2", 32 | "1.19.2", 33 | "1.19.3", 34 | "1.19.4", 35 | "1.20.1", 36 | "1.20.2" 37 | // "snapshot", 38 | ) 39 | for (String version : versions) { 40 | include(":$version") 41 | 42 | def proj = project(":$version") 43 | proj.projectDir = file("versions/$version") 44 | proj.buildFileName = "../../common.gradle" 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/me/lntricate/intricarpet/mixins/interactions/EntitySelectorMixin.java: -------------------------------------------------------------------------------- 1 | package me.lntricate.intricarpet.mixins.interactions; 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.CallbackInfoReturnable; 7 | 8 | import com.google.common.base.Predicate; 9 | import com.google.common.base.Predicates; 10 | 11 | import me.lntricate.intricarpet.interactions.Interaction; 12 | import me.lntricate.intricarpet.interfaces.IServerPlayer; 13 | import net.minecraft.world.entity.Entity; 14 | import net.minecraft.world.entity.EntitySelector; 15 | 16 | @Mixin(EntitySelector.class) 17 | public class EntitySelectorMixin 18 | { 19 | @Inject(method = "pushableBy", at = @At("HEAD"), cancellable = true) 20 | private static void pushableBy(Entity entity, CallbackInfoReturnable> cir) 21 | { 22 | if(entity instanceof IServerPlayer player && !player.getInteraction(Interaction.ENTITIES)) 23 | cir.setReturnValue(Predicates.alwaysFalse()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## IntriCarpet 2 | 3 | [![License](https://img.shields.io/github/license/Fallen-Breath/fabric-mod-template.svg)](http://www.gnu.org/licenses/lgpl-3.0.html) 4 | 5 | This mod uses Fallen's fabric mod template. 6 | 7 | This is a carpet extension that adds mainly stuff useful for TNT tech development. 8 | 9 | ## Features 10 | - Improved explosion logger, which groups explosions by position: `/log explosions compact` 11 | - Adds Interactions, which let you disable the interactions between your player and the world, per player. 12 | 13 | ## Interactions 14 | - Blocks: Includes tripwire, pressure plates, trampling farmland, etc. 15 | - Chunkloading: Toggles all chunkloading for the player, including teleport tickets. 16 | - Entities: Makes all entities noclip through the player. 17 | - Mob Spawning: Disables the player's effect on mob spawning. Does not disable your effects on the mobcap. 18 | - Random Ticks: Disables the player's effect on random ticks. 19 | - Updates: Suppresses all updates caused by the player's interactions with the world. 20 | 21 | Command format: 22 | - `/interaction`: Shows your current interaction settings. 23 | - `/interaction `: Displays the value of the specified interaction. 24 | - `/interaction `: Changes the value of the specified interaction. 25 | -------------------------------------------------------------------------------- /.github/workflows/scripts/summary.py: -------------------------------------------------------------------------------- 1 | import glob 2 | import json 3 | import os 4 | 5 | 6 | def read_prop(file_name: str, key: str) -> str: 7 | with open(file_name) as prop: 8 | return next(filter( 9 | lambda l: l.split('=', 1)[0].strip() == key, 10 | prop.readlines() 11 | )).split('=', 1)[1].lstrip() 12 | 13 | 14 | target_subproject = os.environ.get('TARGET_SUBPROJECT', '') 15 | with open('.github/workflows/matrix_includes.json') as f: 16 | matrix: list[dict] = json.load(f) 17 | 18 | with open(os.environ['GITHUB_STEP_SUMMARY'], 'w') as f: 19 | f.write('## Build Artifacts Summary\n\n') 20 | f.write('| Subproject | for Minecraft | Files |\n') 21 | f.write('| --- | --- | --- |\n') 22 | 23 | for m in matrix: 24 | subproject = m['subproject_dir'] 25 | if target_subproject != '' and subproject != target_subproject: 26 | continue 27 | game_versions = read_prop('versions/{}/gradle.properties'.format(subproject), 'game_versions') 28 | game_versions = game_versions.strip().replace('\\n', ', ') 29 | file_names = glob.glob('build-artifacts/{}/build/libs/*.jar'.format(subproject)) 30 | file_names = ', '.join(map( 31 | lambda fn: '`{}`'.format(os.path.basename(fn)), 32 | filter(lambda fn: not fn.endswith('-sources.jar') and not fn.endswith('-dev.jar'), file_names) 33 | )) 34 | f.write('| {} | {} | {} |\n'.format(subproject, game_versions, file_names)) 35 | -------------------------------------------------------------------------------- /src/main/java/me/lntricate/intricarpet/mixins/interactions/ServerPlayerMixin.java: -------------------------------------------------------------------------------- 1 | package me.lntricate.intricarpet.mixins.interactions; 2 | 3 | import me.lntricate.intricarpet.interactions.Interaction; 4 | import me.lntricate.intricarpet.interfaces.IServerPlayer; 5 | 6 | import java.util.Map; 7 | 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Inject; 11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 12 | 13 | import net.minecraft.server.level.ServerPlayer; 14 | 15 | @Mixin(ServerPlayer.class) 16 | public class ServerPlayerMixin implements IServerPlayer 17 | { 18 | private Map interactions; 19 | 20 | @Inject(method = "", at = @At("TAIL")) 21 | private void onInit(CallbackInfo ci) 22 | { 23 | interactions = Interaction.get(((ServerPlayer)(Object)this).getUUID()); 24 | } 25 | 26 | @Override 27 | public boolean getInteraction(Interaction key) 28 | { 29 | return interactions.get(key); 30 | } 31 | 32 | @Override 33 | public Map getInteractions() 34 | { 35 | return interactions; 36 | } 37 | 38 | @Override 39 | public void setInteraction(Interaction key, boolean value) 40 | { 41 | interactions.put(key, value); 42 | Interaction.set(((ServerPlayer)(Object)this).getUUID(), key, value); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /.github/workflows/matrix_prep.yml: -------------------------------------------------------------------------------- 1 | name: step.matrix_prepare 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | target_subproject: 7 | description: The subproject name of the specified Minecraft version for generating matrix entry 8 | type: string 9 | required: false 10 | default: '' 11 | outputs: 12 | matrix: 13 | description: The generated run matrix 14 | value: ${{ jobs.matrix_prep.outputs.matrix }} 15 | 16 | 17 | jobs: 18 | matrix_prep: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v3 22 | 23 | - name: Display context 24 | run: | 25 | echo ref_name = ${{ github.ref_name }} 26 | echo target_subproject = ${{ github.event.inputs.target_subproject }} 27 | echo target_release_tag = ${{ github.event.inputs.target_release_tag }} 28 | 29 | - id: setmatrix 30 | uses: JoshuaTheMiller/conditional-build-matrix@v1.0.1 31 | with: 32 | # inputFile: '.github/workflows/matrix_includes.json' # Default input file path 33 | filter: '[? `${{ github.event_name }}` == `release` || `${{ github.event.inputs.target_subproject }}` == `` || `"${{ github.event.inputs.target_subproject }}"` == subproject_dir ]' 34 | 35 | - name: Print matrix 36 | run: echo ${{ steps.setmatrix.outputs.matrix }} 37 | 38 | outputs: 39 | matrix: ${{ steps.setmatrix.outputs.matrix }} 40 | -------------------------------------------------------------------------------- /src/main/java/me/lntricate/intricarpet/mixins/interactions/NaturalSpawnerMixin.java: -------------------------------------------------------------------------------- 1 | package me.lntricate.intricarpet.mixins.interactions; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.injection.At; 5 | import org.spongepowered.asm.mixin.injection.Redirect; 6 | 7 | import me.lntricate.intricarpet.interactions.Interaction; 8 | import me.lntricate.intricarpet.interfaces.IServerPlayer; 9 | import net.minecraft.server.level.ServerLevel; 10 | import net.minecraft.world.entity.player.Player; 11 | import net.minecraft.world.level.NaturalSpawner; 12 | 13 | @Mixin(NaturalSpawner.class) 14 | public class NaturalSpawnerMixin 15 | { 16 | @Redirect(method = "Lnet/minecraft/world/level/NaturalSpawner;spawnCategoryForPosition(Lnet/minecraft/world/entity/MobCategory;Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/level/chunk/ChunkAccess;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/NaturalSpawner$SpawnPredicate;Lnet/minecraft/world/level/NaturalSpawner$AfterSpawnCallback;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerLevel;getNearestPlayer(DDDDZ)Lnet/minecraft/world/entity/player/Player;")) 17 | private static Player getNearestPlayer(ServerLevel self, double a, double b, double c, double d, boolean e) 18 | { 19 | return self.getNearestPlayer(a, b, c, d, entity -> !(entity instanceof IServerPlayer player && !player.getInteraction(Interaction.MOBSPAWNING))); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/me/lntricate/intricarpet/helpers/ExplosionHelper.java: -------------------------------------------------------------------------------- 1 | package me.lntricate.intricarpet.helpers; 2 | 3 | import net.minecraft.world.phys.Vec3; 4 | 5 | public class ExplosionHelper 6 | { 7 | private static Vec3 pos = null; 8 | private static int countInPos = 0; 9 | private static int countInTick = 0; 10 | private static long tick = 0; 11 | private static long time = 0; 12 | private static boolean affectBlocks; 13 | 14 | public static Vec3 getPos(){return pos;} 15 | public static int getCountInPos(){return countInPos;} 16 | public static int getCountInTick(){return countInTick;} 17 | public static long getTick(){return tick;} 18 | public static long getTime(){return time;} 19 | public static boolean getAffectBlocks(){return affectBlocks;} 20 | 21 | public static boolean isNew(Vec3 pos_, long tick_) 22 | { 23 | return tick != tick_ || !pos.equals(pos_); 24 | } 25 | 26 | public static boolean isEmpty() 27 | { 28 | return pos == null; 29 | } 30 | 31 | public static void registerNewPos(Vec3 pos_, long tick_, long time_, boolean affectBlocks_) 32 | { 33 | pos = pos_; 34 | tick = tick_; 35 | countInPos = 1; 36 | countInTick += 1; 37 | time = time_; 38 | affectBlocks = affectBlocks_; 39 | } 40 | 41 | public static void clear() 42 | { 43 | pos = null; 44 | countInTick = 0; 45 | } 46 | 47 | public static void incrementCounts(long tick) 48 | { 49 | countInPos ++; 50 | countInTick ++; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/me/lntricate/intricarpet/mixins/OptimizedExplosionMixin.java: -------------------------------------------------------------------------------- 1 | package me.lntricate.intricarpet.mixins; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.Unique; 5 | import org.spongepowered.asm.mixin.injection.At; 6 | import org.spongepowered.asm.mixin.injection.Inject; 7 | import org.spongepowered.asm.mixin.injection.At.Shift; 8 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 9 | import org.spongepowered.asm.mixin.injection.callback.LocalCapture; 10 | 11 | import carpet.helpers.OptimizedExplosion; 12 | import carpet.logging.logHelpers.ExplosionLogHelper; 13 | import carpet.mixins.ExplosionAccessor; 14 | import me.lntricate.intricarpet.Rules; 15 | import net.minecraft.world.entity.Entity; 16 | import net.minecraft.world.level.Explosion; 17 | import net.minecraft.world.phys.Vec3; 18 | 19 | @Mixin(OptimizedExplosion.class) 20 | public class OptimizedExplosionMixin 21 | { 22 | @Unique private static final double SAME_POSITION_VELOCITY = 0.9923437498509884; 23 | 24 | @Inject(method = "doExplosionA", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;getZ()D", ordinal = 1, shift = Shift.BY, by = 3), locals = LocalCapture.CAPTURE_FAILHARD) 25 | private static void onSamePosition(Explosion e, ExplosionLogHelper eLogger, CallbackInfo ci, ExplosionAccessor eAccess, boolean eventNeeded, float f3, int k1, int l1, int i2, int i1, int j2, int j1, Vec3 vec3d, Entity explodingEntity, int k2, Entity entity) 26 | { 27 | if(Rules.optimizedTNTEdgeCases || !entity.isOnGround()) 28 | { 29 | Vec3 vel = entity.getDeltaMovement(); 30 | entity.setDeltaMovement(vel.x, vel.y - SAME_POSITION_VELOCITY, vel.z); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/me/lntricate/intricarpet/IntricarpetMod.java: -------------------------------------------------------------------------------- 1 | package me.lntricate.intricarpet; 2 | 3 | import net.fabricmc.api.ModInitializer; 4 | import net.fabricmc.loader.api.FabricLoader; 5 | import net.fabricmc.loader.api.metadata.ModMetadata; 6 | import net.minecraft.commands.CommandSourceStack; 7 | 8 | import org.apache.logging.log4j.LogManager; 9 | import org.apache.logging.log4j.Logger; 10 | 11 | import com.mojang.brigadier.CommandDispatcher; 12 | 13 | import carpet.CarpetExtension; 14 | import carpet.CarpetServer; 15 | import me.lntricate.intricarpet.commands.InteractionCommand; 16 | import me.lntricate.intricarpet.logging.LoggerRegistry; 17 | 18 | public class IntricarpetMod implements ModInitializer, CarpetExtension 19 | { 20 | public static final Logger LOGGER = LogManager.getLogger(); 21 | 22 | public static final String MOD_ID = "intricarpet"; 23 | public static String MOD_VERSION = "unknown"; 24 | public static String MOD_NAME = "unknown"; 25 | 26 | @Override 27 | public void onInitialize() 28 | { 29 | CarpetServer.manageExtension(new IntricarpetMod()); 30 | } 31 | 32 | @Override 33 | public void onGameStarted() 34 | { 35 | ModMetadata metadata = FabricLoader.getInstance().getModContainer(MOD_ID).orElseThrow(RuntimeException::new).getMetadata(); 36 | MOD_NAME = metadata.getName(); 37 | MOD_VERSION = metadata.getVersion().getFriendlyString(); 38 | 39 | CarpetServer.settingsManager.parseSettingsClass(Rules.class); 40 | } 41 | 42 | @Override 43 | public void registerCommands(CommandDispatcher dispatcher) 44 | { 45 | InteractionCommand.register(dispatcher); 46 | } 47 | 48 | @Override 49 | public void registerLoggers() 50 | { 51 | LoggerRegistry.registerLoggers(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/me/lntricate/intricarpet/mixins/logger/ExplosionLogHelperMixin.java: -------------------------------------------------------------------------------- 1 | package me.lntricate.intricarpet.mixins.logger; 2 | 3 | import java.util.List; 4 | 5 | import org.spongepowered.asm.mixin.Final; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.Shadow; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Inject; 10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 12 | 13 | import com.llamalad7.mixinextras.injector.ModifyReceiver; 14 | 15 | import carpet.logging.logHelpers.ExplosionLogHelper; 16 | import net.minecraft.network.chat.BaseComponent; 17 | import net.minecraft.world.phys.Vec3; 18 | 19 | @Mixin(ExplosionLogHelper.class) 20 | public class ExplosionLogHelperMixin 21 | { 22 | @Shadow @Final private Vec3 pos; 23 | @Shadow private boolean affectBlocks; 24 | 25 | @Inject(method = "onExplosionDone", at = @At("HEAD"), remap = false) 26 | private void onExplosionDone(long gametime, CallbackInfo ci) 27 | { 28 | me.lntricate.intricarpet.logging.logHelpers.ExplosionLogHelper.onExplosion(pos, gametime, affectBlocks); 29 | } 30 | 31 | private String option = ""; 32 | 33 | @Inject(method = "lambda$onExplosionDone$1", at = @At("HEAD"), remap = false) 34 | private void getOption(long gametime, String option_, CallbackInfoReturnable cir) 35 | { 36 | option = option_; 37 | } 38 | 39 | @ModifyReceiver(method = "lambda$onExplosionDone$1", at = @At(value = "INVOKE", target = "Ljava/util/List;toArray([Ljava/lang/Object;)[Ljava/lang/Object;", remap = false)) 40 | private List addLoggers(List messages, Object[] dummy) 41 | { 42 | return me.lntricate.intricarpet.logging.logHelpers.ExplosionLogHelper.onLog(messages, option); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/me/lntricate/intricarpet/mixins/interactions/ServerChunkCacheMixin.java: -------------------------------------------------------------------------------- 1 | package me.lntricate.intricarpet.mixins.interactions; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.Shadow; 5 | import org.spongepowered.asm.mixin.injection.At; 6 | 7 | import com.llamalad7.mixinextras.injector.WrapWithCondition; 8 | 9 | import me.lntricate.intricarpet.interactions.Interaction; 10 | import me.lntricate.intricarpet.interfaces.IChunkMap; 11 | import net.minecraft.server.level.ChunkMap; 12 | import net.minecraft.server.level.ServerChunkCache; 13 | import net.minecraft.server.level.ServerLevel; 14 | import net.minecraft.world.level.NaturalSpawner.SpawnState; 15 | import net.minecraft.world.level.chunk.LevelChunk; 16 | 17 | @Mixin(ServerChunkCache.class) 18 | public class ServerChunkCacheMixin 19 | { 20 | @Shadow private ChunkMap chunkMap; 21 | 22 | private static final String targetMethod = 23 | //#if MC >= 11800 24 | //$$ "tickChunks"; 25 | //#else 26 | "method_20801"; 27 | //#endif 28 | 29 | @WrapWithCondition(method = targetMethod, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/NaturalSpawner;spawnForChunk(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/level/chunk/LevelChunk;Lnet/minecraft/world/level/NaturalSpawner$SpawnState;ZZZ)V")) 30 | private boolean shouldSpawnMobs(ServerLevel a, LevelChunk levelChunk, SpawnState b, boolean c, boolean d, boolean e) 31 | { 32 | return ((IChunkMap)chunkMap).anyPlayerCloseWithInteraction(levelChunk.getPos(), Interaction.MOBSPAWNING); 33 | } 34 | 35 | @WrapWithCondition(method = targetMethod, at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerLevel;tickChunk(Lnet/minecraft/world/level/chunk/LevelChunk;I)V")) 36 | private boolean shouldRandomTick(ServerLevel instance, LevelChunk levelChunk, int i) 37 | { 38 | return ((IChunkMap)chunkMap).anyPlayerCloseWithInteraction(levelChunk.getPos(), Interaction.RANDOMTICKS); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/me/lntricate/intricarpet/interactions/Interaction.java: -------------------------------------------------------------------------------- 1 | package me.lntricate.intricarpet.interactions; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.UUID; 6 | 7 | public enum Interaction 8 | { 9 | BLOCKS ("blocks", "Blocks"), 10 | CHUNKLOADING("chunkloading", "Chunkloading"), 11 | ENTITIES ("entities", "Entities"), 12 | MOBSPAWNING ("mobSpawning", "Mob Spawning"), 13 | RANDOMTICKS ("randomTicks", "Random Ticks"), 14 | UPDATES ("updates", "Updates"); 15 | 16 | private final String name; 17 | private final String commandKey; 18 | 19 | private static final Map defaultInteractions = new HashMap<>(); 20 | private static final Map byCommandKey = new HashMap<>(); 21 | private static final Map> playerInteractionMap = new HashMap<>(); 22 | 23 | static 24 | { 25 | for(Interaction i : values()) 26 | { 27 | defaultInteractions.put(i, true); 28 | byCommandKey.put(i.commandKey, i); 29 | } 30 | } 31 | 32 | Interaction(String commandKey, String name) 33 | { 34 | this.commandKey = commandKey; 35 | this.name = name; 36 | } 37 | 38 | public static String[] commandKeys() 39 | { 40 | return byCommandKey.keySet().toArray(new String[0]); 41 | } 42 | 43 | public static Interaction byCommandKey(String key) 44 | { 45 | return byCommandKey.get(key); 46 | } 47 | 48 | public String getName() 49 | { 50 | return name; 51 | } 52 | 53 | public static Map get(UUID id) 54 | { 55 | Map interactions = playerInteractionMap.get(id); 56 | if(interactions != null) 57 | return interactions; 58 | 59 | interactions = new HashMap<>(defaultInteractions); 60 | playerInteractionMap.put(id, interactions); 61 | return interactions; 62 | } 63 | 64 | public static void set(UUID id, Interaction i, boolean value) 65 | { 66 | playerInteractionMap.get(id).put(i, value); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/me/lntricate/intricarpet/mixins/interactions/ChunkMapMixin.java: -------------------------------------------------------------------------------- 1 | package me.lntricate.intricarpet.mixins.interactions; 2 | 3 | import org.spongepowered.asm.mixin.Final; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.Shadow; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.Inject; 8 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 9 | 10 | import me.lntricate.intricarpet.interactions.Interaction; 11 | import me.lntricate.intricarpet.interfaces.IChunkMap; 12 | import me.lntricate.intricarpet.interfaces.IServerPlayer; 13 | import net.minecraft.server.level.ChunkMap; 14 | import net.minecraft.server.level.PlayerMap; 15 | import net.minecraft.server.level.ServerPlayer; 16 | import net.minecraft.world.entity.Entity; 17 | import net.minecraft.world.level.ChunkPos; 18 | 19 | @Mixin(ChunkMap.class) 20 | public class ChunkMapMixin implements IChunkMap 21 | { 22 | @Shadow private static double euclideanDistanceSquared(ChunkPos chunkPos, Entity entity){return 0.0;} 23 | @Shadow @Final private PlayerMap playerMap; 24 | 25 | private boolean playerValid(ServerPlayer player, ChunkPos chunkPos, Interaction interaction) 26 | { 27 | return ((IServerPlayer)player).getInteraction(interaction) && euclideanDistanceSquared(chunkPos, player) < 16384d; 28 | } 29 | 30 | @Override 31 | public boolean anyPlayerCloseWithInteraction(ChunkPos chunkPos, Interaction interaction) 32 | { 33 | //#if MC >= 11800 34 | //#if MC >= 12002 35 | //$$ for(ServerPlayer player : playerMap.getAllPlayers()) 36 | //#else 37 | //$$ for(ServerPlayer player : playerMap.getPlayers(chunkPos.toLong())) 38 | //#endif 39 | //$$ if(playerValid(player, chunkPos, interaction)) 40 | //$$ return true; 41 | //$$ return false; 42 | //#else 43 | return playerMap.getPlayers(chunkPos.toLong()).anyMatch(player -> playerValid(player, chunkPos, interaction)); 44 | //#endif 45 | } 46 | 47 | @Inject(method = "skipPlayer", at = @At("HEAD"), cancellable = true) 48 | private void skipPlayer(ServerPlayer player, CallbackInfoReturnable cir) 49 | { 50 | if(!((IServerPlayer)player).getInteraction(Interaction.CHUNKLOADING)) 51 | cir.setReturnValue(true); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/me/lntricate/intricarpet/logging/logHelpers/ExplosionLogHelper.java: -------------------------------------------------------------------------------- 1 | package me.lntricate.intricarpet.logging.logHelpers; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Locale; 6 | 7 | import carpet.logging.LoggerRegistry; 8 | import carpet.utils.Messenger; 9 | import me.lntricate.intricarpet.helpers.ExplosionHelper; 10 | import net.minecraft.network.chat.BaseComponent; 11 | import net.minecraft.world.phys.Vec3; 12 | 13 | public class ExplosionLogHelper 14 | { 15 | private static BaseComponent log; 16 | 17 | public static void onExplosion(Vec3 pos, long tick, boolean affectBlocks) 18 | { 19 | if(ExplosionHelper.isEmpty() || ExplosionHelper.isNew(pos, tick)) 20 | { 21 | long time = System.currentTimeMillis(); 22 | logCompact(time, false); 23 | ExplosionHelper.registerNewPos(pos, tick, time, affectBlocks); 24 | } 25 | else 26 | { 27 | log = null; 28 | ExplosionHelper.incrementCounts(tick); 29 | } 30 | } 31 | 32 | public static List onLog(List messages, String option) 33 | { 34 | if(option.equals("compact")) 35 | { 36 | if(log != null) 37 | messages.add(log); 38 | } 39 | return messages; 40 | } 41 | 42 | private static void logCompact(long time, boolean endOfTick) 43 | { 44 | if(ExplosionHelper.isEmpty()) 45 | return; 46 | 47 | Vec3 pos = ExplosionHelper.getPos(); 48 | log = Messenger.c( 49 | "d " + ExplosionHelper.getCountInPos() + "x ", 50 | Messenger.dblt("l", pos.x, pos.y, pos.z), 51 | "p [Tp]", String.format(Locale.ENGLISH, "!/tp %.3f %.3f %.3f", pos.x, pos.y, pos.z), 52 | ExplosionHelper.getAffectBlocks() ? "m damage" : "m no damage", 53 | "g (", "d " + (time - ExplosionHelper.getTime()), "g ms)", 54 | endOfTick ? Messenger.c("g \n(", "d " + ExplosionHelper.getCountInTick(), "g total)") : Messenger.c() 55 | ); 56 | } 57 | 58 | public static void afterEntities() 59 | { 60 | if(LoggerRegistry.__explosions) 61 | { 62 | logCompact(System.currentTimeMillis(), true); 63 | LoggerRegistry.getLogger("explosions").log((option) -> 64 | { 65 | return onLog(new ArrayList(), option).toArray(new BaseComponent[0]); 66 | }); 67 | log = null; 68 | } 69 | ExplosionHelper.clear(); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: step.build 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | release: 7 | type: boolean 8 | required: false 9 | default: false 10 | target_subproject: 11 | description: The subproject name of the specified Minecraft version to be built. Leave it empty to build all 12 | type: string 13 | required: false 14 | default: '' 15 | 16 | jobs: 17 | build: 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - uses: actions/checkout@v3 22 | - name: Set up JDK 17 23 | uses: actions/setup-java@v3 24 | with: 25 | distribution: 'temurin' 26 | java-version: 17 27 | 28 | - name: Cache gradle files 29 | uses: actions/cache@v3 30 | with: 31 | path: | 32 | ~/.gradle/caches 33 | ~/.gradle/wrapper 34 | ./.gradle/loom-cache 35 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle', '**/gradle.properties', '**/*.accesswidener') }} 36 | restore-keys: | 37 | ${{ runner.os }}-gradle- 38 | 39 | - name: Get subproject name to build 40 | id: subproject_info 41 | run: | 42 | if [ "${{ inputs.target_subproject }}" != "" ] 43 | then 44 | echo "prefix=${{ inputs.target_subproject }}:" >> $GITHUB_OUTPUT 45 | else 46 | echo "prefix=" >> $GITHUB_OUTPUT 47 | fi 48 | 49 | - name: Build with Gradle 50 | run: | 51 | chmod +x gradlew 52 | ./gradlew ${{ steps.subproject_info.outputs.prefix }}build --no-daemon 53 | env: 54 | BUILD_ID: ${{ github.run_number }} 55 | BUILD_RELEASE: ${{ inputs.release }} 56 | 57 | - uses: actions/upload-artifact@v3 58 | with: 59 | name: build-artifacts 60 | path: versions/*/build/libs/ 61 | 62 | summary: 63 | runs-on: ubuntu-22.04 64 | needs: 65 | - build 66 | 67 | steps: 68 | - uses: actions/checkout@v3 69 | 70 | - name: Download build artifacts 71 | uses: actions/download-artifact@v3 72 | with: 73 | name: build-artifacts 74 | path: build-artifacts 75 | 76 | - name: Make build summary 77 | run: python3 .github/workflows/scripts/summary.py # Python 3.10.6 78 | env: 79 | TARGET_SUBPROJECT: ${{ inputs.target_subproject }} 80 | -------------------------------------------------------------------------------- /src/main/java/me/lntricate/intricarpet/mixins/interactions/EntityMixin.java: -------------------------------------------------------------------------------- 1 | package me.lntricate.intricarpet.mixins.interactions; 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 com.llamalad7.mixinextras.injector.ModifyReturnValue; 9 | import com.llamalad7.mixinextras.injector.WrapWithCondition; 10 | 11 | import me.lntricate.intricarpet.interactions.Interaction; 12 | import me.lntricate.intricarpet.interfaces.IServerPlayer; 13 | import net.minecraft.core.BlockPos; 14 | import net.minecraft.world.entity.Entity; 15 | import net.minecraft.world.level.Level; 16 | import net.minecraft.world.level.block.Block; 17 | import net.minecraft.world.level.block.state.BlockState; 18 | 19 | @Mixin(Entity.class) 20 | public class EntityMixin 21 | { 22 | private boolean noBlockInteraction() 23 | { 24 | return (Entity)(Object)this instanceof IServerPlayer player && !player.getInteraction(Interaction.BLOCKS); 25 | } 26 | 27 | // TODO: Redstone ore 28 | // @ModifyReturnValue(method = "isSteppingCarefully", at = @At("RETURN")) 29 | // private boolean isSteppingCarefully(boolean original) 30 | // { 31 | // if((Entity)(Object)this instanceof IServerPlayer) 32 | // System.out.println(original || noBlockInteraction()); 33 | // return original || noBlockInteraction(); 34 | // } 35 | 36 | @WrapWithCondition(method = "checkFallDamage", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/Block;fallOn(Lnet/minecraft/world/level/Level;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/entity/Entity;F)V")) 37 | private boolean shouldFallOn(Block instance, Level level, BlockState blockState, BlockPos blockPos, Entity entity, float fallDistance) 38 | { 39 | return !noBlockInteraction(); 40 | } 41 | 42 | @Inject(method = "checkInsideBlocks", at = @At("HEAD"), cancellable = true) 43 | private void checkInsideBlocks(CallbackInfo ci) 44 | { 45 | if(noBlockInteraction()) 46 | ci.cancel(); 47 | } 48 | 49 | @ModifyReturnValue(method = "isIgnoringBlockTriggers", at = @At("RETURN")) 50 | private boolean isIgnoringBlockTriggers(boolean original) 51 | { 52 | return original || noBlockInteraction(); 53 | } 54 | 55 | @Inject(method = "teleportToWithTicket", at = @At("HEAD"), cancellable = true) 56 | private void teleportToWithTicket(double x, double y, double z, CallbackInfo ci) 57 | { 58 | if((Entity)(Object)this instanceof IServerPlayer player && !player.getInteraction(Interaction.CHUNKLOADING)) 59 | ci.cancel(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /versions/1.17.1/.factorypath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /versions/1.18.2/.factorypath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /versions/1.19.2/.factorypath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /versions/1.19.3/.factorypath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /versions/1.19.4/.factorypath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /versions/1.20.1/.factorypath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /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% equ 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% equ 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 | set EXIT_CODE=%ERRORLEVEL% 84 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 85 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 86 | exit /b %EXIT_CODE% 87 | 88 | :mainEnd 89 | if "%OS%"=="Windows_NT" endlocal 90 | 91 | :omega 92 | -------------------------------------------------------------------------------- /common.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'maven-publish' 2 | apply plugin: 'fabric-loom' 3 | apply plugin: 'com.replaymod.preprocess' 4 | 5 | int mcVersion = 1 6 | 7 | preprocess { 8 | mcVersion = vars.get()["MC"] 9 | tabIndentation = false 10 | } 11 | 12 | repositories { 13 | maven { 14 | url 'https://masa.dy.fi/maven' 15 | } 16 | maven { 17 | url 'https://jitpack.io' 18 | } 19 | maven { 20 | url 'https://www.cursemaven.com' 21 | } 22 | } 23 | 24 | dependencies { 25 | // loom 26 | minecraft "com.mojang:minecraft:${project.minecraft_version}" 27 | mappings loom.officialMojangMappings() 28 | modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" 29 | // MixinExtras 30 | include(implementation(annotationProcessor("com.github.llamalad7.mixinextras:mixinextras-fabric:0.2.0-beta.8"))) 31 | // Mods 32 | modImplementation "carpet:fabric-carpet:${project.carpet_version}" 33 | } 34 | 35 | loom { 36 | runConfigs.all { 37 | // to make sure it generates all "Minecraft Client (:subproject_name)" applications 38 | ideConfigGenerated true 39 | runDir '../../run' 40 | vmArgs '-Dmixin.debug.export=true' 41 | } 42 | } 43 | 44 | // loom { 45 | // accessWidenerPath = file("src/main/resources/modid.accesswidener") 46 | // } 47 | 48 | remapJar { 49 | remapperIsolation = true 50 | } 51 | 52 | if (mcVersion >= 11800) { 53 | sourceCompatibility = JavaVersion.VERSION_17 54 | targetCompatibility = JavaVersion.VERSION_17 55 | } 56 | else if (mcVersion >= 11700) { 57 | sourceCompatibility = JavaVersion.VERSION_16 58 | targetCompatibility = JavaVersion.VERSION_16 59 | } 60 | else { 61 | sourceCompatibility = JavaVersion.VERSION_1_8 62 | targetCompatibility = JavaVersion.VERSION_1_8 63 | } 64 | 65 | String versionSuffix = '' 66 | if (System.getenv("BUILD_RELEASE") != "true") { 67 | String buildNumber = System.getenv("BUILD_ID") 68 | versionSuffix += buildNumber != null ? ('+build.' + buildNumber) : '-SHAPSHOT' 69 | } 70 | String fullModVersion = project.mod_version + versionSuffix 71 | 72 | version = 'v' + fullModVersion 73 | group = project.maven_group 74 | archivesBaseName = project.archives_base_name + '-mc' + project.minecraft_version 75 | 76 | processResources { 77 | inputs.property "version", fullModVersion 78 | 79 | filesMatching("fabric.mod.json") { 80 | def valueMap = [ 81 | "id": project.mod_id, 82 | "name": project.mod_name, 83 | "version": fullModVersion, 84 | "minecraft_dependency": project.minecraft_dependency, 85 | "carpet_dependency": project.carpet_dependency, 86 | ] 87 | expand valueMap 88 | } 89 | } 90 | 91 | tasks.withType(JavaCompile) { 92 | options.encoding = "UTF-8" 93 | options.compilerArgs << "-Xlint:deprecation" << "-Xlint:removal" << "-Xlint:unchecked" 94 | options.warnings = false 95 | } 96 | 97 | java { 98 | // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task 99 | // if it is present. 100 | // If you remove this line, sources will not be generated. 101 | withSourcesJar() 102 | } 103 | 104 | jar { 105 | from(rootProject.file('LICENSE')) { 106 | rename { "${it}_${project.archivesBaseName}"} 107 | } 108 | } 109 | 110 | // configure the maven publication 111 | publishing { 112 | publications { 113 | mavenJava(MavenPublication) { 114 | artifactId archivesBaseName 115 | from components.java 116 | } 117 | } 118 | 119 | // select the repositories you want to publish to 120 | repositories { 121 | // uncomment to publish to the local maven 122 | // mavenLocal() 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/me/lntricate/intricarpet/commands/InteractionCommand.java: -------------------------------------------------------------------------------- 1 | package me.lntricate.intricarpet.commands; 2 | 3 | import com.mojang.brigadier.CommandDispatcher; 4 | import com.mojang.brigadier.arguments.BoolArgumentType; 5 | import com.mojang.brigadier.arguments.StringArgumentType; 6 | import com.mojang.brigadier.context.CommandContext; 7 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 8 | 9 | import carpet.utils.Messenger; 10 | import carpet.settings.SettingsManager; 11 | import net.minecraft.commands.CommandSourceStack; 12 | import me.lntricate.intricarpet.Rules; 13 | import me.lntricate.intricarpet.interactions.Interaction; 14 | import me.lntricate.intricarpet.interfaces.IServerPlayer; 15 | 16 | import java.util.Map; 17 | 18 | import static com.mojang.brigadier.arguments.StringArgumentType.getString; 19 | import static com.mojang.brigadier.arguments.BoolArgumentType.getBool; 20 | import static net.minecraft.commands.Commands.argument; 21 | import static net.minecraft.commands.Commands.literal; 22 | import static net.minecraft.commands.SharedSuggestionProvider.suggest; 23 | 24 | public class InteractionCommand 25 | { 26 | public static void register(CommandDispatcher dispatcher) 27 | { 28 | dispatcher.register(literal("interaction") 29 | .requires((player) -> SettingsManager.canUseCommand(player, Rules.commandInteraction)) 30 | .then(argument("interaction", StringArgumentType.word()) 31 | .suggests((c, b) -> suggest(Interaction.commandKeys(), b)) 32 | .then(argument("value", BoolArgumentType.bool()) 33 | .executes(InteractionCommand::setInteraction) 34 | ) 35 | .executes(InteractionCommand::getInteraction) 36 | ) 37 | .executes(InteractionCommand::getInteractions) 38 | ); 39 | } 40 | 41 | private static String v(boolean value) 42 | { 43 | return (value ? "l " : "r ") + value; 44 | } 45 | 46 | private static String i(Interaction interaction) 47 | { 48 | return "t " + interaction.getName(); 49 | } 50 | 51 | private static int setInteraction(CommandContext c) 52 | { 53 | try 54 | { 55 | IServerPlayer player = (IServerPlayer)c.getSource().getPlayerOrException(); 56 | Interaction i = Interaction.byCommandKey(getString(c, "interaction")); 57 | boolean value = getBool(c, "value"); 58 | player.setInteraction(i, value); 59 | Messenger.m(c.getSource(), "g Interaction ", i(i), "g set to ", v(value)); 60 | return 0; 61 | } 62 | catch(CommandSyntaxException e) 63 | { 64 | Messenger.m(c.getSource(), "r Interaction command must be executed by a player"); 65 | return 1; 66 | } 67 | } 68 | 69 | private static int getInteraction(CommandContext c) 70 | { 71 | try 72 | { 73 | IServerPlayer player = (IServerPlayer)c.getSource().getPlayerOrException(); 74 | Interaction i = Interaction.byCommandKey(getString(c, "interaction")); 75 | Messenger.m(c.getSource(), "g Interaction ", i(i), "g is currently set to ", v(player.getInteraction(i))); 76 | return 0; 77 | } 78 | catch(CommandSyntaxException e) 79 | { 80 | Messenger.m(c.getSource(), "r Interaction command must be executed by a player"); 81 | return 1; 82 | } 83 | } 84 | 85 | private static int getInteractions(CommandContext c) 86 | { 87 | try 88 | { 89 | IServerPlayer player = (IServerPlayer)c.getSource().getPlayerOrException(); 90 | for(Map.Entry entry : player.getInteractions().entrySet()) 91 | Messenger.m(c.getSource(), i(entry.getKey()), "g : ", v(entry.getValue())); 92 | return 0; 93 | } 94 | catch(CommandSyntaxException e) 95 | { 96 | Messenger.m(c.getSource(), "r Interaction command must be executed by a player"); 97 | return 1; 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/me/lntricate/intricarpet/mixins/interactions/ServerGamePacketListenerImplMixin.java: -------------------------------------------------------------------------------- 1 | package me.lntricate.intricarpet.mixins.interactions; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.Shadow; 5 | import org.spongepowered.asm.mixin.injection.At; 6 | import org.spongepowered.asm.mixin.injection.Inject; 7 | import org.spongepowered.asm.mixin.injection.At.Shift; 8 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 9 | 10 | import carpet.CarpetSettings; 11 | import me.lntricate.intricarpet.interactions.Interaction; 12 | import me.lntricate.intricarpet.interfaces.IServerPlayer; 13 | import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket; 14 | import net.minecraft.network.protocol.game.ServerboundUseItemOnPacket; 15 | import net.minecraft.network.protocol.game.ServerboundUseItemPacket; 16 | import net.minecraft.server.level.ServerPlayer; 17 | import net.minecraft.server.network.ServerGamePacketListenerImpl; 18 | 19 | @Mixin(ServerGamePacketListenerImpl.class) 20 | public class ServerGamePacketListenerImplMixin 21 | { 22 | @Shadow private ServerPlayer player; 23 | 24 | @Inject(method = "handleUseItemOn", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerPlayerGameMode;useItemOn(Lnet/minecraft/server/level/ServerPlayer;Lnet/minecraft/world/level/Level;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/InteractionHand;Lnet/minecraft/world/phys/BlockHitResult;)Lnet/minecraft/world/InteractionResult;")) 25 | private void beforeInteractBlock(ServerboundUseItemOnPacket packet, CallbackInfo ci) 26 | { 27 | if(!((IServerPlayer)player).getInteraction(Interaction.UPDATES)) 28 | CarpetSettings.impendingFillSkipUpdates.set(true); 29 | } 30 | 31 | @Inject(method = "handleUseItemOn", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerPlayerGameMode;useItemOn(Lnet/minecraft/server/level/ServerPlayer;Lnet/minecraft/world/level/Level;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/InteractionHand;Lnet/minecraft/world/phys/BlockHitResult;)Lnet/minecraft/world/InteractionResult;", shift = Shift.AFTER)) 32 | private void afterInteractBlock(ServerboundUseItemOnPacket packet, CallbackInfo ci) 33 | { 34 | CarpetSettings.impendingFillSkipUpdates.set(false); 35 | } 36 | 37 | @Inject(method = "handleUseItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerPlayerGameMode;useItem(Lnet/minecraft/server/level/ServerPlayer;Lnet/minecraft/world/level/Level;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/InteractionHand;)Lnet/minecraft/world/InteractionResult;")) 38 | private void beforeInteractItem(ServerboundUseItemPacket packet, CallbackInfo ci) 39 | { 40 | if(!((IServerPlayer)player).getInteraction(Interaction.UPDATES)) 41 | CarpetSettings.impendingFillSkipUpdates.set(true); 42 | } 43 | 44 | @Inject(method = "handleUseItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerPlayerGameMode;useItem(Lnet/minecraft/server/level/ServerPlayer;Lnet/minecraft/world/level/Level;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/InteractionHand;)Lnet/minecraft/world/InteractionResult;", shift = Shift.AFTER)) 45 | private void afterInteractItem(ServerboundUseItemPacket packet, CallbackInfo ci) 46 | { 47 | CarpetSettings.impendingFillSkipUpdates.set(false); 48 | } 49 | 50 | private static final String handleBlockBreakAction = 51 | //#if MC >= 11900 52 | //$$ "Lnet/minecraft/server/level/ServerPlayerGameMode;handleBlockBreakAction(Lnet/minecraft/core/BlockPos;Lnet/minecraft/network/protocol/game/ServerboundPlayerActionPacket$Action;Lnet/minecraft/core/Direction;II)V"; 53 | //#else 54 | "Lnet/minecraft/server/level/ServerPlayerGameMode;handleBlockBreakAction(Lnet/minecraft/core/BlockPos;Lnet/minecraft/network/protocol/game/ServerboundPlayerActionPacket$Action;Lnet/minecraft/core/Direction;I)V"; 55 | //#endif 56 | 57 | @Inject(method = "handlePlayerAction", at = @At(value = "INVOKE", target = handleBlockBreakAction)) 58 | private void beforeBreakBlock(ServerboundPlayerActionPacket packet, CallbackInfo ci) 59 | { 60 | if(!((IServerPlayer)player).getInteraction(Interaction.UPDATES)) 61 | CarpetSettings.impendingFillSkipUpdates.set(true); 62 | } 63 | 64 | @Inject(method = "handlePlayerAction", at = @At(value = "INVOKE", target = handleBlockBreakAction, shift = Shift.AFTER)) 65 | private void afterBreakBlock(ServerboundPlayerActionPacket packet, CallbackInfo ci) 66 | { 67 | CarpetSettings.impendingFillSkipUpdates.set(false); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | release: 5 | types: 6 | - published 7 | workflow_dispatch: 8 | inputs: 9 | target_subproject: 10 | description: The subproject name of the specified Minecraft version to be released. 11 | type: string 12 | required: false 13 | default: '' 14 | target_release_tag: 15 | description: The tag of the release you want to append the artifact to 16 | type: string 17 | required: true 18 | 19 | 20 | jobs: 21 | matrix_prep: 22 | uses: ./.github/workflows/matrix_prep.yml 23 | with: 24 | target_subproject: ${{ github.event.inputs.target_subproject }} 25 | 26 | build: 27 | uses: ./.github/workflows/build.yml 28 | with: 29 | target_subproject: ${{ github.event.inputs.target_subproject }} 30 | release: true 31 | 32 | release: 33 | needs: 34 | - matrix_prep 35 | - build 36 | runs-on: ubuntu-latest 37 | 38 | strategy: 39 | matrix: ${{ fromJson(needs.matrix_prep.outputs.matrix) }} 40 | 41 | steps: 42 | - uses: actions/checkout@v3 43 | 44 | - name: Download build artifacts 45 | uses: actions/download-artifact@v3 46 | with: 47 | name: build-artifacts 48 | path: build-artifacts 49 | 50 | - name: Get github release information 51 | if: ${{ github.event_name == 'workflow_dispatch' }} 52 | id: get_release 53 | uses: cardinalby/git-get-release-action@v1.1 54 | env: 55 | GITHUB_TOKEN: ${{ github.token }} 56 | with: 57 | tag: ${{ github.event.inputs.target_release_tag }} 58 | 59 | - name: Generate publish related information 60 | id: release_info 61 | run: | 62 | if [ $GITHUB_EVENT_NAME == 'release' ] 63 | then 64 | echo "tag_name=" >> $GITHUB_OUTPUT # leave an empty value here so softprops/action-gh-release will use the default value 65 | elif [ $GITHUB_EVENT_NAME == 'workflow_dispatch' ] 66 | then 67 | echo "tag_name=${{ github.event.inputs.target_release_tag }}" >> $GITHUB_OUTPUT 68 | else 69 | echo Unknown github event name $GITHUB_EVENT_NAME 70 | exit 1 71 | fi 72 | 73 | - name: Read common properties 74 | id: properties_g 75 | uses: christian-draeger/read-properties@1.1.1 76 | with: 77 | path: gradle.properties 78 | properties: 'mod_name mod_version' 79 | 80 | - name: Read version-specific properties 81 | id: properties_v 82 | uses: christian-draeger/read-properties@1.1.1 83 | with: 84 | path: ${{ format('versions/{0}/gradle.properties', matrix.subproject_dir) }} 85 | properties: 'minecraft_version game_versions' 86 | 87 | - name: Fix game version 88 | id: game_versions 89 | run: | 90 | # Fixed \n in game_versions isn't parsed by christian-draeger/read-properties as a line separator 91 | echo 'value<> $GITHUB_OUTPUT 92 | echo -e "${{ steps.properties_v.outputs.game_versions }}" >> $GITHUB_OUTPUT 93 | echo 'EOF' >> $GITHUB_OUTPUT 94 | 95 | - name: Publish Minecraft Mods 96 | uses: Kir-Antipov/mc-publish@v3.2 97 | with: 98 | modrinth-id: _INSERT_MODRITH_MOD_ID_HERE_ 99 | modrinth-token: ${{ secrets.MODRINTH_API_TOKEN }} 100 | 101 | curseforge-id: _INSERT_CURSEFORGE_MOD_ID_HERE_ 102 | curseforge-token: ${{ secrets.CF_API_TOKEN }} 103 | 104 | github-tag: ${{ steps.release_info.outputs.tag_name }} 105 | github-token: ${{ secrets.GITHUB_TOKEN }} 106 | 107 | files-primary: ${{ format('build-artifacts/{0}/build/libs/!(*-@(dev|sources)).jar', matrix.subproject_dir) }} 108 | files-secondary: '' 109 | 110 | name: ${{ format('{0} v{1} for mc{2}', steps.properties_g.outputs.mod_name, steps.properties_g.outputs.mod_version, steps.properties_v.outputs.minecraft_version) }} 111 | version: ${{ format('mc{0}-v{1}', steps.properties_v.outputs.minecraft_version, steps.properties_g.outputs.mod_version) }} 112 | version-type: release 113 | changelog: ${{ format('{0}{1}', github.event.release.body, steps.get_release.outputs.body) }} # one of them should be an empty string (null) 114 | 115 | loaders: fabric 116 | game-versions: ${{ steps.game_versions.outputs.value }} 117 | version-resolver: exact 118 | 119 | retry-attempts: 3 120 | retry-delay: 10000 121 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 84 | 85 | APP_NAME="Gradle" 86 | APP_BASE_NAME=${0##*/} 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | MAX_FD=$( ulimit -H -n ) || 147 | warn "Could not query maximum file descriptor limit" 148 | esac 149 | case $MAX_FD in #( 150 | '' | soft) :;; #( 151 | *) 152 | ulimit -n "$MAX_FD" || 153 | warn "Could not set maximum file descriptor limit to $MAX_FD" 154 | esac 155 | fi 156 | 157 | # Collect all arguments for the java command, stacking in reverse order: 158 | # * args from the command line 159 | # * the main class name 160 | # * -classpath 161 | # * -D...appname settings 162 | # * --module-path (only if needed) 163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 164 | 165 | # For Cygwin or MSYS, switch paths to Windows format before running java 166 | if "$cygwin" || "$msys" ; then 167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 169 | 170 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 171 | 172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 173 | for arg do 174 | if 175 | case $arg in #( 176 | -*) false ;; # don't mess with options #( 177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 178 | [ -e "$t" ] ;; #( 179 | *) false ;; 180 | esac 181 | then 182 | arg=$( cygpath --path --ignore --mixed "$arg" ) 183 | fi 184 | # Roll the args list around exactly as many times as the number of 185 | # args, so each arg winds up back in the position where it started, but 186 | # possibly modified. 187 | # 188 | # NB: a `for` loop captures its iteration list before it begins, so 189 | # changing the positional parameters here affects neither the number of 190 | # iterations, nor the values presented in `arg`. 191 | shift # remove old arg 192 | set -- "$@" "$arg" # push replacement arg 193 | done 194 | fi 195 | 196 | # Collect all arguments for the java command; 197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 198 | # shell script including quotes and variable substitutions, so put them in 199 | # double quotes to make sure that they get re-expanded; and 200 | # * put everything else in single quotes, so that it's not re-expanded. 201 | 202 | set -- \ 203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 204 | -classpath "$CLASSPATH" \ 205 | org.gradle.wrapper.GradleWrapperMain \ 206 | "$@" 207 | 208 | # Stop when "xargs" is not available. 209 | if ! command -v xargs >/dev/null 2>&1 210 | then 211 | die "xargs is not available" 212 | fi 213 | 214 | # Use "xargs" to parse quoted args. 215 | # 216 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 217 | # 218 | # In Bash we could simply go: 219 | # 220 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 221 | # set -- "${ARGS[@]}" "$@" 222 | # 223 | # but POSIX shell has neither arrays nor command substitution, so instead we 224 | # post-process each arg (as a line of input to sed) to backslash-escape any 225 | # character that might be a shell metacharacter, then use eval to reverse 226 | # that process (while maintaining the separation between arguments), and wrap 227 | # the whole thing up as a single "set" statement. 228 | # 229 | # This will of course break if any of these variables contains a newline or 230 | # an unmatched quote. 231 | # 232 | 233 | eval "set -- $( 234 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 235 | xargs -n1 | 236 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 237 | tr '\n' ' ' 238 | )" '"$@"' 239 | 240 | exec "$JAVACMD" "$@" 241 | -------------------------------------------------------------------------------- /versions/1.20.2/.factorypath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /src/main/java/me/lntricate/intricarpet/helpers/OptimizedExplosion.java: -------------------------------------------------------------------------------- 1 | // package me.lntricate.intricarpet.helpers; 2 | // 3 | // import java.util.ArrayList; 4 | // import java.util.Collections; 5 | // import java.util.HashMap; 6 | // import java.util.HashSet; 7 | // import java.util.Iterator; 8 | // import java.util.List; 9 | // import java.util.Map; 10 | // import java.util.Optional; 11 | // 12 | // import org.apache.commons.lang3.tuple.Pair; 13 | // 14 | // import com.google.common.collect.Sets; 15 | // 16 | // import carpet.mixins.ExplosionAccessor; 17 | // import it.unimi.dsi.fastutil.objects.ObjectArrayList; 18 | // import me.lntricate.intricarpet.logging.logHelpers.ExplosionLogHelper; 19 | // import me.lntricate.intricarpet.mixins.ExplosionDamageAccessor; 20 | // import net.minecraft.core.BlockPos; 21 | // import net.minecraft.server.level.ServerLevel; 22 | // import net.minecraft.util.Mth; 23 | // import net.minecraft.world.entity.Entity; 24 | // import net.minecraft.world.entity.LivingEntity; 25 | // import net.minecraft.world.entity.item.ItemEntity; 26 | // import net.minecraft.world.entity.item.PrimedTnt; 27 | // import net.minecraft.world.entity.player.Player; 28 | // import net.minecraft.world.item.ItemStack; 29 | // import net.minecraft.world.item.enchantment.ProtectionEnchantment; 30 | // import net.minecraft.world.level.ClipContext; 31 | // import net.minecraft.world.level.Explosion; 32 | // import net.minecraft.world.level.ExplosionDamageCalculator; 33 | // import net.minecraft.world.level.Level; 34 | // import net.minecraft.world.level.block.Block; 35 | // import net.minecraft.world.level.block.Blocks; 36 | // import net.minecraft.world.level.block.entity.BlockEntity; 37 | // import net.minecraft.world.level.block.state.BlockState; 38 | // import net.minecraft.world.level.material.FluidState; 39 | // import net.minecraft.world.level.storage.loot.LootContext; 40 | // import net.minecraft.world.level.storage.loot.parameters.LootContextParams; 41 | // import net.minecraft.world.phys.AABB; 42 | // import net.minecraft.world.phys.BlockHitResult; 43 | // import net.minecraft.world.phys.HitResult; 44 | // import net.minecraft.world.phys.Vec3; 45 | // 46 | // /* 47 | // * WIP optimizedTNT rewrite 48 | // */ 49 | // public class OptimizedExplosion 50 | // { 51 | // private static Explosion explosion; 52 | // private static ExplosionAccessor eAccess; 53 | // private static ExplosionDamageAccessor eAccess2; 54 | // 55 | // // Explosion data 56 | // private static double ex, ey, ez; 57 | // private static Vec3 pos; 58 | // private static Level level; 59 | // private static float power; 60 | // private static List toBlow = new ArrayList<>(); 61 | // 62 | // // For checking 63 | // private static long memTick = 0; 64 | // private static Vec3 memPos; 65 | // private static float memPower; 66 | // private static ExplosionDamageCalculator memDamageCalculator; 67 | // 68 | // // For using 69 | // private static List memEntities; 70 | // private static Map memVelocity = new HashMap<>(); 71 | // private static Map> memBlocks = new HashMap<>(); 72 | // 73 | // private static final Vec3[] RAYS = new Vec3[1352]; 74 | // 75 | // static 76 | // { 77 | // int i = 0; 78 | // for(int x = 0; x < 16; ++x) 79 | // for(int y = 0; y < 16; ++y) 80 | // for(int z = 0; z < 16; ++z) 81 | // if(x == 0 || x == 15 || y == 0 || y == 15 || z == 0 || z == 15) 82 | // { 83 | // double dx = x / 15f * 2f - 1f; 84 | // double dy = y / 15f * 2f - 1f; 85 | // double dz = z / 15f * 2f - 1f; 86 | // double mag = Math.sqrt(dx*dx + dy*dy + dz*dz); 87 | // RAYS[i++] = new Vec3(dx / mag * 0.3f, dy / mag * 0.3f, dz / mag * 0.3f); 88 | // } 89 | // } 90 | // 91 | // private static final class EntityKey 92 | // { 93 | // private final ExposureKey exposureKey; 94 | // private final float eyeHeight; 95 | // private final Integer hash; 96 | // 97 | // EntityKey(Entity entity) 98 | // { 99 | // exposureKey = new ExposureKey(entity); 100 | // eyeHeight = entity.getEyeHeight(); 101 | // hash = entity instanceof LivingEntity ? entity.hashCode() : null; 102 | // } 103 | // } 104 | // 105 | // private static final class ExposureKey 106 | // { 107 | // public final double x, y, z; 108 | // public final AABB aabb; 109 | // 110 | // ExposureKey(Entity entity) 111 | // { 112 | // x = entity.getX(); 113 | // y = entity.getY(); 114 | // z = entity.getZ(); 115 | // aabb = entity.getBoundingBox(); 116 | // } 117 | // } 118 | // 119 | // public static void doExplosionA(Explosion e, ExplosionLogHelper logger) 120 | // { 121 | // setExplosion(e); 122 | // checkMem(); 123 | // collectBlocks(); 124 | // pushEntities(); 125 | // } 126 | // 127 | // public static void setExplosion(Explosion e) 128 | // { 129 | // explosion = e; 130 | // eAccess = (ExplosionAccessor)explosion; 131 | // eAccess2 = (ExplosionDamageAccessor)explosion; 132 | // 133 | // ex = eAccess.getX(); ey = eAccess.getY(); eAccess.getZ(); 134 | // pos = new Vec3(ex, ey, ez); 135 | // level = eAccess.getWorld(); 136 | // power = eAccess.getPower(); 137 | // toBlow.clear(); 138 | // } 139 | // 140 | // public static void checkMem() 141 | // { 142 | // if(memPos.equals(pos) && memTick == level.getGameTime() && memPower == power) 143 | // return; 144 | // 145 | // if(memTick != level.getGameTime() || eAccess2.getDamageCalculator() != memDamageCalculator) 146 | // { 147 | // memBlocks.clear(); 148 | // memDamageCalculator = eAccess2.getDamageCalculator(); 149 | // } 150 | // 151 | // memPos = pos; 152 | // memTick = level.getGameTime(); 153 | // memPower = power; 154 | // 155 | // memVelocity.clear(); 156 | // 157 | // double x = eAccess.getX(); double y = eAccess.getY(); double z = eAccess.getZ(); 158 | // int minX = Mth.floor(x - power - 1d); 159 | // int maxX = Mth.floor(x - power - 1d); 160 | // int minY = Mth.floor(y - power - 1d); 161 | // int maxY = Mth.floor(y - power - 1d); 162 | // int minZ = Mth.floor(z - power - 1d); 163 | // int maxZ = Mth.floor(z - power - 1d); 164 | // 165 | // Entity tnt = eAccess2.getSource(); 166 | // memEntities = level.getEntities(tnt, new AABB(minX, minY, minZ, maxX, maxY, maxZ)); 167 | // 168 | // Iterator iter = memEntities.iterator(); 169 | // while(iter.hasNext()) 170 | // if(iter.next().ignoreExplosion()) 171 | // iter.remove(); 172 | // 173 | // if(tnt != null) 174 | // { 175 | // memEntities.remove(tnt); 176 | // if(tnt instanceof PrimedTnt && tnt.isOnGround()) 177 | // { 178 | // iter = memEntities.iterator(); 179 | // while(iter.hasNext()) 180 | // { 181 | // Entity entity = iter.next(); 182 | // if(entity instanceof PrimedTnt && 183 | // entity.getX() == tnt.getX() && 184 | // entity.getY() == tnt.getY() && 185 | // entity.getZ() == tnt.getZ()) 186 | // { 187 | // iter.remove(); 188 | // } 189 | // } 190 | // } 191 | // } 192 | // } 193 | // 194 | // private static void doRay(HashSet blocks, Vec3 rayPos, Vec3 delta, ExplosionDamageCalculator damageCalculator, float rand) 195 | // { 196 | // for(float rayStrength = power * (0.7F + rand * 0.6F); rayStrength > 0F; rayStrength -= 0.22500001F, rayPos = rayPos.add(delta)) 197 | // { 198 | // BlockPos pos = new BlockPos(rayPos); 199 | // if(memBlocks.containsKey(pos)) 200 | // { 201 | // Pair entry = memBlocks.get(pos); 202 | // rayStrength -= entry.getLeft(); 203 | // if(rayStrength > 0F && damageCalculator.shouldBlockExplode(explosion, level, pos, entry.getRight(), rayStrength)) 204 | // blocks.add(pos); 205 | // } 206 | // else 207 | // { 208 | // BlockState blockState = level.getBlockState(pos); 209 | // FluidState fluidState = level.getFluidState(pos); 210 | // if(!level.isInWorldBounds(pos)) 211 | // break; 212 | // 213 | // Optional blastResistance = damageCalculator.getBlockExplosionResistance(explosion, level, pos, blockState, fluidState); 214 | // 215 | // if(blastResistance.isPresent()) 216 | // { 217 | // float decrement = (blastResistance.get() + 0.3F) * 0.3F; 218 | // rayStrength -= decrement; 219 | // memBlocks.put(pos, Pair.of(decrement, blockState)); 220 | // } 221 | // else 222 | // memBlocks.put(pos, Pair.of(0f, blockState)); 223 | // 224 | // if(rayStrength > 0F && damageCalculator.shouldBlockExplode(explosion, level, pos, blockState, rayStrength)) 225 | // blocks.add(pos); 226 | // } 227 | // } 228 | // } 229 | // 230 | // public static void collectBlocks() 231 | // { 232 | // toBlow.clear(); 233 | // HashSet blocks = Sets.newHashSet(); 234 | // ExplosionDamageCalculator damageCalculator = eAccess2.getDamageCalculator(); 235 | // 236 | // for(Vec3 ray : RAYS) 237 | // doRay(blocks, pos, ray, damageCalculator, level.random.nextFloat()); 238 | // 239 | // toBlow.addAll(blocks); 240 | // } 241 | // 242 | // public static void pushEntities() 243 | // { 244 | // for(Entity entity : memEntities) 245 | // { 246 | // EntityKey entityKey = new EntityKey(entity); 247 | // if(memVelocity.containsKey(entityKey)) 248 | // { 249 | // entity.setDeltaMovement(entity.getDeltaMovement().add(memVelocity.get(entityKey))); 250 | // continue; 251 | // } 252 | // 253 | // double x = entity.getX(), y = entity.getY(), z = entity.getZ(); 254 | // double dx = x - ex, dy = y - ey, dz = z - ez; 255 | // double magSq = dx*dx + dy*dy + dz*dz; 256 | // 257 | // double distance = Math.sqrt(magSq); 258 | // if(distance > power) 259 | // continue; 260 | // 261 | // distance /= power; 262 | // double mag = distance; 263 | // 264 | // if(!(entity instanceof PrimedTnt)) 265 | // { 266 | // dy = entity.getEyeY() - y; 267 | // magSq = dx*dx + dy*dy + dz*dz; 268 | // 269 | // if(magSq == 0d) 270 | // continue; 271 | // 272 | // mag = Math.sqrt(magSq); 273 | // } 274 | // else if(magSq == 0d) 275 | // continue; 276 | // 277 | // dx /= mag; 278 | // dy /= mag; 279 | // dz /= mag; 280 | // 281 | // double knockback = (1d - distance) * getExposure(entity); 282 | // entity.hurt(explosion.getDamageSource(), (int)((knockback * knockback + knockback) / 2d * 7d * (double)power + 1d)); 283 | // 284 | // if(entity instanceof Player player && !player.isSpectator() && (!player.isCreative() || !player.getAbilities().flying)) 285 | // explosion.getHitPlayers().put(player, new Vec3(dx*knockback, dy*knockback, dz*knockback)); 286 | // 287 | // if(entity instanceof LivingEntity livingEntity) 288 | // knockback = ProtectionEnchantment.getExplosionKnockbackAfterDampener(livingEntity, knockback); 289 | // 290 | // Vec3 velocity = new Vec3(dx*knockback, dy*knockback, dz*knockback); 291 | // entity.setDeltaMovement(entity.getDeltaMovement().add(velocity)); 292 | // memVelocity.put(entityKey, velocity); 293 | // } 294 | // } 295 | // 296 | // private static float getExposure(Entity entity) 297 | // { 298 | // AABB aabb = entity.getBoundingBox(); 299 | // double xw = 1d / ((aabb.maxX - aabb.minX) * 2d + 1d); 300 | // double yw = 1d / ((aabb.maxY - aabb.minY) * 2d + 1d); 301 | // double zw = 1d / ((aabb.maxZ - aabb.minZ) * 2d + 1d); 302 | // double xh = (1d - Math.floor(1d/xw) * xw) / 2d; 303 | // double zh = (1d - Math.floor(1d/zw) * zw) / 2d; 304 | // 305 | // int hit = 0, total = 0; 306 | // 307 | // if(xw < 0d || yw < 0d || zw < 0d) 308 | // return 0f; 309 | // 310 | // for(float dx = 0f; dx <= 1f; dx += xw) 311 | // for(float dy = 0f; dy <= 1f; dy += yw) 312 | // for(float dz = 0f; dz <= 1f; dz += zw) 313 | // { 314 | // double x = Mth.lerp((double)dx, aabb.minX, aabb.maxX); 315 | // double y = Mth.lerp((double)dy, aabb.minY, aabb.maxY); 316 | // double z = Mth.lerp((double)dz, aabb.minZ, aabb.maxZ); 317 | // Vec3 vec3 = new Vec3(x + xh, y, z + zh); 318 | // BlockHitResult result = level.clip(new ClipContext(vec3, pos, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, entity)); 319 | // if(result.getType() == HitResult.Type.MISS) 320 | // ++hit; 321 | // 322 | // ++total; 323 | // } 324 | // 325 | // return (float)hit / (float)total; 326 | // } 327 | // 328 | // public static void doExplosionB(boolean spawnParticles) 329 | // { 330 | // ObjectArrayList> list = new ObjectArrayList<>(); 331 | // Collections.shuffle(toBlow, level.random); 332 | // for(BlockPos pos : toBlow) 333 | // { 334 | // BlockState state = memBlocks.get(pos).getRight(); 335 | // Block block = state.getBlock(); 336 | // if(!state.isAir()) 337 | // { 338 | // BlockPos pos1 = pos.immutable(); 339 | // level.getProfiler().push("explosion_blocks"); 340 | // if(block.dropFromExplosion(explosion) && level instanceof ServerLevel serverLevel) 341 | // { 342 | // BlockEntity blockEntity = state.hasBlockEntity() ? level.getBlockEntity(pos) : null; 343 | // LootContext.Builder builder = new LootContext.Builder(serverLevel) 344 | // .withRandom(level.random) 345 | // .withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(pos)) 346 | // .withParameter(LootContextParams.TOOL, ItemStack.EMPTY) 347 | // .withOptionalParameter(LootContextParams.BLOCK_ENTITY, blockEntity) 348 | // .withOptionalParameter(LootContextParams.THIS_ENTITY, eAccess2.getSource()); 349 | // if(eAccess.getDestructionType() == Explosion.BlockInteraction.DESTROY) 350 | // builder.withParameter(LootContextParams.EXPLOSION_RADIUS, power); 351 | // state.getDrops(builder).forEach((ItemStack stack) -> addBlockDrops(list, stack, pos1)); 352 | // } 353 | // level.setBlock(pos, Blocks.AIR.defaultBlockState(), 3); 354 | // block.wasExploded(level, pos, explosion); 355 | // level.getProfiler().pop(); 356 | // } 357 | // } 358 | // } 359 | // 360 | // private static void addBlockDrops(ObjectArrayList> list, ItemStack stack, BlockPos pos) 361 | // { 362 | // int s = list.size(); 363 | // for(int i = 0; i < s; ++i) 364 | // { 365 | // com.mojang.datafixers.util.Pair pair = list.get(i); 366 | // ItemStack stack2 = pair.getFirst(); 367 | // if(ItemEntity.areMergable(stack2, stack)) 368 | // { 369 | // ItemStack stack3 = ItemEntity.merge(stack2, stack, 16); 370 | // list.set(i, com.mojang.datafixers.util.Pair.of(stack3, pair.getSecond())); 371 | // if(stack.isEmpty()) 372 | // return; 373 | // } 374 | // } 375 | // list.add(com.mojang.datafixers.util.Pair.of(stack, pos)); 376 | // } 377 | // } 378 | --------------------------------------------------------------------------------