├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── CHANGELOG ├── LICENSE ├── README.md ├── README_zh_cn.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src └── main ├── java └── lovexyn0827 │ └── mess │ ├── MessMod.java │ ├── MessModMixinPlugin.java │ ├── command │ ├── AccessingPathCommand.java │ ├── CommandUtil.java │ ├── CountEntitiesCommand.java │ ├── ElementSetArgumentType.java │ ├── EnsureCommand.java │ ├── EntityConfigCommand.java │ ├── EntityFieldCommand.java │ ├── EntityLogCommand.java │ ├── EntitySidebarCommand.java │ ├── EnumSetArgumentType.java │ ├── ExplodeCommand.java │ ├── ExportSaveCommand.java │ ├── ExtendedFloatArgumentType.java │ ├── FilteredSetArgumentType.java │ ├── FreezeEntityCommand.java │ ├── HudCommand.java │ ├── LagCommand.java │ ├── LazyLoadCommand.java │ ├── LoadJavaAgentCommand.java │ ├── LogChunkBehaviorCommand.java │ ├── LogDeathCommand.java │ ├── LogMovementCommand.java │ ├── LogPacketCommand.java │ ├── MessCfgCommand.java │ ├── ModifyCommand.java │ ├── MoveEntityCommand.java │ ├── NameEntityCommand.java │ ├── PartlyKillCommand.java │ ├── PoiCommand.java │ ├── RaycastCommand.java │ ├── RepeatCommand.java │ ├── RideCommand.java │ ├── RngCommand.java │ ├── SetExplosionBlockCommand.java │ ├── StackEntityCommand.java │ ├── TileEntityCommand.java │ └── VariableCommand.java │ ├── export │ ├── ExportTask.java │ ├── Region.java │ ├── SaveComponent.java │ └── WorldGenType.java │ ├── fakes │ ├── ChunkTaskPrioritySystemInterface.java │ ├── ChunkTicketManagerInterface.java │ ├── EntityInterface.java │ ├── EntitySelectorInterface.java │ ├── EntitySelectorReaderInterface.java │ ├── HudDataSubscribeState.java │ ├── MinecraftClientInterface.java │ ├── ServerPlayerEntityInterface.java │ ├── ServerWorldInterface.java │ └── ThreadedAnvilChunkStorageInterface.java │ ├── log │ ├── AbstractAchivingLogger.java │ ├── CsvWriter.java │ ├── chunk │ │ ├── ChunkBehaviorLogger.java │ │ ├── ChunkEvent.java │ │ └── ChunkTaskPrintUtil.java │ └── entity │ │ ├── EntityHolder.java │ │ ├── EntityLogColumn.java │ │ ├── EntityLogger.java │ │ └── SideLogStoragePolicy.java │ ├── mixins │ ├── AbstractRedstoneGateBlockMixin.java │ ├── ArgumentTypesMixin.java │ ├── BlockItemMixin.java │ ├── BlockPosArgumentTypeMixin.java │ ├── BlockStateArgumentMixin.java │ ├── BoatEntityAccessor.java │ ├── ChunkStatusMixin.java │ ├── ChunkTaskPrioritySystemMixin.java │ ├── ChunkTicketManagerMixin.java │ ├── ChunkTicketManagerNearbyChunkTicketUpdaterMixin.java │ ├── ClientCommandSourceMixin.java │ ├── ClientConnectionMixin.java │ ├── ClientPlayNetworkHandlerMixin.java │ ├── ClientPlayerEntityMixin.java │ ├── CloneCommandMixin.java │ ├── CommandManagerRegistrationEnvironmentAccessor.java │ ├── CommandMixin.java │ ├── CraftingTableBlockMixin.java │ ├── CreativeInventoryScreenMixin.java │ ├── CustomPayloadC2SPacketAccessor.java │ ├── DataCommandStorageAccessor.java │ ├── DebugHudMixin.java │ ├── DebugRendererMixin.java │ ├── DebugStickItemMixin.java │ ├── DieableEntityMixin.java │ ├── EnchantCommandMixin.java │ ├── EndEyeItemMixin.java │ ├── EntityAccessor.java │ ├── EntityMixin.java │ ├── EntityPredicatesMixin.java │ ├── EntitySelectorMixin_Client.java │ ├── EntitySelectorMixin_Server.java │ ├── EntitySelectorOptionsMixin.java │ ├── EntitySelectorReaderMixin.java │ ├── ExplosionMixin.java │ ├── FillCommandMixin.java │ ├── FletchingTableBlockMixin.java │ ├── FormattingAccessor.java │ ├── GameRendererMixin.java │ ├── IdCountsStateAccessor.java │ ├── InGameHudMixin.java │ ├── ItemCooldownManagerMixin.java │ ├── KeyboardMixin.java │ ├── KillCommandMixin.java │ ├── LanguageManagerMixin.java │ ├── LivingEntityMixin.java │ ├── MinecartItemMixin.java │ ├── MinecraftClientMixin.java │ ├── MinecraftServerAccessor.java │ ├── MinecraftServerMixin.java │ ├── NetworkStateAccessor.java │ ├── PistonExtensionBlockMixin.java │ ├── PlayerInventoryMixin_Client.java │ ├── PlayerInventoryMixin_Server.java │ ├── PlayerManagerMixin.java │ ├── ProjectileEntityMixin.java │ ├── RaidManagerAccessor.java │ ├── RailPlacementHelperMixin.java │ ├── RegionBasedStorageAccessor.java │ ├── ServerChunkManagerMainThreadExecutorMixin.java │ ├── ServerChunkManagerMixin.java │ ├── ServerCommandSourceAccessor.java │ ├── ServerPlayNetworkHandlerMixin.java │ ├── ServerPlayerEntityMixin.java │ ├── ServerPlayerInteractionManagerMixin.java │ ├── ServerWorldMixin.java │ ├── SpawnEggItemMixin.java │ ├── StructureBlockBlockEntityMixin.java │ ├── ThreadedAnvilChunkStorageMixin.java │ ├── TntEntityMixin.java │ ├── WorldChunkMixin_GetEntityExpansion.java │ ├── WorldListWidgetEntryAccessor.java │ ├── WorldListWidgetEntryMixin.java │ ├── WorldListWidgetMixin.java │ ├── WorldMixin.java │ ├── WorldMixin_GetEntityExpansion.java │ ├── WorldRendererMixin.java │ └── WorldSavePathMixin.java │ ├── network │ ├── Channels.java │ ├── MessClientNetworkHandler.java │ └── MessServerNetworkHandler.java │ ├── options │ ├── BooleanParser.java │ ├── EnumParser.java │ ├── FloatParser.java │ ├── IntegerParser.java │ ├── InvalidOptionException.java │ ├── Label.java │ ├── ListParser.java │ ├── Option.java │ ├── OptionManager.java │ ├── OptionParser.java │ ├── OptionSet.java │ ├── OptionWrapper.java │ ├── RangeParser.java │ └── StringParser.java │ ├── rendering │ ├── BlockInfoRenderer.java │ ├── ChunkLoadingInfoRenderer.java │ ├── FlowerFieldRenderer.java │ ├── FrozenUpdateMode.java │ ├── LocalShapeStorage.java │ ├── RemoteShapeCache.java │ ├── RemoteShapeSender.java │ ├── RenderedBitmap.java │ ├── RenderedBox.java │ ├── RenderedLine.java │ ├── RenderedText.java │ ├── ServerSyncedBoxRenderer.java │ ├── Shape.java │ ├── ShapeCache.java │ ├── ShapeRenderer.java │ ├── ShapeSender.java │ ├── ShapeSpace.java │ └── hud │ │ ├── AlignMode.java │ │ ├── ClientHudManager.java │ │ ├── EntityHud.java │ │ ├── EntityHudUtil.java │ │ ├── EntitySideBar.java │ │ ├── HudManager.java │ │ ├── HudType.java │ │ ├── HudUtil.java │ │ ├── LookingAtEntityHud.java │ │ ├── PlayerHud.java │ │ ├── ServerHudManager.java │ │ └── data │ │ ├── BuiltinHudInfo.java │ │ ├── DataType.java │ │ ├── HudDataSender.java │ │ ├── HudDataStorage.java │ │ ├── HudLine.java │ │ ├── LocalDataStorage.java │ │ ├── LocalDefaultHudDataStorage.java │ │ ├── LocalSidebarDataStorage.java │ │ ├── RemoteHudDataSender.java │ │ ├── RemoteHudDataStorage.java │ │ ├── SidebarDataSender.java │ │ └── SidebarLine.java │ └── util │ ├── ArgumentListTokenizer.java │ ├── BlockPlacementHistory.java │ ├── CarpetUtil.java │ ├── EntityDataDumpHelper.java │ ├── FloatPredicate.java │ ├── FormattedText.java │ ├── JavaAgent.java │ ├── ListenedField.java │ ├── LockableLinkedHashMap.java │ ├── LockableList.java │ ├── LockedException.java │ ├── MethodDescriptor.java │ ├── NameFilter.java │ ├── NoChunkLoadingWorld.java │ ├── ParameterizedTypeImpl.java │ ├── PulseRecorder.java │ ├── RaycastUtil.java │ ├── Reflection.java │ ├── ServerMicroTime.java │ ├── TranslatableException.java │ ├── WrappedPath.java │ ├── access │ ├── AccessingFailureException.java │ ├── AccessingPath.java │ ├── AccessingPathArgumentType.java │ ├── AccessingUtils.java │ ├── BytecodeHelper.java │ ├── ClassCastNode.java │ ├── CompilationContext.java │ ├── CompilationException.java │ ├── CompiledPath.java │ ├── ComponentNode.java │ ├── CustomNode.java │ ├── ElementNode.java │ ├── FailureCause.java │ ├── FieldNode.java │ ├── InvalidLiteralException.java │ ├── JavaAccessingPath.java │ ├── Literal.java │ ├── LiteralNode.java │ ├── MapperNode.java │ ├── MethodNode.java │ ├── Node.java │ ├── NodeCompiler.java │ ├── PathClassLoader.java │ ├── PathCompiler.java │ ├── SimpleNode.java │ ├── SizeNode.java │ └── ValueOfMapNode.java │ ├── blame │ ├── AnalyzedCause.java │ ├── BlamingMode.java │ ├── Cause.java │ ├── Confidence.java │ ├── StackTrace.java │ ├── StackTraceCause.java │ └── TraceElement.java │ ├── deobfuscating │ ├── DummyMapping.java │ ├── Mapping.java │ ├── MappingProvider.java │ ├── MethodInfo.java │ └── TinyMapping.java │ ├── i18n │ ├── I18N.java │ └── Language.java │ └── phase │ ├── ClientTickingPhase.java │ ├── ServerTickingPhase.java │ ├── TickingPhase.java │ └── TickingPhaseArgumentType.java └── resources ├── assets ├── MessMod.png └── lang │ ├── en_us.json │ └── zh_cn.json ├── fabric.mod.json ├── messmod.accesswidener └── messmod.mixins.json /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Enter the command '...' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. Windows 7 64bit] 28 | - Java Version [e.g. Java 1.8.0_241 64bit, OpenJDK build 11+28] 29 | - Version [e.g. 22] 30 | 31 | **Additional context** 32 | Add any other context about the problem here. It could be screenshots, the crash report, the save where you have found the problem, or something else. 33 | -------------------------------------------------------------------------------- /.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 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.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 | 35 | # messmod custom 36 | 37 | archive/ 38 | src/test 39 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Done to increase the memory available to gradle. 2 | org.gradle.jvmargs=-Xmx1G 3 | 4 | # Fabric Properties 5 | # check these on https://fabricmc.net/use 6 | minecraft_version=1.16.4 7 | yarn_mappings=1.16.4+build.1 8 | loader_version=0.11.0 9 | 10 | # Mod Properties 11 | mod_version = 0.8.0+v20250311-BETA 12 | maven_group = lovexyn0827 13 | archives_base_name = messmod 14 | 15 | # Dependencies 16 | # currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api 17 | fabric_version=0.29.3+1.16 18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lovexyn0827/MessMod/a1c2d0b4164cef52e73161b924416879041e1b07/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven{ url 'https://maven.aliyun.com/nexus/content/groups/public/' } 4 | maven{ url 'https://maven.aliyun.com/nexus/content/repositories/jcenter'} 5 | maven { 6 | name = 'Fabric' 7 | url = 'https://maven.fabricmc.net/' 8 | } 9 | gradlePluginPortal() 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/command/ElementSetArgumentType.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.command; 2 | 3 | import java.util.Collection; 4 | import java.util.Set; 5 | import java.util.concurrent.CompletableFuture; 6 | 7 | import com.google.common.collect.Sets; 8 | import com.mojang.brigadier.StringReader; 9 | import com.mojang.brigadier.arguments.ArgumentType; 10 | import com.mojang.brigadier.context.CommandContext; 11 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 12 | import com.mojang.brigadier.suggestion.Suggestions; 13 | import com.mojang.brigadier.suggestion.SuggestionsBuilder; 14 | 15 | import lovexyn0827.mess.util.NameFilter; 16 | 17 | /** 18 | * @author lovexyn0827 19 | * @date Aug. 16, 2023 20 | * @param The type of elements to be filtered 21 | * @param The type of parsing result which used to store the filtering result 22 | */ 23 | public abstract class ElementSetArgumentType> 24 | implements ArgumentType { 25 | protected abstract R filter(NameFilter filter); 26 | 27 | @Override 28 | public R parse(StringReader reader) throws CommandSyntaxException { 29 | int start = reader.getCursor(); 30 | while(reader.canRead()) { 31 | char c = reader.peek(); 32 | if(Character.isJavaIdentifierPart(c) || c == '*' || c == '?') { 33 | reader.skip(); 34 | } else { 35 | break; 36 | } 37 | } 38 | 39 | return this.filter(NameFilter.compile(reader.getString().substring(start, reader.getCursor()))); 40 | } 41 | 42 | @Override 43 | public abstract CompletableFuture listSuggestions( 44 | CommandContext context, SuggestionsBuilder builder); 45 | 46 | @Override 47 | public Collection getExamples() { 48 | return Sets.newHashSet("*", "ENTITY", "EN???Y", "E*T?"); 49 | } 50 | 51 | public static abstract class ParseResult { 52 | protected final Set set; 53 | 54 | public ParseResult(Set set) { 55 | this.set = set; 56 | } 57 | 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/command/EnsureCommand.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.command; 2 | 3 | import static net.minecraft.server.command.CommandManager.argument; 4 | import static net.minecraft.server.command.CommandManager.literal; 5 | 6 | import com.mojang.brigadier.Command; 7 | import com.mojang.brigadier.CommandDispatcher; 8 | import com.mojang.brigadier.builder.LiteralArgumentBuilder; 9 | 10 | import net.minecraft.block.BlockState; 11 | import net.minecraft.block.entity.BlockEntity; 12 | import net.minecraft.block.entity.BlockEntityType; 13 | import net.minecraft.command.argument.BlockPosArgumentType; 14 | import net.minecraft.server.command.ServerCommandSource; 15 | import net.minecraft.util.math.BlockPos; 16 | import net.minecraft.world.World; 17 | 18 | public class EnsureCommand { 19 | public static void register(CommandDispatcher dispatcher) { 20 | LiteralArgumentBuilder command = literal("ensure").requires(CommandUtil.COMMAND_REQUMENT) 21 | .then(argument("pos", BlockPosArgumentType.blockPos()) 22 | .executes((ct) -> { 23 | BlockPos pos = BlockPosArgumentType.getBlockPos(ct, "pos"); 24 | World world = ct.getSource().getWorld(); 25 | BlockState state = world.getBlockState(pos); 26 | BlockEntity be = world.getBlockEntity(pos); 27 | String posStr = "(" + pos.getX() + "," + pos.getY() + "," + pos.getZ() + ")"; 28 | CommandUtil.feedbackWithArgs(ct, "cmd.ensure.blockat", posStr, state); 29 | if(be != null) { 30 | CommandUtil.feedbackWithArgs(ct, "cmd.ensure.be", BlockEntityType.getId(be.getType())); 31 | } 32 | 33 | return Command.SINGLE_SUCCESS; 34 | })); 35 | dispatcher.register(command); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/command/EntityConfigCommand.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.command; 2 | 3 | import static net.minecraft.server.command.CommandManager.argument; 4 | import static net.minecraft.server.command.CommandManager.literal; 5 | 6 | import java.util.Collection; 7 | import java.util.Collections; 8 | 9 | import com.mojang.brigadier.CommandDispatcher; 10 | import com.mojang.brigadier.builder.LiteralArgumentBuilder; 11 | import com.mojang.brigadier.context.CommandContext; 12 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 13 | 14 | import lovexyn0827.mess.MessMod; 15 | import lovexyn0827.mess.fakes.EntityInterface; 16 | import net.minecraft.client.MinecraftClient; 17 | import net.minecraft.command.argument.EntityArgumentType; 18 | import net.minecraft.entity.Entity; 19 | import net.minecraft.server.command.ServerCommandSource; 20 | 21 | public class EntityConfigCommand { 22 | @SuppressWarnings("resource") 23 | public static void register(CommandDispatcher dispatcher) { 24 | LiteralArgumentBuilder dsh = literal("disableStepHeight"). 25 | executes((ct)->{ 26 | getEntities(ct).forEach((e) -> ((EntityInterface) e).setStepHeightDisabled(true)); 27 | CommandUtil.feedback(ct, "cmd.general.success"); 28 | return 1; 29 | }); 30 | LiteralArgumentBuilder esh = literal("enableStepHeight"). 31 | executes((ct)->{ 32 | getEntities(ct).forEach((e) -> ((EntityInterface) e).setStepHeightDisabled(false)); 33 | CommandUtil.feedback(ct, "cmd.general.success"); 34 | return 1; 35 | }); 36 | LiteralArgumentBuilder command = literal("entityconfig"). 37 | requires(CommandUtil.COMMAND_REQUMENT).requires((s) -> !MessMod.isDedicatedEnv()). 38 | then(argument("targets",EntityArgumentType.entities()).then(dsh).then(esh)). 39 | then(literal("localPlayer"). 40 | then(literal("disableStepHeight"). 41 | executes((ct)->{ 42 | ((EntityInterface) MinecraftClient.getInstance().player).setStepHeightDisabled(true);; 43 | CommandUtil.feedback(ct, "cmd.general.success"); 44 | return 1; 45 | })). 46 | then(literal("enableStepHeight"). 47 | executes((ct)->{ 48 | ((EntityInterface) MinecraftClient.getInstance().player).setStepHeightDisabled(false);; 49 | CommandUtil.feedback(ct, "cmd.general.success"); 50 | return 1; 51 | }))); 52 | dispatcher.register(command); 53 | } 54 | 55 | private static Collection getEntities(CommandContext ct) { 56 | try { 57 | return EntityArgumentType.getEntities(ct, "targets"); 58 | } catch (CommandSyntaxException e) { 59 | CommandUtil.error(ct, e.getMessage()); 60 | } 61 | 62 | return Collections.emptyList(); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/command/ExplodeCommand.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.command; 2 | 3 | import com.mojang.brigadier.CommandDispatcher; 4 | import com.mojang.brigadier.builder.LiteralArgumentBuilder; 5 | import com.mojang.brigadier.arguments.BoolArgumentType; 6 | 7 | import net.minecraft.command.argument.Vec3ArgumentType; 8 | import net.minecraft.server.command.ServerCommandSource; 9 | import net.minecraft.server.world.ServerWorld; 10 | import net.minecraft.util.math.Vec3d; 11 | import net.minecraft.world.explosion.Explosion.DestructionType; 12 | 13 | import static net.minecraft.server.command.CommandManager.argument; 14 | import static net.minecraft.server.command.CommandManager.literal; 15 | 16 | public class ExplodeCommand { 17 | 18 | public static void register(CommandDispatcher dispatcher) { 19 | LiteralArgumentBuilder command = literal("explode").requires(CommandUtil.COMMAND_REQUMENT). 20 | then(argument("pos", Vec3ArgumentType.vec3()). 21 | then(argument("power", ExtendedFloatArgumentType.floatArg()). 22 | executes((ct) -> { 23 | ServerWorld world = ct.getSource().getWorld(); 24 | Vec3d pos = Vec3ArgumentType.getVec3(ct, "pos"); 25 | createExplosion(world,pos,ExtendedFloatArgumentType.getFloat(ct, "power"), false); 26 | CommandUtil.feedback(ct, "cmd.general.success"); 27 | return 1; 28 | }). 29 | then(argument("fire",BoolArgumentType.bool()). 30 | executes((ct)->{ 31 | ServerWorld world = ct.getSource().getWorld(); 32 | Vec3d pos = Vec3ArgumentType.getVec3(ct, "pos"); 33 | createExplosion(world, pos, 34 | ExtendedFloatArgumentType.getFloat(ct, "power"), 35 | BoolArgumentType.getBool(ct, "fire")); 36 | CommandUtil.feedback(ct, "cmd.general.success"); 37 | return 1; 38 | })))); 39 | dispatcher.register(command); 40 | } 41 | 42 | private static void createExplosion(ServerWorld world, Vec3d pos, float power, boolean fire) { 43 | world.createExplosion(null, pos.x, pos.y, pos.z, power, fire, DestructionType.DESTROY); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/command/ExtendedFloatArgumentType.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.command; 2 | 3 | import com.mojang.brigadier.StringReader; 4 | import com.mojang.brigadier.arguments.ArgumentType; 5 | import com.mojang.brigadier.context.CommandContext; 6 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 7 | 8 | import net.minecraft.command.argument.ArgumentTypes; 9 | import net.minecraft.command.argument.serialize.ConstantArgumentSerializer; 10 | import net.minecraft.server.command.ServerCommandSource; 11 | 12 | public class ExtendedFloatArgumentType implements ArgumentType { 13 | 14 | @Override 15 | public Float parse(StringReader reader) throws CommandSyntaxException { 16 | String str = reader.readUnquotedString(); 17 | try { 18 | return Float.parseFloat(str); 19 | } catch (NumberFormatException e) { 20 | throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.readerInvalidFloat().createWithContext(reader, str); 21 | } 22 | } 23 | 24 | public static ExtendedFloatArgumentType floatArg() { 25 | return new ExtendedFloatArgumentType(); 26 | } 27 | 28 | public static float getFloat(CommandContext ct, String string) { 29 | return ct.getArgument(string, Float.class); 30 | } 31 | 32 | public static void registerArgumentType() { 33 | ArgumentTypes.register("mess_float", ExtendedFloatArgumentType.class, 34 | new ConstantArgumentSerializer(ExtendedFloatArgumentType::floatArg)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/command/FreezeEntityCommand.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.command; 2 | 3 | import static net.minecraft.server.command.CommandManager.argument; 4 | import static net.minecraft.server.command.CommandManager.literal; 5 | 6 | import java.util.Collection; 7 | import com.mojang.brigadier.Command; 8 | import com.mojang.brigadier.CommandDispatcher; 9 | import com.mojang.brigadier.builder.LiteralArgumentBuilder; 10 | 11 | import lovexyn0827.mess.fakes.EntityInterface; 12 | import net.minecraft.command.argument.EntityArgumentType; 13 | import net.minecraft.entity.Entity; 14 | import net.minecraft.server.command.ServerCommandSource; 15 | 16 | public class FreezeEntityCommand { 17 | public static void register(CommandDispatcher dispatcher) { 18 | LiteralArgumentBuilder command = literal("freezentity").requires(CommandUtil.COMMAND_REQUMENT) 19 | .then(literal("freeze") 20 | .then(argument("entities", EntityArgumentType.entities()) 21 | .executes((ct) -> { 22 | Collection l = EntityArgumentType.getEntities(ct, "entities"); 23 | long count = l.stream().filter((e) -> !((EntityInterface) e).isFrozen()) 24 | .map((e) -> { 25 | ((EntityInterface) e).setFrozen(true); 26 | return e; 27 | }) 28 | .count(); 29 | CommandUtil.feedbackWithArgs(ct, "cmd.freezentity.sub", l.size(), count); 30 | return Command.SINGLE_SUCCESS; 31 | }))) 32 | .then(literal("resume") 33 | .then(argument("entities", EntityArgumentType.entities()) 34 | .executes((ct) -> { 35 | Collection l = EntityArgumentType.getEntities(ct, "entities"); 36 | long count = l.stream().filter((e) -> ((EntityInterface) e).isFrozen()) 37 | .map((e) -> { 38 | ((EntityInterface) e).setFrozen(false); 39 | return e; 40 | }) 41 | .count(); 42 | CommandUtil.feedbackWithArgs(ct, "cmd.freezentity.unsub", l.size(), count); 43 | return Command.SINGLE_SUCCESS; 44 | })));; 45 | dispatcher.register(command); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/command/LoadJavaAgentCommand.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.command; 2 | 3 | import static net.minecraft.server.command.CommandManager.argument; 4 | import static net.minecraft.server.command.CommandManager.literal; 5 | 6 | import java.net.MalformedURLException; 7 | import java.net.URL; 8 | import java.nio.file.Path; 9 | import java.nio.file.Paths; 10 | 11 | import com.mojang.brigadier.Command; 12 | import com.mojang.brigadier.CommandDispatcher; 13 | import com.mojang.brigadier.arguments.StringArgumentType; 14 | import com.mojang.brigadier.builder.LiteralArgumentBuilder; 15 | 16 | import lovexyn0827.mess.util.JavaAgent; 17 | import net.minecraft.server.command.ServerCommandSource; 18 | 19 | public class LoadJavaAgentCommand { 20 | public static void register(CommandDispatcher dispatcher) { 21 | LiteralArgumentBuilder command = literal("loadjavaagent").requires(CommandUtil.COMMAND_REQUMENT) 22 | .then(literal("fromFile") 23 | .then(argument("path", StringArgumentType.greedyString()) 24 | .executes((ct) -> { 25 | // TODO Translate 26 | boolean success = false; 27 | Path jarPath = Paths.get(StringArgumentType.getString(ct, "path")); 28 | try { 29 | success = JavaAgent.load(jarPath).attach(); 30 | } catch (Exception e) { 31 | e.printStackTrace(); 32 | } 33 | 34 | if (success) { 35 | CommandUtil.feedbackWithArgs(ct, "cmd.loadjavaagent.loadsuc", jarPath); 36 | return Command.SINGLE_SUCCESS; 37 | } else { 38 | CommandUtil.error(ct, "cmd.loadjavaagent.fail"); 39 | return 0; 40 | } 41 | }))) 42 | .then(literal("fromUrl") 43 | .then(argument("path", StringArgumentType.greedyString()) 44 | .executes((ct) -> { 45 | // TODO Cache 46 | // TODO nocache 47 | boolean success = false; 48 | URL url; 49 | try { 50 | url = new URL(StringArgumentType.getString(ct, "path")); 51 | } catch (MalformedURLException e1) { 52 | CommandUtil.error(ct, "cmd.loadjavaagent.malurl"); 53 | return 0; 54 | } 55 | 56 | try { 57 | success = JavaAgent.download(url).attach(); 58 | } catch (Exception e) { 59 | e.printStackTrace(); 60 | } 61 | 62 | if (success) { 63 | CommandUtil.feedbackWithArgs(ct, "cmd.loadjavaagent.loadsuc", url); 64 | return Command.SINGLE_SUCCESS; 65 | } else { 66 | CommandUtil.error(ct, "cmd.loadjavaagent.fail"); 67 | return 0; 68 | } 69 | }))); 70 | dispatcher.register(command); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/command/NameEntityCommand.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.command; 2 | 3 | import static net.minecraft.server.command.CommandManager.argument; 4 | import static net.minecraft.server.command.CommandManager.literal; 5 | 6 | import com.mojang.brigadier.Command; 7 | import com.mojang.brigadier.CommandDispatcher; 8 | import com.mojang.brigadier.arguments.StringArgumentType; 9 | import com.mojang.brigadier.builder.LiteralArgumentBuilder; 10 | 11 | import net.minecraft.command.argument.EntityArgumentType; 12 | import net.minecraft.server.command.ServerCommandSource; 13 | import net.minecraft.text.LiteralText; 14 | 15 | public class NameEntityCommand { 16 | public static void register(CommandDispatcher dispatcher) { 17 | LiteralArgumentBuilder command = literal("namentity").requires(CommandUtil.COMMAND_REQUMENT) 18 | .then(argument("entities", EntityArgumentType.entities()) 19 | .then(argument("name", StringArgumentType.greedyString()) 20 | .executes((ct) -> { 21 | EntityArgumentType.getEntities(ct, "entities").forEach((e) -> { 22 | e.setCustomName(new LiteralText(StringArgumentType.getString(ct, "name"))); 23 | e.setCustomNameVisible(true); 24 | }); 25 | CommandUtil.feedback(ct, "cmd.general.success"); 26 | return Command.SINGLE_SUCCESS; 27 | }))); 28 | dispatcher.register(command); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/command/PartlyKillCommand.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.command; 2 | 3 | import static net.minecraft.server.command.CommandManager.argument; 4 | import static net.minecraft.server.command.CommandManager.literal; 5 | 6 | import org.apache.commons.lang3.mutable.MutableInt; 7 | 8 | import com.mojang.brigadier.Command; 9 | import com.mojang.brigadier.CommandDispatcher; 10 | import com.mojang.brigadier.arguments.DoubleArgumentType; 11 | import com.mojang.brigadier.builder.LiteralArgumentBuilder; 12 | 13 | import lovexyn0827.mess.options.OptionManager; 14 | import net.minecraft.command.argument.EntityArgumentType; 15 | import net.minecraft.entity.mob.MobEntity; 16 | import net.minecraft.server.command.ServerCommandSource; 17 | 18 | public class PartlyKillCommand { 19 | public static void register(CommandDispatcher dispatcher) { 20 | LiteralArgumentBuilder command = literal("partlykill").requires(CommandUtil.COMMAND_REQUMENT) 21 | .then(argument("entities", EntityArgumentType.entities()) 22 | .then(argument("possibility", DoubleArgumentType.doubleArg(0.0D, 1.0D)) 23 | .executes((ct) -> { 24 | double p = DoubleArgumentType.getDouble(ct, "possibility"); 25 | MutableInt selected = new MutableInt(); 26 | MutableInt killed = new MutableInt(); 27 | EntityArgumentType.getEntities(ct, "entities").forEach((e) -> { 28 | selected.increment();; 29 | if(Math.random() < p) { 30 | killed.increment(); 31 | if(OptionManager.mobFastKill && e instanceof MobEntity) { 32 | e.remove(); 33 | } else { 34 | e.kill(); 35 | } 36 | } 37 | }); 38 | 39 | CommandUtil.feedbackWithArgs(ct, "cmd.partlykill.result", selected.getValue(), killed.getValue()); 40 | return Command.SINGLE_SUCCESS; 41 | }))); 42 | dispatcher.register(command); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/command/RepeatCommand.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.command; 2 | 3 | import static net.minecraft.server.command.CommandManager.argument; 4 | import static net.minecraft.server.command.CommandManager.literal; 5 | 6 | import java.util.Collections; 7 | 8 | import com.mojang.brigadier.CommandDispatcher; 9 | import com.mojang.brigadier.arguments.BoolArgumentType; 10 | import com.mojang.brigadier.arguments.IntegerArgumentType; 11 | import com.mojang.brigadier.builder.LiteralArgumentBuilder; 12 | 13 | import net.minecraft.server.command.ServerCommandSource; 14 | 15 | public class RepeatCommand { 16 | public static void register(CommandDispatcher dispatcher) { 17 | LiteralArgumentBuilder command = literal("repeat").requires(CommandUtil.COMMAND_REQUMENT) 18 | .then(argument("times", IntegerArgumentType.integer(0)) 19 | .then(argument("feedbacks", BoolArgumentType.bool()) 20 | .fork(dispatcher.getRoot(), (ct) -> { 21 | return Collections.nCopies(IntegerArgumentType.getInteger(ct, "times"), 22 | BoolArgumentType.getBool(ct, "feedbacks") ? ct.getSource() : CommandUtil.noreplySourceFor(ct.getSource())); 23 | }))); 24 | dispatcher.register(command); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/command/RideCommand.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.command; 2 | 3 | import static net.minecraft.server.command.CommandManager.argument; 4 | import static net.minecraft.server.command.CommandManager.literal; 5 | 6 | import java.util.Collection; 7 | 8 | import org.apache.commons.lang3.mutable.MutableInt; 9 | 10 | import com.mojang.brigadier.Command; 11 | import com.mojang.brigadier.CommandDispatcher; 12 | import com.mojang.brigadier.arguments.BoolArgumentType; 13 | import com.mojang.brigadier.builder.LiteralArgumentBuilder; 14 | 15 | import net.minecraft.command.argument.EntityArgumentType; 16 | import net.minecraft.entity.Entity; 17 | import net.minecraft.server.command.ServerCommandSource; 18 | 19 | public class RideCommand { 20 | public static void register(CommandDispatcher dispatcher) { 21 | LiteralArgumentBuilder command = literal("ride").requires(CommandUtil.COMMAND_REQUMENT) 22 | .then(argument("passengers", EntityArgumentType.entities()) 23 | .then(argument("vehicle", EntityArgumentType.entity()) 24 | .then(argument("force", BoolArgumentType.bool()) 25 | .executes((ct) -> { 26 | Entity vehicle = EntityArgumentType.getEntity(ct, "vehicle"); 27 | MutableInt success = new MutableInt(0); 28 | Collection passengers = EntityArgumentType.getEntities(ct, "passengers"); 29 | passengers.forEach((e) -> { 30 | if(e.startRiding(vehicle, BoolArgumentType.getBool(ct, "force"))) { 31 | success.increment(); 32 | } 33 | }); 34 | 35 | CommandUtil.feedbackWithArgs(ct, "cmd.ride.info",passengers.size(), success.getValue()); 36 | return Command.SINGLE_SUCCESS; 37 | })))); 38 | dispatcher.register(command); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/command/SetExplosionBlockCommand.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.command; 2 | 3 | import static net.minecraft.server.command.CommandManager.literal; 4 | import static net.minecraft.server.command.CommandManager.argument; 5 | 6 | import com.mojang.brigadier.CommandDispatcher; 7 | import com.mojang.brigadier.builder.LiteralArgumentBuilder; 8 | 9 | import net.minecraft.block.BlockState; 10 | import net.minecraft.command.argument.BlockStateArgumentType; 11 | import net.minecraft.server.command.ServerCommandSource; 12 | 13 | public class SetExplosionBlockCommand { 14 | private static BlockState blockState = null; 15 | private static BlockState fireState = null; 16 | 17 | public static void register(CommandDispatcher dispatcher) { 18 | LiteralArgumentBuilder command = literal("setexplodeblock").requires(CommandUtil.COMMAND_REQUMENT). 19 | then(argument("blockState",BlockStateArgumentType.blockState()). 20 | then(argument("fireState",BlockStateArgumentType.blockState()). 21 | executes((ct->{ 22 | blockState = BlockStateArgumentType.getBlockState(ct, "blockState").getBlockState(); 23 | fireState = BlockStateArgumentType.getBlockState(ct, "fireState").getBlockState(); 24 | CommandUtil.feedback(ct, "cmd.general.success"); 25 | return 1; 26 | })))); 27 | dispatcher.register(command); 28 | } 29 | 30 | public static void reset() { 31 | blockState = null; 32 | fireState = null; 33 | } 34 | 35 | public static BlockState getBlockState() { 36 | return blockState; 37 | } 38 | 39 | public static BlockState getFireState() { 40 | return fireState; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/command/StackEntityCommand.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.command; 2 | 3 | import static net.minecraft.server.command.CommandManager.argument; 4 | import static net.minecraft.server.command.CommandManager.literal; 5 | 6 | import com.mojang.brigadier.Command; 7 | import com.mojang.brigadier.CommandDispatcher; 8 | import com.mojang.brigadier.arguments.IntegerArgumentType; 9 | import com.mojang.brigadier.builder.LiteralArgumentBuilder; 10 | 11 | import net.minecraft.command.argument.EntityArgumentType; 12 | import net.minecraft.entity.Entity; 13 | import net.minecraft.server.command.ServerCommandSource; 14 | 15 | public class StackEntityCommand { 16 | public static void register(CommandDispatcher dispatcher) { 17 | LiteralArgumentBuilder command = literal("stackentity").requires(CommandUtil.COMMAND_REQUMENT) 18 | .then(argument("entity", EntityArgumentType.entities()) 19 | .then(argument("count", IntegerArgumentType.integer(1)) 20 | .executes((ct) -> { 21 | Entity center = EntityArgumentType.getEntity(ct, "entity"); 22 | int count = IntegerArgumentType.getInteger(ct, "count"); 23 | // Summon (n - 1) entities, so that the resulting stack contains n entities. 24 | for (int i = 1; i < count; i++) { 25 | Entity e = center.getType().create(center.world); 26 | e.copyPositionAndRotation(center); 27 | e.setVelocity(center.getVelocity()); 28 | } 29 | 30 | CommandUtil.feedback(ct, "cmd.general.success"); 31 | return Command.SINGLE_SUCCESS; 32 | }))); 33 | dispatcher.register(command); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/export/SaveComponent.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.export; 2 | 3 | import com.google.common.collect.ImmutableBiMap; 4 | 5 | import lovexyn0827.mess.options.ListParser; 6 | 7 | public enum SaveComponent { 8 | REGION, 9 | POI, 10 | GAMERULES, 11 | RAID, 12 | MAP_LOCAL, 13 | MAP_OTHER, 14 | ICON, 15 | ADVANCEMENTS_SELF, 16 | ADVANCEMENT_OTHER, 17 | PLAYER_SELF, 18 | PLAYER_OTHER, 19 | STAT_SELF, 20 | STAT_OTHER, 21 | SCOREBOARD, 22 | FORCE_CHUNKS_LOCAL, 23 | FORCE_CHUNKS_OTHER, 24 | DATA_COMMAND_STORAGE, 25 | CARPET, 26 | MESSMOD; 27 | 28 | private static final ImmutableBiMap BY_NAME; 29 | 30 | static { 31 | ImmutableBiMap.Builder builder = ImmutableBiMap.builder(); 32 | for(SaveComponent comp : values()) { 33 | builder.put(comp.name(), comp); 34 | } 35 | 36 | BY_NAME = builder.build(); 37 | } 38 | 39 | public static class DefaultListParser extends ListParser { 40 | public DefaultListParser() { 41 | super(BY_NAME); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/export/WorldGenType.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.export; 2 | 3 | public enum WorldGenType { 4 | COPY, 5 | VOID, 6 | PLAIN, 7 | GLASS, 8 | BEDROCK; 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/fakes/ChunkTaskPrioritySystemInterface.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.fakes; 2 | 3 | import net.minecraft.server.world.ServerWorld; 4 | 5 | public interface ChunkTaskPrioritySystemInterface { 6 | void initWorld(ServerWorld world); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/fakes/ChunkTicketManagerInterface.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.fakes; 2 | 3 | import net.minecraft.server.world.ServerWorld; 4 | import net.minecraft.util.Identifier; 5 | 6 | public interface ChunkTicketManagerInterface { 7 | Identifier getDimesionId(); 8 | void initWorld(ServerWorld world); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/fakes/EntityInterface.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.fakes; 2 | 3 | public interface EntityInterface { 4 | boolean isFrozen(); 5 | void setFrozen(boolean frozen); 6 | boolean isStepHeightDisabled(); 7 | void setStepHeightDisabled(boolean disabled); 8 | boolean shouldLogMovement(); 9 | void setMovementSubscribed(boolean subscribed); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/fakes/EntitySelectorInterface.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.fakes; 2 | 3 | import net.minecraft.network.NetworkSide; 4 | 5 | public interface EntitySelectorInterface { 6 | void setSide(NetworkSide side); 7 | void setTargetOnly(boolean targetOnly); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/fakes/EntitySelectorReaderInterface.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.fakes; 2 | 3 | import java.util.regex.Pattern; 4 | 5 | import net.minecraft.network.NetworkSide; 6 | import net.minecraft.predicate.NumberRange.IntRange; 7 | 8 | public interface EntitySelectorReaderInterface { 9 | void setIdRange(IntRange intRange); 10 | IntRange getIdRange(); 11 | void setSide(NetworkSide side); 12 | NetworkSide getSide(); 13 | void setTypeRegex(Pattern typeRegex); 14 | Pattern getTypeRegex(); 15 | void setNameRegex(Pattern nameRegex); 16 | Pattern getNameRegex(); 17 | void setClassRegex(Pattern classRegex); 18 | Pattern getClassRegex(); 19 | void setInstanceofClass(Class cl); 20 | Class getInstanceofClass(); 21 | boolean targetOnly(); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/fakes/HudDataSubscribeState.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.fakes; 2 | 3 | import lovexyn0827.mess.rendering.hud.HudType; 4 | 5 | public interface HudDataSubscribeState { 6 | boolean isSubscribed(HudType type); 7 | void subscribe(HudType type); 8 | void unsubscribe(HudType type); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/fakes/MinecraftClientInterface.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.fakes; 2 | 3 | import net.minecraft.entity.Entity; 4 | 5 | public interface MinecraftClientInterface { 6 | Entity getTargetForCommandSuggestions(); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/fakes/ServerPlayerEntityInterface.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.fakes; 2 | 3 | import lovexyn0827.mess.util.BlockPlacementHistory; 4 | 5 | public interface ServerPlayerEntityInterface { 6 | BlockPlacementHistory getBlockPlacementHistory(); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/fakes/ServerWorldInterface.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.fakes; 2 | 3 | import lovexyn0827.mess.util.NoChunkLoadingWorld; 4 | import lovexyn0827.mess.util.PulseRecorder; 5 | 6 | public interface ServerWorldInterface { 7 | PulseRecorder getPulseRecorder(); 8 | NoChunkLoadingWorld toNoChunkLoadingWorld(); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/fakes/ThreadedAnvilChunkStorageInterface.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.fakes; 2 | 3 | import net.minecraft.server.world.ChunkHolder; 4 | 5 | public interface ThreadedAnvilChunkStorageInterface { 6 | ChunkHolder getCHForMessMod(long pos); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/log/AbstractAchivingLogger.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.log; 2 | 3 | import java.io.FileOutputStream; 4 | import java.io.IOException; 5 | import java.nio.file.Files; 6 | import java.nio.file.Path; 7 | import java.text.SimpleDateFormat; 8 | import java.util.Date; 9 | import java.util.zip.ZipEntry; 10 | import java.util.zip.ZipOutputStream; 11 | 12 | import org.apache.logging.log4j.LogManager; 13 | import org.apache.logging.log4j.Logger; 14 | 15 | import lovexyn0827.mess.MessMod; 16 | import lovexyn0827.mess.mixins.WorldSavePathMixin; 17 | import net.minecraft.server.MinecraftServer; 18 | 19 | public abstract class AbstractAchivingLogger { 20 | public static final Logger LOGGER = LogManager.getLogger(); 21 | private Path logPath; 22 | private long lastSessionStart; 23 | protected boolean hasCreatedAnyLog; 24 | protected final MinecraftServer server; 25 | 26 | public AbstractAchivingLogger(MinecraftServer server) { 27 | this.server = server; 28 | this.initialize(server); 29 | } 30 | 31 | public void initialize(MinecraftServer server) { 32 | this.lastSessionStart = System.currentTimeMillis(); 33 | this.logPath = server.getSavePath(WorldSavePathMixin.create(this.getLogFolderName())).toAbsolutePath(); 34 | if(!Files.exists(this.logPath)) { 35 | try { 36 | Files.createDirectory(this.logPath); 37 | } catch (IOException e) { 38 | LOGGER.fatal("Failed to create folder for entity logs!"); 39 | e.printStackTrace(); 40 | // We don't rethrow the IOException to reduce crashes. 41 | } 42 | } 43 | } 44 | 45 | protected abstract String getLogFolderName(); 46 | 47 | public Path getLogPath() { 48 | return this.logPath; 49 | } 50 | 51 | public void archiveLogs() throws IOException { 52 | Path archiveDir = this.logPath.resolve("archived"); 53 | if(!Files.exists(archiveDir)) { 54 | Files.createDirectory(archiveDir); 55 | } 56 | 57 | if(this.hasCreatedAnyLog) { 58 | String fn = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss").format(new Date()) + ".zip"; 59 | Path archive = archiveDir.resolve(fn); 60 | try(ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(archive.toFile()))) { 61 | Files.walk(this.logPath, 1) 62 | .filter((f) -> f.getFileName().toString().endsWith(".csv")) 63 | .filter((f) -> f.toFile().lastModified() >= this.lastSessionStart) 64 | .forEach((f) -> { 65 | try { 66 | zos.putNextEntry(new ZipEntry(f.getFileName().toString())); 67 | zos.write(Files.readAllBytes(f)); 68 | Files.delete(f); 69 | } catch (IOException e) { 70 | MessMod.LOGGER.warn("Failed to archive " + f.toString()); 71 | e.printStackTrace(); 72 | } 73 | }); 74 | zos.finish(); 75 | } 76 | 77 | LOGGER.info("Archived the logs to " + archive.toAbsolutePath().toString()); 78 | } 79 | } 80 | 81 | } -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/log/CsvWriter.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.log; 2 | 3 | import java.io.Flushable; 4 | import java.io.IOException; 5 | import java.io.Writer; 6 | import java.util.ArrayList; 7 | import java.util.Arrays; 8 | import java.util.List; 9 | import java.util.stream.Collectors; 10 | import java.util.stream.Stream; 11 | 12 | import org.apache.commons.lang3.StringEscapeUtils; 13 | 14 | public class CsvWriter implements AutoCloseable, Flushable { 15 | private Writer writer; 16 | private int columnNumber; 17 | 18 | private CsvWriter(Builder b, Writer writer) { 19 | this.writer = writer; 20 | this.columnNumber = b.headers.size(); 21 | try { 22 | this.writer.write(toLine(b.headers.stream())); 23 | } catch (IOException e) { 24 | e.printStackTrace(); 25 | } 26 | } 27 | 28 | private static String toLine(Stream line) { 29 | return line.map((obj) -> obj == null ? "[NULL]" : obj.toString()) 30 | .map(StringEscapeUtils::escapeCsv) 31 | .collect(Collectors.joining(",")) + "\r\n"; 32 | } 33 | 34 | @Override 35 | public void close() throws IOException { 36 | this.writer.close(); 37 | } 38 | 39 | public void flush() throws IOException { 40 | this.writer.flush(); 41 | } 42 | 43 | public void println(Object... data) { 44 | try { 45 | if(data.length != this.columnNumber) { 46 | throw new IllegalArgumentException("Expected " + this.columnNumber + " elements, but got " + data.length); 47 | } 48 | 49 | this.writer.write(toLine(Arrays.stream(data))); 50 | } catch (IOException e) { 51 | e.printStackTrace(); 52 | } 53 | } 54 | 55 | public static class Builder { 56 | private List headers = new ArrayList<>(); 57 | 58 | public Builder addColumn(String header) { 59 | this.headers.add(header); 60 | return this; 61 | } 62 | 63 | public CsvWriter build(Writer writer) { 64 | return new CsvWriter(this, writer); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/log/chunk/ChunkEvent.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.log.chunk; 2 | 3 | public enum ChunkEvent { 4 | LOADING, 5 | UNLOADING, 6 | GENERATION, 7 | UPGRADE, 8 | END_LOADING, 9 | END_UNLOADING, 10 | END_GENERATION, 11 | END_UPGRADE, 12 | SCHEDULER_LOADING, 13 | SCHEDULER_UNLOADING, 14 | SCHEDULER_GENERATION, 15 | SCHEDULER_UPGRADE, 16 | TICKET_ADDITION, 17 | TICKET_REMOVAL, 18 | PLAYER_TICKER_UPDATE, 19 | ASYNC_TASKS, 20 | ASYNC_TASK_SINGLE, 21 | ASYNC_TASK_ADDITION, 22 | SCM_TICK, 23 | CTM_TICK, 24 | SCM_INIT_CACHE, 25 | CTPS_LEVEL, 26 | CTPS_REMOVE, 27 | CTPS_CHUNK; 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/log/chunk/ChunkTaskPrintUtil.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.log.chunk; 2 | 3 | import java.lang.reflect.Field; 4 | import java.util.concurrent.CompletableFuture; 5 | 6 | import lovexyn0827.mess.MessMod; 7 | import lovexyn0827.mess.options.OptionManager; 8 | import lovexyn0827.mess.util.Reflection; 9 | import lovexyn0827.mess.util.deobfuscating.Mapping; 10 | 11 | public final class ChunkTaskPrintUtil { 12 | public static String printTask(long id, Object task) { 13 | if (!OptionManager.detailedChunkTaskLogging) { 14 | return Long.toString(id); 15 | } 16 | 17 | StringBuilder sb = new StringBuilder(256); 18 | Mapping map = MessMod.INSTANCE.getMapping(); 19 | String taskClassName = task.getClass().getName(); 20 | sb.append(map.namedClass(taskClassName)); 21 | sb.append('#').append(id); 22 | sb.append('{'); 23 | for (Field f : Reflection.getInstanceFields(task.getClass())) { 24 | sb.append(map.namedField(f.getName())); 25 | sb.append('='); 26 | f.setAccessible(true); 27 | try { 28 | Object val = f.get(task); 29 | String str; 30 | if (val == null) { 31 | str = "[null]"; 32 | } else if (val.getClass().isSynthetic() || val instanceof CompletableFuture) { 33 | try { 34 | str = "[" + printTask(System.identityHashCode(val), val) + "]"; 35 | } catch (Exception e) { 36 | str = val.toString().replace(',', ';'); 37 | e.printStackTrace(); 38 | } 39 | 40 | } else { 41 | str = val.toString().replace(',', ';'); 42 | } 43 | 44 | sb.append(str); 45 | } catch (Exception e) { 46 | sb.append("?ERROR?"); 47 | e.printStackTrace(); 48 | } 49 | 50 | sb.append('|'); 51 | } 52 | 53 | sb.deleteCharAt(sb.length() - 1); 54 | sb.append('}'); 55 | return sb.toString(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/log/entity/EntityLogColumn.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.log.entity; 2 | 3 | import lovexyn0827.mess.util.phase.TickingPhase; 4 | import net.minecraft.entity.Entity; 5 | 6 | public interface EntityLogColumn { 7 | boolean canGetFrom(Entity e); 8 | TickingPhase getPhase(); 9 | String getName(); 10 | Object getFrom(Entity entity); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/log/entity/SideLogStoragePolicy.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.log.entity; 2 | 3 | public enum SideLogStoragePolicy { 4 | MIXED(true, true), 5 | SEPARATED(true, true), 6 | SERVER_ONLY(true, false), 7 | CLIENT_ONLY(false, true); 8 | 9 | public final boolean shouldTickServer; 10 | public final boolean shouldTickClient; 11 | 12 | private SideLogStoragePolicy(boolean shouldTickServer, boolean shouldTickClient) { 13 | this.shouldTickServer = shouldTickServer; 14 | this.shouldTickClient = shouldTickClient; 15 | } 16 | } -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/AbstractRedstoneGateBlockMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.gen.Invoker; 5 | 6 | import net.minecraft.block.AbstractRedstoneGateBlock; 7 | import net.minecraft.block.BlockState; 8 | import net.minecraft.util.math.BlockPos; 9 | import net.minecraft.world.BlockView; 10 | 11 | @Mixin(AbstractRedstoneGateBlock.class) 12 | public interface AbstractRedstoneGateBlockMixin { 13 | @Invoker("getOutputLevel") 14 | int getOutputRSLevel(BlockView world, BlockPos pos, BlockState state); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/ArgumentTypesMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 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 lovexyn0827.mess.command.EnumSetArgumentType; 9 | import lovexyn0827.mess.command.ExtendedFloatArgumentType; 10 | import lovexyn0827.mess.command.FilteredSetArgumentType; 11 | import lovexyn0827.mess.util.access.AccessingPathArgumentType; 12 | import lovexyn0827.mess.util.phase.TickingPhaseArgumentType; 13 | import net.minecraft.command.argument.ArgumentTypes; 14 | 15 | @Mixin(ArgumentTypes.class) 16 | public class ArgumentTypesMixin { 17 | @Inject(method = "register()V", at = @At(value = "HEAD")) 18 | private static void addMessModArgumentTypes(CallbackInfo ci) { 19 | EnumSetArgumentType.registerArgumentType(); 20 | ExtendedFloatArgumentType.registerArgumentType(); 21 | FilteredSetArgumentType.registerArgumentType(); 22 | AccessingPathArgumentType.registerArgumentType(); 23 | TickingPhaseArgumentType.registerArgumentType(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/BlockItemMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 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 | import org.spongepowered.asm.mixin.injection.callback.LocalCapture; 8 | 9 | import lovexyn0827.mess.fakes.ServerPlayerEntityInterface; 10 | import lovexyn0827.mess.options.OptionManager; 11 | import lovexyn0827.mess.util.BlockPlacementHistory; 12 | import net.minecraft.block.BlockState; 13 | import net.minecraft.entity.player.PlayerEntity; 14 | import net.minecraft.item.BlockItem; 15 | import net.minecraft.item.ItemPlacementContext; 16 | import net.minecraft.server.network.ServerPlayerEntity; 17 | import net.minecraft.util.ActionResult; 18 | 19 | @Mixin(BlockItem.class) 20 | public class BlockItemMixin { 21 | @Inject(method = "place(Lnet/minecraft/item/ItemPlacementContext;)Lnet/minecraft/util/ActionResult;", 22 | at = @At(value = "INVOKE", 23 | target = "Lnet/minecraft/item/BlockItem;place" 24 | + "(Lnet/minecraft/item/ItemPlacementContext;Lnet/minecraft/block/BlockState;)Z" 25 | ), 26 | locals = LocalCapture.CAPTURE_FAILHARD) 27 | private void recordPlacement(ItemPlacementContext context, CallbackInfoReturnable cir, 28 | ItemPlacementContext itemPlacementContext, BlockState blockState) { 29 | PlayerEntity player = context.getPlayer(); 30 | if(OptionManager.blockPlacementHistory && context.getPlayer() instanceof ServerPlayerEntity) { 31 | BlockPlacementHistory history = ((ServerPlayerEntityInterface) player).getBlockPlacementHistory(); 32 | if(history != null) { 33 | history.pushSingle(context.getBlockPos(), player.world.getBlockState(context.getBlockPos()), 34 | blockState, player.world.getBlockEntity(context.getBlockPos())); 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/BlockPosArgumentTypeMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 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 | import com.mojang.brigadier.context.CommandContext; 8 | 9 | import lovexyn0827.mess.options.OptionManager; 10 | import net.minecraft.command.argument.BlockPosArgumentType; 11 | import net.minecraft.command.argument.PosArgument; 12 | import net.minecraft.server.command.ServerCommandSource; 13 | import net.minecraft.util.math.BlockPos; 14 | 15 | @Mixin(BlockPosArgumentType.class) 16 | public class BlockPosArgumentTypeMixin { 17 | @Inject(method = "getLoadedBlockPos", 18 | at = @At(value = "HEAD"), 19 | cancellable = true 20 | ) 21 | private static void returnIfNeeded(CommandContext context, String name, CallbackInfoReturnable cir) { 22 | if(OptionManager.disableChunkLoadingCheckInCommands) { 23 | BlockPos blockPos = ((PosArgument)context.getArgument(name, PosArgument.class)) 24 | .toAbsoluteBlockPos((ServerCommandSource)context.getSource()); 25 | cir.setReturnValue(blockPos); 26 | cir.cancel(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/BlockStateArgumentMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import org.jetbrains.annotations.Nullable; 4 | import org.spongepowered.asm.mixin.Final; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.Shadow; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.Inject; 9 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 10 | import org.spongepowered.asm.mixin.injection.callback.LocalCapture; 11 | 12 | import lovexyn0827.mess.options.OptionManager; 13 | import lovexyn0827.mess.util.BlockPlacementHistory; 14 | import net.minecraft.block.BlockState; 15 | import net.minecraft.command.argument.BlockStateArgument; 16 | import net.minecraft.nbt.CompoundTag; 17 | import net.minecraft.server.world.ServerWorld; 18 | import net.minecraft.util.math.BlockPos; 19 | 20 | @Mixin(BlockStateArgument.class) 21 | public class BlockStateArgumentMixin { 22 | @Nullable @Shadow @Final 23 | private CompoundTag data; 24 | 25 | @Inject(method = "setBlockState", at = @At(value = "INVOKE", target = "net/minecraft/server/world/ServerWorld." 26 | + "setBlockState(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;I)Z"), 27 | locals = LocalCapture.CAPTURE_FAILHARD) 28 | private void onSetBlock(ServerWorld serverWorld, BlockPos blockPos, int i, CallbackInfoReturnable cir, 29 | BlockState blockState) { 30 | if(OptionManager.fillHistory) { 31 | BlockPlacementHistory.appendBlockChange(serverWorld, blockPos, serverWorld.getBlockState(blockPos), 32 | blockState, null, this.data); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/BoatEntityAccessor.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.gen.Accessor; 5 | 6 | import net.minecraft.entity.vehicle.BoatEntity; 7 | 8 | @Mixin(BoatEntity.class) 9 | public interface BoatEntityAccessor { 10 | @Accessor("velocityDecay") 11 | public float getVelocityDeacyMCWMEM(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/ChunkTicketManagerNearbyChunkTicketUpdaterMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 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.callback.CallbackInfo; 8 | 9 | import lovexyn0827.mess.MessMod; 10 | import lovexyn0827.mess.fakes.ChunkTicketManagerInterface; 11 | import lovexyn0827.mess.log.chunk.ChunkBehaviorLogger; 12 | import lovexyn0827.mess.log.chunk.ChunkEvent; 13 | import lovexyn0827.mess.util.blame.StackTrace; 14 | import net.minecraft.server.world.ChunkTicketManager; 15 | 16 | @Mixin(ChunkTicketManager.NearbyChunkTicketUpdater.class) 17 | public class ChunkTicketManagerNearbyChunkTicketUpdaterMixin { 18 | @Shadow() 19 | private ChunkTicketManager field_17463; 20 | 21 | @Inject(method = "updateTicket", at = @At("HEAD")) 22 | private void updateTicket(long pos, int distance, 23 | boolean oldWithinViewDistance, boolean withinViewDistance, CallbackInfo ci) { 24 | if(ChunkBehaviorLogger.shouldSkip()) { 25 | return; 26 | } 27 | 28 | MessMod.INSTANCE.getChunkLogger().onEvent(ChunkEvent.PLAYER_TICKER_UPDATE, pos, 29 | ((ChunkTicketManagerInterface) this.field_17463).getDimesionId(), Thread.currentThread(), 30 | StackTrace.blameCurrent(), 31 | String.format("%s -> %s[%d]", oldWithinViewDistance, withinViewDistance, distance)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/ClientCommandSourceMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import java.util.Collection; 4 | import java.util.Collections; 5 | 6 | import org.spongepowered.asm.mixin.Final; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.Shadow; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Inject; 11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 12 | 13 | import lovexyn0827.mess.fakes.MinecraftClientInterface; 14 | import lovexyn0827.mess.options.OptionManager; 15 | import net.minecraft.client.MinecraftClient; 16 | import net.minecraft.client.network.ClientCommandSource; 17 | import net.minecraft.entity.Entity; 18 | 19 | @Mixin(ClientCommandSource.class) 20 | public class ClientCommandSourceMixin { 21 | @Shadow 22 | private @Final MinecraftClient client; 23 | 24 | @Inject(method = "getEntitySuggestions", at = @At("HEAD"), cancellable = true) 25 | private void tryUseIndependentlyPickedEntity(CallbackInfoReturnable> cir) { 26 | if(OptionManager.independentEntityPickerForInfomation) { 27 | Entity e = ((MinecraftClientInterface) this.client).getTargetForCommandSuggestions(); 28 | cir.setReturnValue(e == null ? Collections.emptyList() : Collections.singleton(e.getUuidAsString())); 29 | cir.cancel(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/ClientConnectionMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import java.lang.reflect.Field; 4 | 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.Shadow; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.Inject; 9 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 10 | 11 | import io.netty.channel.ChannelHandlerContext; 12 | import io.netty.util.concurrent.Future; 13 | import io.netty.util.concurrent.GenericFutureListener; 14 | import lovexyn0827.mess.MessMod; 15 | import lovexyn0827.mess.command.LogPacketCommand; 16 | import lovexyn0827.mess.util.deobfuscating.Mapping; 17 | import net.minecraft.network.ClientConnection; 18 | import net.minecraft.network.NetworkSide; 19 | import net.minecraft.network.Packet; 20 | 21 | @Mixin(ClientConnection.class) 22 | public class ClientConnectionMixin { 23 | @Shadow 24 | private NetworkSide side; 25 | 26 | @Inject(method = "sendImmediately", at = @At("HEAD")) 27 | private void onPacketBeingSended(Packet packet, GenericFutureListener> callback, CallbackInfo ci) { 28 | if(LogPacketCommand.isSubscribed(packet)) { 29 | MessMod.LOGGER.info("{}: Sended Packet: {}", 30 | this.side == NetworkSide.CLIENTBOUND ? "CLIENT" : "SERVER", 31 | toString(packet)); 32 | } 33 | } 34 | 35 | @Inject(method = "channelRead0", at = @At("HEAD")) 36 | private void onPacketBeingSended(ChannelHandlerContext channelHandlerContext, Packet packet, CallbackInfo ci) { 37 | if(LogPacketCommand.isSubscribed(packet)) { 38 | MessMod.LOGGER.info("{}: Received Packet: {}", 39 | this.side == NetworkSide.CLIENTBOUND ? "CLIENT" : "SERVER", 40 | toString(packet)); 41 | } 42 | } 43 | 44 | private static String toString(Packet packet) { 45 | Mapping mapping = MessMod.INSTANCE.getMapping(); 46 | StringBuilder sb = new StringBuilder(mapping.simpleNamedClass(packet.getClass().getName())); 47 | sb.append('['); 48 | for(Field f : packet.getClass().getDeclaredFields()) { 49 | f.setAccessible(true); 50 | try { 51 | sb.append(mapping.namedField(f.getName())).append('=').append(f.get(packet)).append(','); 52 | } catch (Exception e) { 53 | e.printStackTrace(); 54 | } 55 | } 56 | 57 | sb.append(']'); 58 | return sb.toString(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/ClientPlayNetworkHandlerMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 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 lovexyn0827.mess.MessMod; 9 | import lovexyn0827.mess.network.MessClientNetworkHandler; 10 | import net.minecraft.client.network.ClientPlayNetworkHandler; 11 | import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; 12 | import net.minecraft.network.packet.s2c.play.DisconnectS2CPacket; 13 | import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket; 14 | import net.minecraft.network.packet.s2c.play.PlayerRespawnS2CPacket; 15 | 16 | @Mixin(ClientPlayNetworkHandler.class) 17 | public abstract class ClientPlayNetworkHandlerMixin { 18 | @Inject(method = "onGameJoin",at = @At(value = "RETURN")) 19 | private void onGameJoined(GameJoinS2CPacket packet, CallbackInfo ci) { 20 | MessMod.INSTANCE.onGameJoined(packet); 21 | } 22 | 23 | @Inject(method = "onPlayerRespawn",at = @At(value = "RETURN")) 24 | private void onPlayerRespawned(PlayerRespawnS2CPacket packet, CallbackInfo ci) { 25 | MessMod.INSTANCE.onPlayerRespawned(packet); 26 | } 27 | 28 | @Inject(method = "onDisconnect",at = @At(value = "RETURN")) 29 | private void onPlayerDisconnect(DisconnectS2CPacket packet, CallbackInfo ci) { 30 | MessMod.INSTANCE.onDisconnect(packet); 31 | } 32 | 33 | @Inject(method = "onCustomPayload", at = @At("HEAD"), cancellable = true) 34 | private void onCustomPayload(CustomPayloadS2CPacket packet, CallbackInfo ci) { 35 | MessClientNetworkHandler handler = MessMod.INSTANCE.getClientNetworkHandler(); 36 | if(handler != null) { 37 | if (MessMod.INSTANCE.getClientNetworkHandler().handlePacket(packet)) { 38 | ci.cancel(); 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/ClientPlayerEntityMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import org.spongepowered.asm.mixin.injection.At; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.injection.Redirect; 6 | 7 | import lovexyn0827.mess.options.OptionManager; 8 | import net.minecraft.client.network.ClientPlayerEntity; 9 | import net.minecraft.entity.player.PlayerAbilities; 10 | 11 | @Mixin(value = ClientPlayerEntity.class, priority = 900) 12 | public abstract class ClientPlayerEntityMixin { 13 | @Redirect(method = "tickMovement", 14 | at = @At(value = "INVOKE", 15 | target = "Lnet/minecraft/entity/player/PlayerAbilities;getFlySpeed()F" 16 | )) 17 | private float modifySpeed(PlayerAbilities abilities) { 18 | float speed = OptionManager.creativeUpwardsSpeed; 19 | if(abilities.creativeMode) { 20 | return Float.isFinite(speed) ? speed : abilities.getFlySpeed(); 21 | } else { 22 | return abilities.getFlySpeed(); 23 | } 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/CloneCommandMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.injection.At; 5 | import org.spongepowered.asm.mixin.injection.ModifyArg; 6 | import org.spongepowered.asm.mixin.injection.Redirect; 7 | 8 | import lovexyn0827.mess.options.OptionManager; 9 | import net.minecraft.server.command.CloneCommand; 10 | import net.minecraft.server.world.ServerWorld; 11 | import net.minecraft.util.math.BlockPos; 12 | 13 | @Mixin(CloneCommand.class) 14 | public abstract class CloneCommandMixin { 15 | @Redirect(method = "execute", 16 | at = @At(value = "INVOKE", 17 | target = "Lnet/minecraft/server/world/ServerWorld;" 18 | + "isRegionLoaded(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/math/BlockPos;)Z") 19 | ) 20 | private static boolean modifyToLoaded(ServerWorld world, BlockPos p1, BlockPos p2) { 21 | return world.isRegionLoaded(p1, p2) || OptionManager.disableChunkLoadingCheckInCommands; 22 | } 23 | 24 | @ModifyArg(method = "execute", 25 | at = @At(value = "INVOKE", 26 | target = "Lnet/minecraft/block/pattern/CachedBlockPosition;" 27 | + "(Lnet/minecraft/world/WorldView;Lnet/minecraft/util/math/BlockPos;Z)V"), 28 | index = 2) 29 | private static boolean forceLoadIfNeeded(boolean forceLoad) { 30 | return forceLoad || OptionManager.disableChunkLoadingCheckInCommands; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/CommandManagerRegistrationEnvironmentAccessor.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.gen.Accessor; 5 | 6 | import net.minecraft.server.command.CommandManager; 7 | 8 | @Mixin(CommandManager.RegistrationEnvironment.class) 9 | public interface CommandManagerRegistrationEnvironmentAccessor { 10 | @Accessor("dedicated") 11 | boolean isDedicated(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/CraftingTableBlockMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | 5 | import lovexyn0827.mess.options.OptionManager; 6 | import lovexyn0827.mess.util.FormattedText; 7 | import net.minecraft.block.AbstractBlock; 8 | import net.minecraft.block.Block; 9 | import net.minecraft.block.BlockState; 10 | import net.minecraft.block.CraftingTableBlock; 11 | import net.minecraft.network.MessageType; 12 | import net.minecraft.server.world.ServerWorld; 13 | import net.minecraft.util.Util; 14 | import net.minecraft.util.math.BlockPos; 15 | import net.minecraft.world.World; 16 | import net.minecraft.world.WorldAccess; 17 | 18 | @Mixin(CraftingTableBlock.class) 19 | public abstract class CraftingTableBlockMixin extends AbstractBlock { 20 | protected CraftingTableBlockMixin(Settings settings) { 21 | super(settings); 22 | } 23 | 24 | @Override 25 | public void neighborUpdate(BlockState state, World world, BlockPos pos, Block block, BlockPos fromPos, boolean notify) { 26 | if(OptionManager.craftingTableBUD && !world.isClient) { 27 | if(world instanceof ServerWorld) { 28 | ServerWorld sw = (ServerWorld) world; 29 | sw.getServer().getPlayerManager().broadcastChatMessage( 30 | new FormattedText("NC: Tick %d @ (%d, %d, %d)", "cl", false, world.getTime(), 31 | pos.getX(), pos.getY(), pos.getZ()).asMutableText(), 32 | MessageType.SYSTEM, Util.NIL_UUID); 33 | } 34 | } 35 | } 36 | 37 | @Override 38 | public void prepare(BlockState state, WorldAccess world, BlockPos pos, int flags, int maxUpdateDepth) { 39 | if(OptionManager.craftingTableBUD && world instanceof ServerWorld) { 40 | ServerWorld sw = (ServerWorld) world; 41 | sw.getServer().getPlayerManager().broadcastChatMessage( 42 | new FormattedText("PP: Tick %d @ (%d, %d, %d)", "1l", false, sw.getTime(), 43 | pos.getX(), pos.getY(), pos.getZ()).asMutableText(), 44 | MessageType.SYSTEM, Util.NIL_UUID); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/CreativeInventoryScreenMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 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 lovexyn0827.mess.options.OptionManager; 9 | import lovexyn0827.mess.util.FormattedText; 10 | import net.minecraft.client.MinecraftClient; 11 | import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen; 12 | 13 | @Mixin(CreativeInventoryScreen.class) 14 | public class CreativeInventoryScreenMixin { 15 | @Inject(method = "onHotbarKeyPress", 16 | at = @At(value = "HEAD"), 17 | cancellable = true 18 | ) 19 | private static void cancelHotbarStorageOperation(MinecraftClient client, int index, boolean restore, boolean save, 20 | CallbackInfo ci) { 21 | if(OptionManager.hotbarLength != 9) { 22 | client.inGameHud.setOverlayMessage(new FormattedText("misc.cancelhotbarstorage", "lc").asMutableText(), false); 23 | ci.cancel(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/CustomPayloadC2SPacketAccessor.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.gen.Accessor; 5 | 6 | import net.minecraft.network.PacketByteBuf; 7 | import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; 8 | import net.minecraft.util.Identifier; 9 | 10 | @Mixin(CustomPayloadC2SPacket.class) 11 | public interface CustomPayloadC2SPacketAccessor { 12 | @Accessor("channel") 13 | public Identifier getMessChannel(); 14 | 15 | @Accessor("data") 16 | public PacketByteBuf getMessData(); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/DataCommandStorageAccessor.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import java.util.Map; 4 | 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | 8 | import net.minecraft.command.DataCommandStorage; 9 | import net.minecraft.world.PersistentState; 10 | 11 | @Mixin(DataCommandStorage.class) 12 | public interface DataCommandStorageAccessor { 13 | @Accessor("storages") 14 | Map getStorages(); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/DebugHudMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 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.ModifyArg; 7 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 8 | 9 | import lovexyn0827.mess.options.OptionManager; 10 | import net.minecraft.client.gui.hud.DebugHud; 11 | import net.minecraft.client.util.math.MatrixStack; 12 | import net.minecraft.util.MetricsData; 13 | 14 | @Mixin(DebugHud.class) 15 | public class DebugHudMixin { 16 | private boolean renderingFpsChart; 17 | 18 | @Inject(method = "drawMetricsData", at = @At("HEAD")) 19 | private void onGraphDrawingBegin(MatrixStack matrices, MetricsData metricsData, 20 | int x, int width, boolean showFps, CallbackInfo ci) { 21 | this.renderingFpsChart = showFps; 22 | } 23 | 24 | @ModifyArg( 25 | method = "drawMetricsData", 26 | at = @At( 27 | value = "INVOKE", 28 | target = "net/minecraft/util/MetricsData.method_15248(JII)I" 29 | ), 30 | index = 0 31 | ) 32 | private long scaleTpsChart(long toScale) { 33 | if(this.renderingFpsChart) { 34 | return toScale; 35 | } else { 36 | return (long) (toScale * (double) OptionManager.tpsGraphScale); 37 | } 38 | } 39 | 40 | @ModifyArg( 41 | method = "drawMetricsData", 42 | at = @At( 43 | value = "INVOKE", 44 | target = "net/minecraft/client/font/TextRenderer.draw" 45 | + "(Lnet/minecraft/client/util/math/MatrixStack;Ljava/lang/String;FFI)I" 46 | ), 47 | index = 1 48 | ) 49 | private String modifyTpsChartLabel(String original) { 50 | double scale = OptionManager.tpsGraphScale; 51 | if(scale == 1.0 || !original.endsWith("TPS")) { 52 | return original; 53 | } 54 | 55 | double scaled = 20 * scale; 56 | if(scaled == (int) scaled) { 57 | return Integer.toString((int) scaled) + " TPS"; 58 | } else { 59 | return Double.toString(scaled) + " TPS"; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/DebugRendererMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 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 lovexyn0827.mess.options.OptionManager; 9 | import net.minecraft.client.render.VertexConsumerProvider; 10 | import net.minecraft.client.render.debug.DebugRenderer; 11 | import net.minecraft.client.util.math.MatrixStack; 12 | 13 | @Mixin(DebugRenderer.class) 14 | public abstract class DebugRendererMixin { 15 | private boolean firstFrame; 16 | 17 | @Inject(method = "render", at = @At("HEAD")) 18 | public void renderMore(MatrixStack matrices, VertexConsumerProvider.Immediate vertexConsumers, 19 | double cameraX, double cameraY, double cameraZ, CallbackInfo ci) { 20 | if (this.firstFrame) { 21 | this.firstFrame = false; 22 | } 23 | 24 | if(OptionManager.vanillaDebugRenderers != null) { 25 | OptionManager.vanillaDebugRenderers.forEach((renderer) -> { 26 | try { 27 | ((DebugRenderer.Renderer) renderer.left().get().get(this)) 28 | .render(matrices, vertexConsumers, cameraX, cameraY, cameraZ); 29 | } catch (Exception e) { 30 | e.printStackTrace(); 31 | } 32 | }); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/DebugStickItemMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 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.Redirect; 7 | 8 | import lovexyn0827.mess.options.OptionManager; 9 | import net.minecraft.block.BlockState; 10 | import net.minecraft.entity.player.PlayerEntity; 11 | import net.minecraft.item.DebugStickItem; 12 | import net.minecraft.item.ItemStack; 13 | import net.minecraft.state.property.Property; 14 | import net.minecraft.util.math.BlockPos; 15 | import net.minecraft.world.WorldAccess; 16 | 17 | @Mixin(DebugStickItem.class) 18 | public abstract class DebugStickItemMixin { 19 | @Shadow public static BlockState cycle(BlockState state, Property property, boolean inverse) { 20 | return null; 21 | } 22 | 23 | @Redirect(method = "use", 24 | at = @At(value = "INVOKE", 25 | target = "Lnet/minecraft/item/DebugStickItem;cycle(Lnet/minecraft/block/BlockState;Lnet/minecraft/state/property/Property;Z)Lnet/minecraft/block/BlockState;") 26 | ) 27 | private BlockState skipInvaildStatesIfNeeded(BlockState state, Property property, boolean inverse, 28 | PlayerEntity player, BlockState stateDuplicated, WorldAccess world, BlockPos pos, boolean update, ItemStack stack) { 29 | if(OptionManager.debugStickSkipsInvaildState) { 30 | Object obj = state.get(property); 31 | BlockState to; 32 | while(!(to = cycle(state, property, inverse)).canPlaceAt(world, pos)) { 33 | if(!obj.equals(to.get(property))) break; 34 | } 35 | 36 | return to; 37 | } 38 | return cycle(state, property, inverse); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/EnchantCommandMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 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 lovexyn0827.mess.options.OptionManager; 8 | import net.minecraft.enchantment.Enchantment; 9 | import net.minecraft.item.ItemStack; 10 | import net.minecraft.server.command.EnchantCommand; 11 | 12 | @Mixin(EnchantCommand.class) 13 | public class EnchantCommandMixin { 14 | @Redirect( 15 | method = "execute", 16 | at = @At( 17 | value = "INVOKE", 18 | target = "net/minecraft/enchantment/Enchantment.getMaxLevel()I" 19 | ) 20 | ) 21 | private static int modifyMaxLevel(Enchantment e) { 22 | if(OptionManager.disableEnchantCommandRestriction) { 23 | return 2147483647; 24 | } else { 25 | return e.getMaxLevel(); 26 | } 27 | } 28 | 29 | @Redirect( 30 | method = "execute", 31 | at = @At( 32 | value = "INVOKE", 33 | target = "net/minecraft/enchantment/Enchantment.isAcceptableItem(Lnet/minecraft/item/ItemStack;)Z" 34 | ) 35 | ) 36 | private static boolean redirectItemValidation(Enchantment e, ItemStack stack) { 37 | if(OptionManager.disableEnchantCommandRestriction) { 38 | return true; 39 | } else { 40 | return e.isAcceptableItem(stack); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/EndEyeItemMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 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 lovexyn0827.mess.options.OptionManager; 9 | import net.minecraft.entity.player.PlayerEntity; 10 | import net.minecraft.item.EnderEyeItem; 11 | import net.minecraft.server.network.ServerPlayerEntity; 12 | import net.minecraft.server.world.ChunkTicketType; 13 | import net.minecraft.util.Hand; 14 | import net.minecraft.util.TypedActionResult; 15 | import net.minecraft.util.hit.HitResult; 16 | import net.minecraft.util.math.ChunkPos; 17 | import net.minecraft.util.math.Vec3d; 18 | import net.minecraft.world.RaycastContext; 19 | import net.minecraft.world.World; 20 | 21 | @Mixin(EnderEyeItem.class) 22 | public class EndEyeItemMixin { 23 | @Inject(method = "use", 24 | at = @At("HEAD") 25 | ) 26 | private void teleportIfNeeded(World world, PlayerEntity player, Hand h, CallbackInfoReturnable> ci) { 27 | if(OptionManager.endEyeTeleport) { 28 | if(player instanceof ServerPlayerEntity && player.abilities.allowFlying) { 29 | ServerPlayerEntity sp = (ServerPlayerEntity)player; 30 | Vec3d start = sp.getPos().add(0, sp.getStandingEyeHeight(), 0); 31 | float r = 180; 32 | try { 33 | float f = OptionManager.maxEndEyeTpRadius; 34 | if(f >= 0) { 35 | r = f; 36 | } 37 | } catch (NumberFormatException e) { 38 | } 39 | 40 | HitResult hit = sp.world.raycast(new RaycastContext(start, 41 | start.add(sp.getRotationVector().multiply(r)), 42 | RaycastContext.ShapeType.COLLIDER, 43 | RaycastContext.FluidHandling.NONE, 44 | sp)); 45 | if(hit.getType() != HitResult.Type.MISS) { 46 | Vec3d pos = hit.getPos(); 47 | sp.getServerWorld().getChunkManager().addTicket(ChunkTicketType.POST_TELEPORT, 48 | new ChunkPos(((int)sp.chunkX), ((int)sp.chunkZ)), 1, sp.getEntityId()); 49 | sp.networkHandler.requestTeleport(pos.x, pos.y, pos.z, sp.yaw, sp.pitch); 50 | } 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/EntityAccessor.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import java.util.Random; 4 | 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | 8 | import net.minecraft.entity.Entity; 9 | 10 | @Mixin(Entity.class) 11 | public interface EntityAccessor { 12 | @Accessor("random") 13 | public Random getRamdomMCWMEM(); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/EntityPredicatesMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 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 lovexyn0827.mess.options.OptionManager; 9 | import net.minecraft.entity.Entity; 10 | import net.minecraft.entity.vehicle.AbstractMinecartEntity; 11 | import net.minecraft.predicate.entity.EntityPredicates; 12 | import net.minecraft.scoreboard.AbstractTeam; 13 | 14 | @Mixin(EntityPredicates.class) 15 | public class EntityPredicatesMixin { 16 | @Inject(method = "method_5915", 17 | at = @At("HEAD"), 18 | cancellable = true, 19 | remap = false 20 | ) 21 | private static void skipEntityIfNeeded(Entity entity, AbstractTeam team, AbstractTeam.CollisionRule rule, 22 | Entity entityBeingTicked, CallbackInfoReturnable cir) { 23 | if(OptionManager.optimizedEntityPushing) { 24 | if(entity instanceof AbstractMinecartEntity) { 25 | if(entity.squaredDistanceTo(entityBeingTicked) < 9.999999747378752E-5D) { 26 | cir.setReturnValue(false); 27 | cir.cancel(); 28 | } 29 | } else { 30 | double dx = entity.getX() - entityBeingTicked.getX(); 31 | double dz = entity.getZ() - entityBeingTicked.getZ(); 32 | if(Math.abs(dx) < 0.009999999776482582D && Math.abs(dz) < 0.009999999776482582D) { 33 | cir.setReturnValue(false); 34 | cir.cancel(); 35 | } 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/EntitySelectorMixin_Server.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import java.util.List; 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 com.google.common.collect.Lists; 11 | 12 | import lovexyn0827.mess.fakes.EntitySelectorInterface; 13 | import lovexyn0827.mess.util.RaycastUtil; 14 | import net.minecraft.command.EntitySelector; 15 | import net.minecraft.entity.Entity; 16 | import net.minecraft.network.NetworkSide; 17 | import net.minecraft.server.command.ServerCommandSource; 18 | import net.minecraft.util.math.Vec3d; 19 | 20 | @Mixin(EntitySelector.class) 21 | public abstract class EntitySelectorMixin_Server implements EntitySelectorInterface { 22 | private boolean targetOnly; 23 | 24 | @Shadow 25 | protected abstract void checkSourcePermission(ServerCommandSource serverCommandSource); 26 | 27 | @Shadow 28 | private List getEntities(Vec3d vec3d, List list) { 29 | throw new AssertionError(); 30 | } 31 | 32 | @Inject(method = "getEntities(Lnet/minecraft/server/command/ServerCommandSource;)Ljava/util/List;", 33 | at = @At("HEAD"), 34 | cancellable = true 35 | ) 36 | private void selectTarget(ServerCommandSource serverCommandSource, 37 | CallbackInfoReturnable> cir) { 38 | if(this.targetOnly) { 39 | this.checkSourcePermission(serverCommandSource); 40 | List result = Lists.newArrayList(); 41 | Entity senderer = serverCommandSource.getEntity(); 42 | if(senderer != null) { 43 | Entity target = RaycastUtil.getTargetEntity(senderer); 44 | if(target != null) { 45 | result.add(target); 46 | } 47 | } 48 | 49 | cir.setReturnValue(result); 50 | cir.cancel(); 51 | } 52 | } 53 | 54 | @Override 55 | public void setTargetOnly(boolean targetOnly) { 56 | this.targetOnly = targetOnly; 57 | } 58 | 59 | @Override 60 | public void setSide(NetworkSide side) { 61 | return; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/FletchingTableBlockMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | 5 | import lovexyn0827.mess.fakes.ServerWorldInterface; 6 | import lovexyn0827.mess.options.OptionManager; 7 | import net.minecraft.block.Block; 8 | import net.minecraft.block.BlockState; 9 | import net.minecraft.block.FletchingTableBlock; 10 | import net.minecraft.block.AbstractBlock; 11 | import net.minecraft.network.MessageType; 12 | import net.minecraft.server.world.ServerWorld; 13 | import net.minecraft.util.Util; 14 | import net.minecraft.util.math.BlockPos; 15 | import net.minecraft.world.World; 16 | import net.minecraft.world.WorldAccess; 17 | 18 | @Mixin(FletchingTableBlock.class) 19 | public abstract class FletchingTableBlockMixin extends AbstractBlock { 20 | protected FletchingTableBlockMixin(Settings settings) { 21 | super(settings); 22 | } 23 | 24 | @Override 25 | public void neighborUpdate(BlockState state, World world, BlockPos pos, Block block, BlockPos fromPos, boolean notify) { 26 | if(OptionManager.fletchingTablePulseDetector && world instanceof ServerWorld) { 27 | detectPulse((ServerWorld) world, pos); 28 | } 29 | } 30 | 31 | @Override 32 | public void prepare(BlockState state, WorldAccess world, BlockPos pos, int flags, int maxUpdateDepth) { 33 | if(OptionManager.fletchingTablePulseDetector && world instanceof ServerWorld) { 34 | detectPulse((ServerWorld) world, pos); 35 | } 36 | } 37 | 38 | private static void detectPulse(ServerWorld sw, BlockPos pos) { 39 | boolean powered = sw.isReceivingRedstonePower(pos); 40 | ((ServerWorldInterface) sw) 41 | .getPulseRecorder() 42 | .setSignalLevel(pos, powered) 43 | .ifPresent((p) -> { 44 | sw.getServer().getPlayerManager().broadcastChatMessage( 45 | p.toText(), 46 | MessageType.SYSTEM, Util.NIL_UUID); 47 | }); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/FormattingAccessor.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.gen.Accessor; 5 | 6 | import net.minecraft.util.Formatting; 7 | 8 | @Mixin(Formatting.class) 9 | public interface FormattingAccessor { 10 | @Accessor("code") 11 | char getCode(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/GameRendererMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 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 lovexyn0827.mess.options.OptionManager; 9 | import net.minecraft.client.render.GameRenderer; 10 | import net.minecraft.entity.Entity; 11 | 12 | @Mixin(GameRenderer.class) 13 | public class GameRendererMixin { 14 | @Inject(method = "method_18144", 15 | at = @At("HEAD"), 16 | cancellable = true, 17 | remap = false 18 | ) 19 | private static void allowNonCollidableEntities(Entity e, CallbackInfoReturnable cir) { 20 | if(OptionManager.allowTargetingSpecialEntities) { 21 | cir.setReturnValue(true); 22 | cir.cancel(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/IdCountsStateAccessor.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.gen.Accessor; 5 | 6 | import it.unimi.dsi.fastutil.objects.Object2IntMap; 7 | import net.minecraft.world.IdCountsState; 8 | 9 | @Mixin(IdCountsState.class) 10 | public interface IdCountsStateAccessor { 11 | @Accessor("idCounts") 12 | Object2IntMap getIdCountsForMessMod(); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/InGameHudMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.injection.At; 5 | import org.spongepowered.asm.mixin.injection.Constant; 6 | import org.spongepowered.asm.mixin.injection.ModifyConstant; 7 | import org.spongepowered.asm.mixin.injection.Redirect; 8 | 9 | import lovexyn0827.mess.options.OptionManager; 10 | import net.minecraft.client.gui.DrawableHelper; 11 | import net.minecraft.client.gui.hud.InGameHud; 12 | import net.minecraft.client.util.math.MatrixStack; 13 | 14 | @Mixin(InGameHud.class) 15 | public class InGameHudMixin extends DrawableHelper { 16 | @ModifyConstant(method = "renderHotbar", constant = @Constant(intValue = 9)) 17 | private int modifyHotbarLength(int lengthO) { 18 | return OptionManager.hotbarLength; 19 | } 20 | 21 | @ModifyConstant(method = "renderHotbar", constant = @Constant(intValue = 90)) 22 | private int modifyHotbarHudLength(int lengthO) { 23 | return OptionManager.hotbarLength * 10; 24 | } 25 | 26 | @ModifyConstant(method = "renderHotbar", constant = @Constant(intValue = 91)) 27 | private int modifyHotbarHudLengthP1(int lengthO) { 28 | return OptionManager.hotbarLength * 10 + 1; 29 | } 30 | 31 | @Redirect(method = "renderHotbar", 32 | at = @At(value = "INVOKE", 33 | target = "Lnet/minecraft/client/gui/hud/InGameHud;drawTexture(Lnet/minecraft/client/util/math/MatrixStack;IIIIII)V", 34 | ordinal = 0 35 | ) 36 | ) 37 | private void drawHotbarBackground(InGameHud hud, MatrixStack matrices, int x, int y, int u, int v, int width, int height) { 38 | if(OptionManager.hotbarLength == 9) { 39 | this.drawTexture(matrices, x, y, u, v, width, height); 40 | } else { 41 | int slots = OptionManager.hotbarLength; 42 | hud.drawTexture(matrices, x, y, 0, 0, 1, 22); 43 | hud.drawTexture(matrices, x + slots * 20 + 1, y, 0, 0, 1, 22); 44 | for(int i = 0; i < slots; i++) { 45 | hud.drawTexture(matrices, x + i * 20 + 1, y, 1, 0, 20, 22); 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/ItemCooldownManagerMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 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 lovexyn0827.mess.options.OptionManager; 9 | import net.minecraft.entity.player.ItemCooldownManager; 10 | import net.minecraft.item.Item; 11 | 12 | @Mixin(ItemCooldownManager.class) 13 | public class ItemCooldownManagerMixin { 14 | @Inject(method = "set", at = @At(value = "HEAD"), cancellable = true) 15 | private void tryCancelUsageCooldown(Item item, int duration, CallbackInfo ci) { 16 | if(OptionManager.disableItemUsageCooldown) { 17 | ci.cancel(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/KillCommandMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 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 lovexyn0827.mess.options.OptionManager; 8 | import net.minecraft.entity.Entity; 9 | import net.minecraft.entity.mob.MobEntity; 10 | import net.minecraft.server.command.KillCommand; 11 | 12 | @Mixin(KillCommand.class) 13 | public abstract class KillCommandMixin { 14 | @Redirect(method = "execute", 15 | at = @At(value = "INVOKE", 16 | target = "Lnet/minecraft/entity/Entity;kill()V") 17 | ) 18 | private static void removeEntity(Entity entity) { 19 | if(OptionManager.mobFastKill && entity instanceof MobEntity) { 20 | entity.remove(); 21 | } else { 22 | entity.kill(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/LanguageManagerMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 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 lovexyn0827.mess.options.OptionManager; 9 | import lovexyn0827.mess.util.i18n.I18N; 10 | import net.minecraft.client.resource.language.LanguageDefinition; 11 | import net.minecraft.client.resource.language.LanguageManager; 12 | 13 | @Mixin(LanguageManager.class) 14 | public abstract class LanguageManagerMixin { 15 | @Inject(method = "setLanguage(Lnet/minecraft/client/resource/language/LanguageDefinition;)V", at = @At("HEAD")) 16 | private void updateLanguage(LanguageDefinition ld, CallbackInfo ci) { 17 | if("-FOLLOW_SYSTEM_SETTINGS-".equals(OptionManager.language)) { 18 | I18N.setLanguage(null, false); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/LivingEntityMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import org.objectweb.asm.Opcodes; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.injection.At; 6 | import org.spongepowered.asm.mixin.injection.Redirect; 7 | 8 | import lovexyn0827.mess.options.OptionManager; 9 | import net.minecraft.entity.LivingEntity; 10 | import net.minecraft.entity.damage.DamageSource; 11 | 12 | @Mixin(LivingEntity.class) 13 | public abstract class LivingEntityMixin { 14 | @Redirect(method = "applyEnchantmentsToDamage", 15 | at = @At(value = "FIELD", 16 | target = "net/minecraft/entity/damage/DamageSource.OUT_OF_WORLD" 17 | + ":Lnet/minecraft/entity/damage/DamageSource;", 18 | opcode = Opcodes.GETSTATIC)) 19 | private DamageSource redirectGetVoidDamageSource() { 20 | return OptionManager.resistanceReducesVoidDamage ? null : DamageSource.OUT_OF_WORLD; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/MinecartItemMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.injection.At; 5 | import org.spongepowered.asm.mixin.injection.ModifyVariable; 6 | import org.spongepowered.asm.mixin.injection.Redirect; 7 | 8 | import lovexyn0827.mess.options.OptionManager; 9 | import net.minecraft.block.Block; 10 | import net.minecraft.block.BlockState; 11 | import net.minecraft.item.ItemUsageContext; 12 | import net.minecraft.item.MinecartItem; 13 | import net.minecraft.tag.BlockTags; 14 | import net.minecraft.tag.Tag; 15 | import net.minecraft.util.math.Direction.Axis; 16 | import net.minecraft.world.World; 17 | 18 | @Mixin(MinecartItem.class) 19 | public abstract class MinecartItemMixin { 20 | @Redirect(method = "useOnBlock", 21 | at = @At(value = "INVOKE", 22 | target = "Lnet/minecraft/block/BlockState;isIn(Lnet/minecraft/tag/Tag;)Z" 23 | ) 24 | ) 25 | private boolean canPlaceMinecart(BlockState state, Tag tag) { 26 | return OptionManager.minecartPlacementOnNonRailBlocks || state.isIn(tag); 27 | } 28 | 29 | @ModifyVariable(method = "useOnBlock", 30 | at = @At(value = "INVOKE", 31 | target = "Lnet/minecraft/block/enums/RailShape;isAscending()Z", 32 | shift = At.Shift.BEFORE 33 | ), 34 | index = 7 35 | ) 36 | private double adjustHeight(double d, ItemUsageContext context) { 37 | if(OptionManager.minecartPlacementOnNonRailBlocks) { 38 | World world = context.getWorld(); 39 | BlockState state = world.getBlockState(context.getBlockPos()); 40 | double height = Math.max(state.getCollisionShape(world, context.getBlockPos()).getMax(Axis.Y), 0.0D); 41 | return state.isIn(BlockTags.RAILS) ? d : height - 0.0625; 42 | } else { 43 | return d; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/MinecraftServerAccessor.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.gen.Accessor; 5 | 6 | import net.minecraft.server.MinecraftServer; 7 | import net.minecraft.world.level.storage.LevelStorage; 8 | 9 | @Mixin(MinecraftServer.class) 10 | public interface MinecraftServerAccessor { 11 | @Accessor("session") 12 | LevelStorage.Session getSession(); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/MinecraftServerMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import java.util.function.BooleanSupplier; 4 | 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.injection.Inject; 7 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 8 | 9 | import lovexyn0827.mess.MessMod; 10 | import lovexyn0827.mess.util.phase.ServerTickingPhase; 11 | 12 | import org.spongepowered.asm.mixin.injection.At; 13 | 14 | import net.minecraft.server.MinecraftServer; 15 | 16 | @Mixin(MinecraftServer.class) 17 | public abstract class MinecraftServerMixin { 18 | @Inject(method = "tick", at = @At(value = "RETURN")) 19 | public void onTicked(BooleanSupplier bs, CallbackInfo ci) { 20 | ServerTickingPhase.TICKED_ALL_WORLDS.begin(null); 21 | MessMod.INSTANCE.onServerTicked((MinecraftServer)(Object) this); 22 | } 23 | 24 | @Inject(method = "runServer", 25 | at = @At(value = "INVOKE", 26 | target = "Lnet/minecraft/server/MinecraftServer;setupServer()Z", 27 | shift = At.Shift.AFTER 28 | ) 29 | ) 30 | private void onServerStarted(CallbackInfo ci) { 31 | MessMod.INSTANCE.onServerStarted((MinecraftServer)(Object)this); 32 | } 33 | 34 | @Inject(method = "shutdown",at = @At(value = "RETURN")) 35 | private void onServerShutdown(CallbackInfo ci) { 36 | MessMod.INSTANCE.onServerShutdown((MinecraftServer)(Object)this); 37 | } 38 | 39 | @Inject(method = "method_16208",at = @At(value = "HEAD")) 40 | private void onAsyncTasksBegin(CallbackInfo ci) { 41 | ServerTickingPhase.SERVER_TASKS.begin(null); 42 | } 43 | 44 | @Inject(method = "method_16208",at = @At(value = "RETURN")) 45 | private void onAsyncTasksExecuted(CallbackInfo ci) { 46 | ServerTickingPhase.REST.begin(null); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/NetworkStateAccessor.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import java.util.Map; 4 | 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | 8 | import net.minecraft.network.NetworkSide; 9 | import net.minecraft.network.NetworkState; 10 | 11 | @Mixin(NetworkState.class) 12 | public interface NetworkStateAccessor { 13 | @Accessor("packetHandlers") 14 | Map> getHandlerMap(); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/PistonExtensionBlockMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 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.callback.CallbackInfoReturnable; 8 | 9 | import lovexyn0827.mess.options.OptionManager; 10 | import net.minecraft.block.BlockState; 11 | import net.minecraft.block.PistonExtensionBlock; 12 | import net.minecraft.block.ShapeContext; 13 | import net.minecraft.util.math.BlockPos; 14 | import net.minecraft.util.shape.VoxelShape; 15 | import net.minecraft.world.BlockView; 16 | 17 | @Mixin(PistonExtensionBlock.class) 18 | public class PistonExtensionBlockMixin { 19 | @Shadow 20 | private VoxelShape getCollisionShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { 21 | return null; 22 | } 23 | 24 | @Inject(method = "getOutlineShape", at = @At("HEAD"), cancellable = true) 25 | private void replaceOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context, 26 | CallbackInfoReturnable cir) { 27 | if(OptionManager.interactableB36) { 28 | cir.setReturnValue(this.getCollisionShape(state, world, pos, context)); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/PlayerInventoryMixin_Client.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.injection.Constant; 5 | import org.spongepowered.asm.mixin.injection.ModifyConstant; 6 | 7 | import lovexyn0827.mess.options.OptionManager; 8 | import net.minecraft.entity.player.PlayerInventory; 9 | 10 | @Mixin(PlayerInventory.class) 11 | public class PlayerInventoryMixin_Client { 12 | @ModifyConstant(method = "scrollInHotbar", constant = @Constant(intValue = 9)) 13 | int modifyHotbarLength(int lengthO) { 14 | return OptionManager.hotbarLength; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/PlayerInventoryMixin_Server.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import org.objectweb.asm.Opcodes; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.injection.At; 6 | import org.spongepowered.asm.mixin.injection.Constant; 7 | import org.spongepowered.asm.mixin.injection.ModifyConstant; 8 | import org.spongepowered.asm.mixin.injection.Redirect; 9 | 10 | import lovexyn0827.mess.options.OptionManager; 11 | import net.minecraft.entity.player.PlayerAbilities; 12 | import net.minecraft.entity.player.PlayerInventory; 13 | 14 | @Mixin(PlayerInventory.class) 15 | public class PlayerInventoryMixin_Server { 16 | @ModifyConstant(method = { "getHotbarSize", "isValidHotbarIndex" }, constant = @Constant(intValue = 9)) 17 | private static int modifyHotbarLength(int lengthO) { 18 | return OptionManager.hotbarLength; 19 | } 20 | 21 | @Redirect(method = "insertStack(ILnet/minecraft/item/ItemStack;)Z", 22 | at = @At(value = "FIELD", 23 | target = "net/minecraft/entity/player/PlayerAbilities.creativeMode:Z", 24 | opcode = Opcodes.GETFIELD 25 | )) 26 | private boolean shouldAlwaysPickupItems(PlayerAbilities abilities) { 27 | return !OptionManager.disableCreativeForcePickup && abilities.creativeMode; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/PlayerManagerMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 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 lovexyn0827.mess.MessMod; 9 | import net.minecraft.network.ClientConnection; 10 | import net.minecraft.server.PlayerManager; 11 | import net.minecraft.server.network.ServerPlayerEntity; 12 | 13 | @Mixin(PlayerManager.class) 14 | public abstract class PlayerManagerMixin { 15 | @Inject(method = "onPlayerConnect", at = @At(value = "RETURN")) 16 | private void onServerPlayerSpawned(ClientConnection connection, ServerPlayerEntity player, CallbackInfo ci) { 17 | MessMod.INSTANCE.onServerPlayerSpawned(player); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/ProjectileEntityMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.injection.Inject; 5 | import org.spongepowered.asm.mixin.injection.ModifyVariable; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 8 | 9 | import lovexyn0827.mess.options.OptionManager; 10 | import net.minecraft.entity.Entity; 11 | import net.minecraft.entity.EntityType; 12 | import net.minecraft.entity.projectile.FireworkRocketEntity; 13 | import net.minecraft.entity.projectile.ProjectileEntity; 14 | import net.minecraft.server.world.ChunkTicketType; 15 | import net.minecraft.server.world.ServerWorld; 16 | import net.minecraft.util.math.ChunkPos; 17 | import net.minecraft.util.math.Vec3d; 18 | import net.minecraft.world.World; 19 | 20 | @Mixin(ProjectileEntity.class) 21 | public abstract class ProjectileEntityMixin extends Entity { 22 | private static final ChunkTicketType ENTITY_TICKET = ChunkTicketType.create("projectile", (a, b) -> 1, 3); 23 | private static final ChunkTicketType PERMANENT_ENTITY_TICKET = ChunkTicketType.create("projectile_permanent", (a, b) -> 1); 24 | private ProjectileEntityMixin(EntityType type, World world) { 25 | super(type, world); 26 | } 27 | 28 | @Inject(method = "tick", 29 | at = @At("TAIL") 30 | ) 31 | private void loadChunkIfNeeded(CallbackInfo ci) { 32 | if(!this.world.isClient) { 33 | // Firework rockets are not supported because their movements are hard to predict. 34 | if(OptionManager.projectileChunkLoading && !((Object)this instanceof FireworkRocketEntity)) { 35 | ServerWorld world = (ServerWorld)this.world; 36 | Vec3d nextPos = this.getPos().add(this.getVelocity()); 37 | ChunkTicketType tt = OptionManager.projectileChunkLoadingPermanence ? PERMANENT_ENTITY_TICKET : ENTITY_TICKET; 38 | world.getServer().submitAndJoin(() -> 39 | world.getChunkManager().addTicket(tt, new ChunkPos((int)(nextPos.x / 16), 40 | (int)(nextPos.z / 16)), OptionManager.projectileChunkLoadingRange, this)); 41 | } 42 | } 43 | } 44 | 45 | @ModifyVariable(method = "setVelocity", 46 | at = @At("HEAD"), 47 | ordinal = 1) 48 | private float tryRemoveRandomness(float dIn) { 49 | return OptionManager.disableProjectileRandomness ? 0.0F : dIn * OptionManager.projectileRandomnessScale; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/RaidManagerAccessor.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import java.util.Map; 4 | 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Accessor; 7 | 8 | import net.minecraft.village.raid.Raid; 9 | import net.minecraft.village.raid.RaidManager; 10 | 11 | @Mixin(RaidManager.class) 12 | public interface RaidManagerAccessor { 13 | @Accessor("raids") 14 | Map getRaids(); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/RailPlacementHelperMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 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 lovexyn0827.mess.options.OptionManager; 9 | import net.minecraft.block.RailPlacementHelper; 10 | import net.minecraft.util.math.BlockPos; 11 | 12 | @Mixin(RailPlacementHelper.class) 13 | public abstract class RailPlacementHelperMixin { 14 | @Inject(method = "canConnect(Lnet/minecraft/util/math/BlockPos;)Z", at = @At("HEAD")) 15 | private void cancelIfNeeded(BlockPos bp, CallbackInfoReturnable cir) { 16 | if(OptionManager.railNoAutoConnection) { 17 | cir.setReturnValue(false); 18 | cir.cancel(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/RegionBasedStorageAccessor.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import java.io.File; 4 | 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Invoker; 7 | 8 | import net.minecraft.nbt.CompoundTag; 9 | import net.minecraft.util.math.ChunkPos; 10 | import net.minecraft.world.storage.RegionBasedStorage; 11 | 12 | @Mixin(RegionBasedStorage.class) 13 | public interface RegionBasedStorageAccessor { 14 | @Invoker("") 15 | public static RegionBasedStorage create(File directory, boolean dsync) { 16 | throw new AssertionError(); 17 | } 18 | 19 | @Invoker("write") 20 | void writeChunk(ChunkPos pos, CompoundTag tag); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/ServerChunkManagerMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 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.callback.CallbackInfo; 8 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 9 | import org.spongepowered.asm.mixin.injection.callback.LocalCapture; 10 | 11 | import lovexyn0827.mess.MessMod; 12 | import lovexyn0827.mess.command.LazyLoadCommand; 13 | import lovexyn0827.mess.fakes.EntityInterface; 14 | import lovexyn0827.mess.log.chunk.ChunkBehaviorLogger; 15 | import lovexyn0827.mess.log.chunk.ChunkEvent; 16 | import lovexyn0827.mess.util.blame.StackTrace; 17 | import net.minecraft.entity.Entity; 18 | import net.minecraft.server.world.ServerChunkManager; 19 | import net.minecraft.server.world.ServerWorld; 20 | import net.minecraft.util.math.ChunkPos; 21 | import net.minecraft.util.math.MathHelper; 22 | 23 | @Mixin(ServerChunkManager.class) 24 | public class ServerChunkManagerMixin { 25 | @Shadow 26 | private ServerWorld world; 27 | 28 | @Inject(method = "shouldTickEntity", at = @At("HEAD"), cancellable = true) 29 | private void tickEntityIfNeeded(Entity entity, CallbackInfoReturnable cir) { 30 | if(((EntityInterface) entity).isFrozen()) { 31 | cir.setReturnValue(false); 32 | cir.cancel(); 33 | } else if(!LazyLoadCommand.LAZY_CHUNKS.isEmpty()) { 34 | long pos = ChunkPos.toLong(MathHelper.floor(entity.getX()) >> 4, MathHelper.floor(entity.getZ()) >> 4); 35 | if(LazyLoadCommand.LAZY_CHUNKS.containsKey(this.world.getRegistryKey()) 36 | && LazyLoadCommand.LAZY_CHUNKS.get(this.world.getRegistryKey()).contains(pos)) { 37 | cir.setReturnValue(false); 38 | cir.cancel(); 39 | } 40 | } 41 | } 42 | 43 | @Inject(method = "initChunkCaches", at = @At("HEAD")) 44 | protected void onInitCaches(CallbackInfo cir) { 45 | if(ChunkBehaviorLogger.shouldSkip()) { 46 | return; 47 | } 48 | 49 | MessMod.INSTANCE.getChunkLogger().onEvent(ChunkEvent.SCM_INIT_CACHE, ChunkPos.MARKER, 50 | this.world.getRegistryKey().getValue(), Thread.currentThread(), StackTrace.blameCurrent(), 51 | null); 52 | } 53 | 54 | @Inject(method = "tick()Z", at = @At("JUMP"), locals = LocalCapture.CAPTURE_FAILHARD) 55 | protected void onTickNoArg(CallbackInfoReturnable cir, boolean blCTM, boolean blTACS) { 56 | if(ChunkBehaviorLogger.shouldSkip()) { 57 | return; 58 | } 59 | 60 | MessMod.INSTANCE.getChunkLogger().onEvent(ChunkEvent.SCM_TICK, ChunkPos.MARKER, 61 | this.world.getRegistryKey().getValue(), Thread.currentThread(), StackTrace.blameCurrent(), 62 | String.format("CTM: %s; TACS: %s", blCTM, blTACS)); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/ServerCommandSourceAccessor.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.gen.Accessor; 5 | 6 | import net.minecraft.server.command.CommandOutput; 7 | import net.minecraft.server.command.ServerCommandSource; 8 | 9 | @Mixin(ServerCommandSource.class) 10 | public interface ServerCommandSourceAccessor { 11 | @Accessor("output") 12 | CommandOutput getOutput(); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/ServerPlayerEntityMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import org.spongepowered.asm.mixin.Final; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.injection.At; 6 | import org.spongepowered.asm.mixin.injection.Inject; 7 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 8 | 9 | import com.mojang.authlib.GameProfile; 10 | 11 | import lovexyn0827.mess.fakes.ServerPlayerEntityInterface; 12 | import lovexyn0827.mess.options.OptionManager; 13 | import lovexyn0827.mess.util.BlockPlacementHistory; 14 | import net.minecraft.entity.player.PlayerEntity; 15 | import net.minecraft.server.MinecraftServer; 16 | import net.minecraft.server.network.ServerPlayerEntity; 17 | import net.minecraft.server.network.ServerPlayerInteractionManager; 18 | import net.minecraft.server.world.ServerWorld; 19 | import net.minecraft.util.math.BlockPos; 20 | import net.minecraft.world.World; 21 | 22 | @Mixin(ServerPlayerEntity.class) 23 | public abstract class ServerPlayerEntityMixin extends PlayerEntity implements ServerPlayerEntityInterface { 24 | public ServerPlayerEntityMixin(World world, BlockPos pos, float yaw, GameProfile profile) { 25 | super(world, pos, yaw, profile); 26 | } 27 | 28 | private @Final BlockPlacementHistory blockPlacementHistory; 29 | 30 | @Override 31 | public BlockPlacementHistory getBlockPlacementHistory() { 32 | return this.blockPlacementHistory; 33 | } 34 | 35 | @Inject(method = "", at = @At("RETURN")) 36 | private void onCreate(MinecraftServer server, ServerWorld world, GameProfile profile, 37 | ServerPlayerInteractionManager interactionManager, CallbackInfo ci) { 38 | this.blockPlacementHistory = new BlockPlacementHistory((ServerPlayerEntity)(Object) this); 39 | } 40 | 41 | @Override 42 | protected void destroy() { 43 | if (!OptionManager.creativeNoVoidDamage || !this.abilities.invulnerable) { 44 | super.destroy(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/SpawnEggItemMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 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.callback.CallbackInfoReturnable; 8 | 9 | import lovexyn0827.mess.options.OptionManager; 10 | import lovexyn0827.mess.util.RaycastUtil; 11 | import net.minecraft.entity.Entity; 12 | import net.minecraft.entity.EntityType; 13 | import net.minecraft.entity.SpawnReason; 14 | import net.minecraft.entity.player.PlayerEntity; 15 | import net.minecraft.item.ItemStack; 16 | import net.minecraft.item.SpawnEggItem; 17 | import net.minecraft.nbt.CompoundTag; 18 | import net.minecraft.server.network.ServerPlayerEntity; 19 | import net.minecraft.server.world.ServerWorld; 20 | import net.minecraft.util.Hand; 21 | import net.minecraft.util.TypedActionResult; 22 | import net.minecraft.util.math.BlockPos; 23 | import net.minecraft.world.World; 24 | 25 | @Mixin(value = SpawnEggItem.class, priority = 1001) 26 | public abstract class SpawnEggItemMixin { 27 | @Shadow 28 | protected abstract EntityType getEntityType(CompoundTag tag); 29 | 30 | @Inject(method = "use(Lnet/minecraft/world/World;Lnet/minecraft/entity/player/PlayerEntity;" 31 | + "Lnet/minecraft/util/Hand;)Lnet/minecraft/util/TypedActionResult;", 32 | at = @At(value = "HEAD"), 33 | cancellable = true 34 | ) 35 | public void mountIfNeeded(World world, PlayerEntity user, Hand hand, 36 | CallbackInfoReturnable> cir) { 37 | if(OptionManager.quickMobMounting && user instanceof ServerPlayerEntity && user.isSneaking()) { 38 | ServerPlayerEntity splayer = (ServerPlayerEntity) user; 39 | ItemStack stack = user.getStackInHand(hand); 40 | Entity vehicle = RaycastUtil.getTargetEntity(splayer); 41 | if(vehicle != null) { 42 | BlockPos pos = vehicle.getBlockPos(); 43 | Entity entity = this.getEntityType(stack.getTag()) 44 | .spawnFromItemStack((ServerWorld)world, stack, user, pos, SpawnReason.SPAWN_EGG, false, false); 45 | entity.startRiding(vehicle, true); 46 | if (!splayer.abilities.creativeMode) { 47 | stack.decrement(1); 48 | } 49 | 50 | cir.setReturnValue(TypedActionResult.consume(stack)); 51 | cir.cancel(); 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/StructureBlockBlockEntityMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | 5 | import lovexyn0827.mess.options.OptionManager; 6 | import net.minecraft.block.entity.BlockEntity; 7 | import net.minecraft.block.entity.BlockEntityType; 8 | import net.minecraft.block.entity.StructureBlockBlockEntity; 9 | 10 | /** 11 | * Loaded only when the Carpet mod is not loaded or the version is 1.4.24 or below. 12 | */ 13 | @Mixin(value = StructureBlockBlockEntity.class, priority = 1001) 14 | public abstract class StructureBlockBlockEntityMixin extends BlockEntity { 15 | public StructureBlockBlockEntityMixin(BlockEntityType type) { 16 | super(type); 17 | } 18 | 19 | @Override 20 | public double getSquaredRenderDistance() { 21 | return OptionManager.expandedStructureBlockRenderingRange ? 10E8D : super.getSquaredRenderDistance(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/TntEntityMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 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 lovexyn0827.mess.options.OptionManager; 9 | import net.minecraft.entity.Entity; 10 | import net.minecraft.entity.EntityType; 11 | import net.minecraft.entity.TntEntity; 12 | import net.minecraft.server.world.ChunkTicketType; 13 | import net.minecraft.server.world.ServerWorld; 14 | import net.minecraft.util.math.ChunkPos; 15 | import net.minecraft.util.math.Vec3d; 16 | import net.minecraft.world.World; 17 | 18 | @Mixin(TntEntity.class) 19 | public abstract class TntEntityMixin extends Entity{ 20 | private static final ChunkTicketType ENTITY_TICKET = ChunkTicketType.create("tnt", (a, b) -> 1, 3); 21 | private static final ChunkTicketType PERMANENT_ENTITY_TICKET = ChunkTicketType.create("tnt_permanent", (a, b) -> 1); 22 | 23 | private TntEntityMixin(EntityType type, World world) { 24 | super(type, world); 25 | } 26 | 27 | @Inject(method = "tick", 28 | at = @At("TAIL") 29 | ) 30 | private void loadChunkIfNeeded(CallbackInfo ci) { 31 | if(!this.world.isClient) { 32 | if(OptionManager.tntChunkLoading) { 33 | ServerWorld world = (ServerWorld)this.world; 34 | Vec3d nextPos = this.getPos(); 35 | ChunkTicketType tt = OptionManager.tntChunkLoadingPermanence ? PERMANENT_ENTITY_TICKET : ENTITY_TICKET; 36 | world.getServer().submitAndJoin(() -> world.getChunkManager().addTicket(tt, 37 | new ChunkPos((int)(nextPos.x / 16), (int)(nextPos.z / 16)), OptionManager.tntChunkLoadingRange, this)); 38 | } 39 | } 40 | } 41 | 42 | @Override 43 | public boolean handleAttack(Entity attacker) { 44 | if(OptionManager.attackableTnt) { 45 | this.remove(); 46 | if(attacker.isSneaking()) { 47 | this.world.getEntitiesByType(EntityType.TNT, this.getBoundingBox(), (e) -> true).forEach(Entity::remove); 48 | } 49 | 50 | return true; 51 | } else { 52 | return super.handleAttack(attacker); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/WorldChunkMixin_GetEntityExpansion.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.injection.Constant; 5 | import org.spongepowered.asm.mixin.injection.ModifyConstant; 6 | 7 | import lovexyn0827.mess.options.OptionManager; 8 | import net.minecraft.world.chunk.WorldChunk; 9 | 10 | @Mixin(value = WorldChunk.class, priority = 900) 11 | public class WorldChunkMixin_GetEntityExpansion { 12 | @ModifyConstant( 13 | method = { "collectOtherEntities", "collectEntities", "collectEntitiesByClass" }, 14 | constant = @Constant(doubleValue = 2.0) 15 | ) 16 | private double modifyGetEntityExpansion(double original) { 17 | return OptionManager.getEntityRangeExpansion; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/WorldListWidgetEntryAccessor.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.gen.Accessor; 5 | 6 | import net.minecraft.client.gui.screen.world.WorldListWidget; 7 | import net.minecraft.world.level.storage.LevelSummary; 8 | 9 | @Mixin(WorldListWidget.Entry.class) 10 | public interface WorldListWidgetEntryAccessor { 11 | @Accessor("level") 12 | LevelSummary getLevelSummary(); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/WorldListWidgetEntryMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import java.io.File; 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 | 12 | import it.unimi.dsi.fastutil.booleans.BooleanConsumer; 13 | import lovexyn0827.mess.util.FormattedText; 14 | import net.minecraft.client.MinecraftClient; 15 | import net.minecraft.client.gui.screen.ConfirmScreen; 16 | import net.minecraft.client.gui.screen.world.SelectWorldScreen; 17 | import net.minecraft.client.gui.screen.world.WorldListWidget; 18 | import net.minecraft.world.level.storage.LevelSummary; 19 | 20 | @Mixin(WorldListWidget.Entry.class) 21 | public abstract class WorldListWidgetEntryMixin { 22 | @Shadow 23 | private @Final MinecraftClient client; 24 | @Shadow 25 | private @Final LevelSummary level; 26 | @Shadow 27 | private @Final SelectWorldScreen screen; 28 | 29 | @Shadow 30 | protected abstract void method_29990(); 31 | 32 | @Inject(method = "start", at = @At(value = "INVOKE", target = "net/minecraft/client/gui/screen/world/WorldListWidget$Entry." 33 | + "method_29990()V"), cancellable = true) 34 | private void requireComfirmIfNeeded(CallbackInfo ci) { 35 | if(this.level.getGameMode().isSurvivalLike() 36 | && !new File(this.level.getFile().getParentFile(), "mcwmem.prop").exists()) { 37 | BooleanConsumer bc = (bool) -> { 38 | if(bool) { 39 | this.method_29990(); 40 | this.client.startIntegratedServer(this.level.getName()); 41 | } else { 42 | this.client.openScreen(this.screen); 43 | } 44 | }; 45 | this.client.openScreen(new ConfirmScreen(bc, new FormattedText("misc.warnsur.title", "cl").asMutableText(), 46 | new FormattedText("misc.warnsur.msg", "f").asMutableText())); 47 | ci.cancel(); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/WorldListWidgetMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 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 | import lovexyn0827.mess.options.OptionManager; 7 | import net.minecraft.client.MinecraftClient; 8 | import net.minecraft.client.gui.screen.world.WorldListWidget; 9 | import net.minecraft.client.gui.widget.EntryListWidget; 10 | import net.minecraft.world.level.storage.LevelSummary; 11 | 12 | @SuppressWarnings("rawtypes") 13 | @Mixin(WorldListWidget.class) 14 | public class WorldListWidgetMixin extends EntryListWidget { 15 | public WorldListWidgetMixin(MinecraftClient client, int width, int height, int top, int bottom, int itemHeight) { 16 | super(client, itemHeight, itemHeight, itemHeight, itemHeight, itemHeight); 17 | } 18 | 19 | @SuppressWarnings("unchecked") 20 | @Redirect(method = "filter", 21 | at = @At(value = "INVOKE", 22 | target = "Lnet/minecraft/client/gui/screen/world/WorldListWidget;addEntry(Lnet/minecraft/client/gui/widget/EntryListWidget$Entry;)I" 23 | ) 24 | ) 25 | private int hideSuvivalSaves(WorldListWidget list, EntryListWidget.Entry entry) { 26 | LevelSummary summary = ((WorldListWidgetEntryAccessor) entry).getLevelSummary(); 27 | if(!OptionManager.hideSurvivalSaves || (summary.hasCheats() && !summary.getGameMode().isSurvivalLike())) { 28 | return this.addEntry(entry); 29 | } 30 | 31 | return 0; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/WorldMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import net.minecraft.world.World; 5 | 6 | @Mixin(World.class) 7 | public class WorldMixin { 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/WorldMixin_GetEntityExpansion.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.injection.Constant; 5 | import org.spongepowered.asm.mixin.injection.ModifyConstant; 6 | 7 | import lovexyn0827.mess.options.OptionManager; 8 | import net.minecraft.world.World; 9 | 10 | @Mixin(value = World.class, priority = 900) 11 | public class WorldMixin_GetEntityExpansion { 12 | @ModifyConstant( 13 | method = { "getOtherEntities", "getEntitiesByType", "getEntitiesByClass", 14 | "getEntitiesIncludingUngeneratedChunks" }, 15 | constant = @Constant(doubleValue = 2.0) 16 | ) 17 | private double modifyGetEntityExpansion(double original) { 18 | return OptionManager.getEntityRangeExpansion; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/WorldRendererMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import com.mojang.blaze3d.systems.RenderSystem; 4 | 5 | import lovexyn0827.mess.MessMod; 6 | import net.minecraft.client.render.Camera; 7 | import net.minecraft.client.render.GameRenderer; 8 | import net.minecraft.client.render.LightmapTextureManager; 9 | import net.minecraft.client.render.WorldRenderer; 10 | import net.minecraft.client.util.math.MatrixStack; 11 | import net.minecraft.util.math.Matrix4f; 12 | import org.spongepowered.asm.mixin.Mixin; 13 | import org.spongepowered.asm.mixin.injection.At; 14 | import org.spongepowered.asm.mixin.injection.Inject; 15 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 16 | 17 | @Mixin(WorldRenderer.class) 18 | public class WorldRendererMixin { 19 | @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/debug/DebugRenderer;render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider$Immediate;DDD)V")) 20 | private void renderShapes(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, CallbackInfo ci) { 21 | if (MessMod.INSTANCE.shapeRenderer != null) { 22 | RenderSystem.pushMatrix(); 23 | MessMod.INSTANCE.shapeRenderer.render(camera, tickDelta); 24 | RenderSystem.popMatrix(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/mixins/WorldSavePathMixin.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.mixins; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.gen.Invoker; 5 | 6 | import net.minecraft.util.WorldSavePath; 7 | 8 | @Mixin(WorldSavePath.class) 9 | public interface WorldSavePathMixin { 10 | @Invoker(value = "") 11 | public static WorldSavePath create(String str) { 12 | throw new AssertionError(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/network/Channels.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.network; 2 | 3 | import net.minecraft.util.Identifier; 4 | 5 | public interface Channels { 6 | public static int CHANNEL_VERSION = 9; // TODO Remember to update the channel version if necessary 7 | Identifier SHAPE = new Identifier("messmod", "shape"); 8 | Identifier HUD = new Identifier("messmod", "hud"); 9 | Identifier VERSION = new Identifier("messmod", "version"); 10 | Identifier UNDO = new Identifier("messmod", "undo"); 11 | Identifier REDO = new Identifier("messmod", "redo"); 12 | Identifier OPTIONS = new Identifier("messmod", "options"); 13 | Identifier OPTION_SINGLE = new Identifier("messmod", "option_single"); 14 | Identifier ENTITY_DUMP = new Identifier("messmod", "entity_dump"); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/options/BooleanParser.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.options; 2 | 3 | import java.util.Set; 4 | 5 | import com.google.common.collect.Sets; 6 | 7 | public class BooleanParser implements OptionParser { 8 | 9 | @Override 10 | public Boolean tryParse(String str) throws InvalidOptionException { 11 | if("true".equals(str)) { 12 | return true; 13 | } else if ("false".equals(str)) { 14 | return false; 15 | } else { 16 | throw new InvalidOptionException("opt.err.reqbool"); 17 | } 18 | } 19 | 20 | @Override 21 | public String serialize(Boolean val) { 22 | return val ? "true" : "false"; 23 | } 24 | 25 | @Override 26 | public Set createSuggestions() { 27 | return Sets.newHashSet("true", "false"); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/options/EnumParser.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.options; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | import java.util.stream.Stream; 6 | 7 | public class EnumParser> implements OptionParser> { 8 | 9 | private Class clazz; 10 | 11 | protected EnumParser(Class clazz) { 12 | this.clazz = clazz; 13 | } 14 | 15 | @Override 16 | public String serialize(Enum val) { 17 | return val.name(); 18 | } 19 | 20 | @Override 21 | public Enum tryParse(String str) throws InvalidOptionException { 22 | try { 23 | return Enum.valueOf(clazz, str); 24 | } catch(IllegalArgumentException e) { 25 | InvalidOptionException e1 = new InvalidOptionException("opt.err.nodef", str); 26 | e1.initCause(e); 27 | throw e1; 28 | } 29 | } 30 | 31 | @Override 32 | public Set createSuggestions() { 33 | return Stream.of(this.clazz.getEnumConstants()) 34 | .map(Enum::name) 35 | .collect(HashSet::new, Set::add, Set::addAll); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/options/FloatParser.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.options; 2 | 3 | public class FloatParser implements OptionParser { 4 | 5 | @Override 6 | public Float tryParse(String str) throws InvalidOptionException { 7 | try { 8 | return Float.valueOf(str); 9 | } catch (NumberFormatException e) { 10 | throw new InvalidOptionException("opt.err.rnum"); 11 | } 12 | } 13 | 14 | @Override 15 | public String serialize(Float val) { 16 | return Float.toString(val); 17 | } 18 | 19 | public static class Positive extends FloatParser { 20 | @Override 21 | public Float tryParse(String str) throws InvalidOptionException { 22 | Float f = super.tryParse(str); 23 | if(f > 0) { 24 | return f; 25 | } else { 26 | throw new InvalidOptionException("opt.err.rpositive"); 27 | } 28 | } 29 | } 30 | 31 | public static class NonNegative extends FloatParser { 32 | @Override 33 | public Float tryParse(String str) throws InvalidOptionException { 34 | Float f = super.tryParse(str); 35 | if(f >= 0) { 36 | return f; 37 | } else { 38 | throw new InvalidOptionException("opt.err.rnonnegative"); 39 | } 40 | } 41 | } 42 | 43 | 44 | public static class NaNablePositive extends Positive { 45 | @Override 46 | public Float tryParse(String str) throws InvalidOptionException { 47 | if("NaN".equals(str)) { 48 | return Float.NaN; 49 | } else { 50 | return super.tryParse(str); 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/options/IntegerParser.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.options; 2 | 3 | public class IntegerParser implements OptionParser { 4 | @Override 5 | public Integer tryParse(String str) throws InvalidOptionException { 6 | try { 7 | return Integer.valueOf(str); 8 | } catch (NumberFormatException e) { 9 | throw new InvalidOptionException("opt.err.rint"); 10 | } 11 | } 12 | 13 | @Override 14 | public String serialize(Integer val) { 15 | return Integer.toString(val); 16 | } 17 | 18 | public static class Positive extends IntegerParser { 19 | @Override 20 | public Integer tryParse(String str) throws InvalidOptionException { 21 | Integer i = super.tryParse(str); 22 | if(i > 0) { 23 | return i; 24 | } else { 25 | throw new InvalidOptionException("opt.err.rpositive"); 26 | } 27 | } 28 | } 29 | 30 | public static class NonNegative extends IntegerParser { 31 | @Override 32 | public Integer tryParse(String str) throws InvalidOptionException { 33 | Integer i = super.tryParse(str); 34 | if(i >= 0) { 35 | return i; 36 | } else { 37 | throw new InvalidOptionException("opt.err.rnonnegative"); 38 | } 39 | } 40 | } 41 | 42 | public static class HotbarLength extends IntegerParser { 43 | @Override 44 | public Integer tryParse(String str) throws InvalidOptionException { 45 | Integer i = super.tryParse(str); 46 | if(i > 0 && i <= 36) { 47 | return i; 48 | } else { 49 | throw new InvalidOptionException("opt.err.rhotbar"); 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/options/InvalidOptionException.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.options; 2 | 3 | import lovexyn0827.mess.util.i18n.I18N; 4 | 5 | // Couldn't extend TranslatableException because it shouldn't be a RuntimeException 6 | public class InvalidOptionException extends Exception { 7 | private Object[] args; 8 | 9 | public InvalidOptionException(String string, Object ... args) { 10 | super(string); 11 | this.args = args; 12 | } 13 | 14 | public String getMessageWithoutArgs() { 15 | if(this.args != null && this.args.length != 0) { 16 | throw new IllegalStateException("Some args are given, use getMessage() instead!"); 17 | } 18 | 19 | return I18N.translate(super.getMessage()); 20 | } 21 | 22 | @Override 23 | public String getMessage() { 24 | return String.format(I18N.translate(super.getMessage()), args); 25 | } 26 | 27 | private static final long serialVersionUID = 1L; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/options/Label.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.options; 2 | 3 | public enum Label { 4 | MESSMOD, 5 | ENTITY, 6 | RENDERER, 7 | INTERACTION_TWEAKS, 8 | EXPLOSION, 9 | RESEARCH, 10 | REDSTONE, 11 | CHUNK, 12 | BUGFIX, 13 | BREAKING_OPTIMIZATION, 14 | MISC 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/options/Option.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.options; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | import net.fabricmc.api.EnvType; 9 | 10 | @Retention(RetentionPolicy.RUNTIME) 11 | @Target(ElementType.FIELD) 12 | @interface Option { 13 | String defaultValue(); 14 | String[] suggestions() default {}; 15 | 16 | /** 17 | * @return true if this option is currently unfinished or buggy. 18 | */ 19 | boolean experimental() default false; 20 | Class> parserClass(); 21 | boolean globalOnly() default false; 22 | EnvType[] environment() default {EnvType.CLIENT, EnvType.SERVER}; 23 | Label[] label(); 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/options/OptionParser.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.options; 2 | 3 | import java.util.Collections; 4 | import java.util.Set; 5 | 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | /** 10 | * @author lovexyn0827 11 | * Date: April 2, 2022 12 | * @param The type of the option. 13 | */ 14 | public interface OptionParser { 15 | /** 16 | * Translate a string representation of a value of an option to its runtime representation. 17 | * @return The runtime representation of {@code str} 18 | * @throws InvalidOptionException If the given string representation is not qualified. 19 | */ 20 | T tryParse(String str) throws InvalidOptionException; 21 | 22 | /** 23 | * Translate a runtime representation of a value of an option to its string representation. 24 | * @return The runtime representation of {@code val} 25 | */ 26 | String serialize(T val); 27 | 28 | @SuppressWarnings("unchecked") 29 | default String serializeObj(Object val) { 30 | return serialize((T) val); 31 | } 32 | 33 | @NotNull 34 | default Set createSuggestions() { 35 | return Collections.emptySet(); 36 | } 37 | 38 | default void validate(String in) throws InvalidOptionException { 39 | this.tryParse(in); 40 | } 41 | 42 | static OptionParser of(Option o) { 43 | try { 44 | return o.parserClass().getConstructor().newInstance(); 45 | } catch (Exception e) { 46 | e.printStackTrace(); 47 | throw new RuntimeException(e); 48 | } 49 | } 50 | 51 | @Nullable 52 | static OptionParser of(String optionName) { 53 | OptionWrapper o = OptionManager.OPTIONS.get(optionName); 54 | if(o != null) { 55 | return of(o.option); 56 | } else { 57 | return null; 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/options/OptionWrapper.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.options; 2 | 3 | import java.lang.reflect.Field; 4 | 5 | import org.jetbrains.annotations.Nullable; 6 | 7 | import com.mojang.brigadier.context.CommandContext; 8 | import com.mojang.brigadier.suggestion.SuggestionProvider; 9 | 10 | import lovexyn0827.mess.options.OptionManager.CustomOptionApplicator; 11 | import lovexyn0827.mess.util.i18n.I18N; 12 | import net.fabricmc.api.EnvType; 13 | import net.fabricmc.loader.api.FabricLoader; 14 | import net.minecraft.server.command.ServerCommandSource; 15 | 16 | public final class OptionWrapper { 17 | final Field field; 18 | final String name; 19 | final OptionParser parser; 20 | final Option option; 21 | 22 | OptionWrapper(Field f) { 23 | this.field = f; 24 | this.name = f.getName(); 25 | this.option = f.getAnnotation(Option.class); 26 | this.parser = OptionParser.of(this.option); 27 | } 28 | 29 | public Object get() { 30 | try { 31 | return this.field.get(null); 32 | } catch (IllegalArgumentException | IllegalAccessException e) { 33 | throw new RuntimeException(e); 34 | } 35 | } 36 | 37 | public void set(Object o, @Nullable CommandContext ct) { 38 | try { 39 | this.field.set(null, o); 40 | CustomOptionApplicator action = OptionManager.CUSTOM_APPLICATION_BEHAVIORS.get(name); 41 | if(action != null) { 42 | action.onOptionUpdate(o, ct); 43 | } 44 | } catch (IllegalArgumentException | IllegalAccessException e) { 45 | throw new RuntimeException(e); 46 | } 47 | } 48 | 49 | public String getDescription() { 50 | return I18N.translate("opt." + this.name + ".desc"); 51 | } 52 | 53 | public boolean isSupportedInCurrentEnv() { 54 | EnvType currentEnv = FabricLoader.getInstance().getEnvironmentType(); 55 | for(EnvType env : this.option.environment()) { 56 | if(env == currentEnv) { 57 | return true; 58 | } 59 | } 60 | 61 | return false; 62 | } 63 | 64 | public String getDefaultValue() { 65 | return this.option.defaultValue(); 66 | } 67 | 68 | public SuggestionProvider getSuggestions() { 69 | return (ct, b) -> { 70 | this.parser.createSuggestions().forEach(b::suggest); 71 | for(String s : this.option.suggestions()) { 72 | b.suggest(s); 73 | } 74 | 75 | b.suggest(this.getDefaultValue()); 76 | return b.buildFuture(); 77 | }; 78 | } 79 | 80 | public boolean isExperimental() { 81 | return this.option.experimental(); 82 | } 83 | 84 | public boolean globalOnly() { 85 | return this.option.globalOnly(); 86 | } 87 | 88 | public Label[] labels() { 89 | return this.option.label(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/options/StringParser.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.options; 2 | 3 | public class StringParser implements OptionParser { 4 | 5 | @Override 6 | public String tryParse(String str) throws InvalidOptionException { 7 | return str; 8 | } 9 | 10 | @Override 11 | public String serialize(String val) { 12 | return val; 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/rendering/FrozenUpdateMode.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.rendering; 2 | 3 | import lovexyn0827.mess.options.EnumParser; 4 | 5 | public enum FrozenUpdateMode { 6 | /** 7 | * Add the stuff normally, and remove them normally in the next server side tick. 8 | */ 9 | NORMALLY, 10 | /** 11 | * Everything remains the same as the first frozen tick. 12 | */ 13 | PAUSE, 14 | /** 15 | * The addition works normally, but the removal pauses. 16 | */ 17 | NO_REMOVAL; 18 | 19 | public static class Parser extends EnumParser { 20 | public Parser() { 21 | super(FrozenUpdateMode.class); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/rendering/LocalShapeStorage.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.rendering; 2 | 3 | import java.util.Set; 4 | import java.util.UUID; 5 | 6 | import com.google.common.collect.Sets; 7 | import com.mojang.util.UUIDTypeAdapter; 8 | 9 | import net.fabricmc.api.EnvType; 10 | import net.fabricmc.api.Environment; 11 | import net.minecraft.client.MinecraftClient; 12 | import net.minecraft.server.network.ServerPlayerEntity; 13 | import net.minecraft.util.registry.RegistryKey; 14 | import net.minecraft.world.World; 15 | 16 | /** 17 | * Stores shapes in single player games. 18 | */ 19 | @Environment(EnvType.CLIENT) 20 | public class LocalShapeStorage extends ShapeCache implements ShapeSender { 21 | private final UUID localPlayerUuid; 22 | 23 | LocalShapeStorage() { 24 | this.localPlayerUuid = UUIDTypeAdapter.fromString(MinecraftClient.getInstance().getSession().getUuid()); 25 | } 26 | 27 | @Override 28 | public synchronized void addShape(Shape shape, RegistryKey dim, ShapeSpace space, 29 | ServerPlayerEntity player) { 30 | if(player == null || this.localPlayerUuid.equals(player.getUuid())) { 31 | Set set = this.getShapesInDimension(dim) 32 | .computeIfAbsent(space, (ss) -> Sets.newHashSet()); 33 | set.add(shape); 34 | } 35 | } 36 | 37 | @Override 38 | public synchronized void clearSpaceFromServer(ShapeSpace space, ServerPlayerEntity player) { 39 | if(player == null || this.localPlayerUuid.equals(player.getUuid())) { 40 | this.clearSpace(space); 41 | } 42 | } 43 | 44 | @Override 45 | public void updateClientTime(long gt) { 46 | this.time = gt; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/rendering/RemoteShapeSender.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.rendering; 2 | 3 | import io.netty.buffer.Unpooled; 4 | import lovexyn0827.mess.network.Channels; 5 | import net.minecraft.nbt.CompoundTag; 6 | import net.minecraft.network.PacketByteBuf; 7 | import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; 8 | import net.minecraft.server.MinecraftServer; 9 | import net.minecraft.server.network.ServerPlayerEntity; 10 | import net.minecraft.util.registry.RegistryKey; 11 | import net.minecraft.world.World; 12 | 13 | public class RemoteShapeSender implements ShapeSender { 14 | private final MinecraftServer server; 15 | 16 | 17 | public RemoteShapeSender(MinecraftServer server) { 18 | this.server = server; 19 | } 20 | 21 | @Override 22 | // Mode - Dimension - Space - Tag 23 | public void addShape(Shape shape, RegistryKey dim, ShapeSpace space, ServerPlayerEntity player) { 24 | PacketByteBuf buffer = new PacketByteBuf(Unpooled.buffer()); 25 | buffer.writeEnumConstant(UpdateMode.ADD_SHAPE); 26 | buffer.writeIdentifier(dim.getValue()); 27 | buffer.writeString(space.name); 28 | CompoundTag tag = new CompoundTag(); 29 | buffer.writeCompoundTag(shape.toTag(tag)); 30 | CustomPayloadS2CPacket packet = new CustomPayloadS2CPacket(Channels.SHAPE, buffer); 31 | if(player == null) { 32 | this.server.getPlayerManager().sendToDimension(packet, dim); 33 | } else { 34 | if(player.networkHandler != null) { 35 | player.networkHandler.sendPacket(packet); 36 | } 37 | } 38 | } 39 | 40 | @Override 41 | public void clearSpaceFromServer(ShapeSpace space, ServerPlayerEntity player) { 42 | PacketByteBuf buffer = new PacketByteBuf(Unpooled.buffer()); 43 | buffer.writeEnumConstant(UpdateMode.CLEAR_SPACE); 44 | buffer.writeString(space.name); 45 | CustomPayloadS2CPacket packet = new CustomPayloadS2CPacket(Channels.SHAPE, buffer); 46 | this.server.getPlayerManager().sendToAll(packet); 47 | } 48 | 49 | @Override 50 | public void updateClientTime(long gt) { 51 | PacketByteBuf buffer = new PacketByteBuf(Unpooled.buffer()); 52 | buffer.writeEnumConstant(UpdateMode.TICK); 53 | buffer.writeLong(gt); 54 | CustomPayloadS2CPacket packet = new CustomPayloadS2CPacket(Channels.SHAPE, buffer); 55 | this.server.getPlayerManager().sendToAll(packet); 56 | } 57 | 58 | public static enum UpdateMode { 59 | ADD_SHAPE, CLEAR_SPACE, TICK; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/rendering/RenderedLine.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.rendering; 2 | 3 | import com.mojang.blaze3d.systems.RenderSystem; 4 | 5 | import net.fabricmc.api.EnvType; 6 | import net.fabricmc.api.Environment; 7 | import net.minecraft.client.render.BufferBuilder; 8 | import net.minecraft.client.render.Tessellator; 9 | import net.minecraft.nbt.CompoundTag; 10 | import net.minecraft.util.math.Vec3d; 11 | import net.minecraft.util.registry.RegistryKey; 12 | import net.minecraft.world.World; 13 | 14 | /** 15 | * Copied From The Fabric-Carpet 16 | */ 17 | public class RenderedLine extends Shape { 18 | 19 | private final Vec3d from; 20 | private final Vec3d to; 21 | 22 | public RenderedLine(Vec3d b, Vec3d a, int color, int life, long gt) { 23 | super(color, 0, life, gt); 24 | this.from = a; 25 | this.to = b; 26 | } 27 | 28 | @Override 29 | @Environment(EnvType.CLIENT) 30 | protected void renderFaces(Tessellator tessellator, BufferBuilder bufferBuilder, double cx, double cy, 31 | double cz, float partialTick) { 32 | } 33 | 34 | @Override 35 | @Environment(EnvType.CLIENT) 36 | protected void renderLines(Tessellator tessellator, BufferBuilder bufferBuilder, double cx, double cy, 37 | double cz, float partialTick) { 38 | RenderSystem.lineWidth(2); 39 | ShapeRenderer.drawLine(tessellator, bufferBuilder, 40 | (float)(from.x-cx-renderEpsilon), (float)(from.y-cy-renderEpsilon), (float)(from.z-cz-renderEpsilon), 41 | (float)(to.x-cx+renderEpsilon), (float)(to.y-cy+renderEpsilon), (float)(to.z-cz+renderEpsilon), 42 | this.r, this.g, this.b, this.a 43 | ); 44 | } 45 | 46 | @Override 47 | protected boolean shouldRender(RegistryKey dimensionType) { 48 | return true; 49 | } 50 | 51 | @Override 52 | protected CompoundTag toTag(CompoundTag tag) { 53 | CompoundTag basic = super.toTag(tag); 54 | basic.putDouble("X0", this.from.x); 55 | basic.putDouble("Y0", this.from.y); 56 | basic.putDouble("Z0", this.from.z); 57 | basic.putDouble("X1", this.to.x); 58 | basic.putDouble("Y1", this.to.y); 59 | basic.putDouble("Z1", this.to.z); 60 | return basic; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/rendering/ServerSyncedBoxRenderer.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.rendering; 2 | 3 | import java.util.List; 4 | 5 | import lovexyn0827.mess.MessMod; 6 | import lovexyn0827.mess.fakes.ServerWorldInterface; 7 | import lovexyn0827.mess.options.OptionManager; 8 | import lovexyn0827.mess.util.CarpetUtil; 9 | import net.minecraft.entity.Entity; 10 | import net.minecraft.server.MinecraftServer; 11 | import net.minecraft.server.network.ServerPlayerEntity; 12 | import net.minecraft.server.world.ServerWorld; 13 | import net.minecraft.util.math.Box; 14 | import net.minecraft.util.math.Vec3d; 15 | 16 | public class ServerSyncedBoxRenderer { 17 | private static final ShapeSpace ENTITY_BOX_SPACE = new ShapeSpace("entity_box"); 18 | private final MinecraftServer server; 19 | 20 | public ServerSyncedBoxRenderer(MinecraftServer server) { 21 | this.server = server; 22 | } 23 | 24 | private void addBoxes(ServerPlayerEntity player, boolean frozen, FrozenUpdateMode mode) { 25 | ShapeSender sr = MessMod.INSTANCE.shapeSender; 26 | float r = OptionManager.serverSyncedBoxRenderRange; 27 | ServerWorld world = player.getServerWorld(); 28 | if(!(frozen && mode == FrozenUpdateMode.NO_REMOVAL)) { 29 | MessMod.INSTANCE.shapeSender.clearSpaceFromServer(ENTITY_BOX_SPACE, player); 30 | } 31 | 32 | List list; 33 | if(r > 0) { 34 | Vec3d pos = player.getPos(); 35 | if (OptionManager.directChunkAccessForMessMod) { 36 | list = ((ServerWorldInterface) world).toNoChunkLoadingWorld() 37 | .getEntitiesByClass(Entity.class, new Box(pos, pos).expand(r), (e) -> true); 38 | } else { 39 | list = world.getEntitiesByClass(Entity.class, new Box(pos, pos).expand(r), (e) -> true); 40 | } 41 | } else { 42 | list = world.getEntitiesByType(null, (e) -> true); 43 | } 44 | 45 | for(Entity entity : list) { 46 | if(entity instanceof ServerPlayerEntity) continue; 47 | sr.addShape(new RenderedBox(entity.getBoundingBox(), 0x31f38bFF, 0, 0, world.getTime()), 48 | world.getRegistryKey(), ENTITY_BOX_SPACE, player); 49 | } 50 | } 51 | 52 | public void tick() { 53 | if(this.server == null || !OptionManager.serverSyncedBox) { 54 | return; 55 | } 56 | 57 | boolean frozen = CarpetUtil.isTickFrozen(); 58 | FrozenUpdateMode mode = OptionManager.serverSyncedBoxUpdateModeInFrozenTicks; 59 | if(frozen && mode == FrozenUpdateMode.PAUSE) { 60 | return; 61 | } 62 | 63 | for(ServerPlayerEntity player : server.getPlayerManager().getPlayerList()) { 64 | if(player.getServerWorld() != null) { 65 | this.addBoxes(player, frozen, mode); 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/rendering/ShapeCache.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.rendering; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.Set; 6 | 7 | import com.google.common.collect.Maps; 8 | import com.google.common.collect.Sets; 9 | 10 | import lovexyn0827.mess.MessMod; 11 | import net.minecraft.client.MinecraftClient; 12 | import net.minecraft.util.registry.RegistryKey; 13 | import net.minecraft.world.World; 14 | 15 | public abstract class ShapeCache { 16 | protected final Map, Map>> backend = Maps.newHashMap(); 17 | protected long time; 18 | 19 | ShapeCache() { 20 | this.backend.put(World.OVERWORLD, new HashMap<>()); 21 | this.backend.put(World.NETHER, new HashMap<>()); 22 | this.backend.put(World.END, new HashMap<>()); 23 | // TODO Custom Dimensions 24 | } 25 | 26 | public final synchronized Map, Map>> getAllShapes() { 27 | return this.backend; 28 | } 29 | 30 | public final synchronized Map> getShapesInDimension(RegistryKey dimensionType) { 31 | return this.backend.get(dimensionType); 32 | } 33 | 34 | public final synchronized void reset() { 35 | this.backend.values().forEach(Map::clear); 36 | } 37 | 38 | public final synchronized void clearSpace(ShapeSpace ss) { 39 | this.backend.values().forEach((map) -> map.computeIfAbsent(ss, (ss1) -> Sets.newConcurrentHashSet()).clear()); 40 | } 41 | 42 | public static ShapeCache create(MinecraftClient mc) { 43 | return MessMod.isDedicatedEnv() ? new RemoteShapeCache() : (ShapeCache) MessMod.INSTANCE.shapeSender; 44 | } 45 | 46 | public final long getTime() { 47 | return this.time; 48 | } 49 | 50 | public void close() { 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/rendering/ShapeSender.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.rendering; 2 | 3 | import lovexyn0827.mess.MessMod; 4 | import net.minecraft.server.MinecraftServer; 5 | import net.minecraft.server.network.ServerPlayerEntity; 6 | import net.minecraft.util.registry.RegistryKey; 7 | import net.minecraft.world.World; 8 | 9 | public interface ShapeSender { 10 | void addShape(Shape shape, RegistryKey dim, ShapeSpace space, ServerPlayerEntity player); 11 | void updateClientTime(long gt); 12 | default void addShape(Shape shape, RegistryKey dim, ServerPlayerEntity player) { 13 | this.addShape(shape, dim, ShapeSpace.DEFAULT, player); 14 | } 15 | 16 | void clearSpaceFromServer(ShapeSpace space, ServerPlayerEntity e); 17 | 18 | static ShapeSender create(MinecraftServer server) { 19 | return MessMod.isDedicatedEnv() ? new RemoteShapeSender(server) : new LocalShapeStorage(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/rendering/ShapeSpace.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.rendering; 2 | 3 | public final class ShapeSpace { 4 | /** 5 | * Default space, which can only be managed by the ShapeRenderer class automatically. 6 | */ 7 | public static final ShapeSpace DEFAULT = new ShapeSpace("default"); 8 | public final String name; 9 | 10 | public ShapeSpace(String name) { 11 | this.name = name; 12 | } 13 | 14 | @Override 15 | public int hashCode() { 16 | return name.hashCode(); 17 | } 18 | 19 | @Override 20 | public boolean equals(Object obj) { 21 | if (obj == null) { 22 | return false; 23 | } else { 24 | if(obj.getClass() == ShapeSpace.class) { 25 | ShapeSpace other = (ShapeSpace) obj; 26 | return this.name.equals(other.name); 27 | } else { 28 | return false; 29 | } 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/rendering/hud/AlignMode.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.rendering.hud; 2 | 3 | import lovexyn0827.mess.options.EnumParser; 4 | 5 | public enum AlignMode { 6 | TOP_LEFT, 7 | TOP_RIGHT, 8 | BOTTIM_LEFT, 9 | BOTTOM_RIGHT; 10 | 11 | public static class Parser extends EnumParser { 12 | public Parser() { 13 | super(AlignMode.class); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/rendering/hud/ClientHudManager.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.rendering.hud; 2 | 3 | import lovexyn0827.mess.options.OptionManager; 4 | import lovexyn0827.mess.rendering.hud.data.HudDataStorage; 5 | import net.minecraft.client.MinecraftClient; 6 | import net.minecraft.client.network.ClientPlayerEntity; 7 | import net.minecraft.server.integrated.IntegratedServer; 8 | 9 | public class ClientHudManager implements HudManager { 10 | public final LookingAtEntityHud lookingHud; 11 | public final PlayerHud playerHudC; 12 | public int hudHeight; 13 | public PlayerHud playerHudS; 14 | public EntitySideBar sidebar; 15 | // Whether or not headers of lines are rendered red 16 | boolean headerSpeciallyColored; 17 | boolean looserLines; 18 | boolean renderBackGround; 19 | 20 | @SuppressWarnings("resource") 21 | public ClientHudManager() { 22 | this.hudHeight = 0; 23 | this.lookingHud = new LookingAtEntityHud(this); 24 | ClientPlayerEntity player = MinecraftClient.getInstance().player; 25 | this.playerHudC = new PlayerHud(this, player, false); 26 | this.sidebar = new EntitySideBar(this); 27 | this.updateStyle(OptionManager.hudStyles); 28 | } 29 | 30 | public void render(ClientPlayerEntity player, IntegratedServer server) { 31 | this.hudHeight = 0; 32 | if(this.lookingHud.shouldRender) { 33 | this.lookingHud.render(); 34 | } 35 | 36 | if(player != null && this.playerHudC.shouldRender) { 37 | this.playerHudC.render(); 38 | } 39 | 40 | if(player != null && this.playerHudS != null && this.playerHudS.shouldRender) { 41 | this.playerHudS.render(); 42 | } 43 | 44 | if(player != null && this.sidebar != null && this.sidebar.shouldRender) { 45 | this.sidebar.render(); 46 | } 47 | } 48 | 49 | public void updateStyle(String code) { 50 | this.headerSpeciallyColored = code.contains("R"); 51 | this.looserLines = code.contains("L"); 52 | this.renderBackGround = code.contains("B"); 53 | } 54 | 55 | public HudDataStorage getData(HudType type) { 56 | EntityHud hud; 57 | switch(type) { 58 | case TARGET : 59 | hud = this.lookingHud; 60 | break; 61 | case CLIENT_PLAYER : 62 | hud = this.playerHudC; 63 | break; 64 | case SERVER_PLAYER : 65 | hud = this.playerHudS; 66 | break; 67 | case SIDEBAR : 68 | hud = this.sidebar; 69 | break; 70 | default : 71 | throw new IllegalArgumentException(); 72 | } 73 | 74 | return hud != null ? hud.getData() : null; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/rendering/hud/EntityHudUtil.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.rendering.hud; 2 | 3 | import net.minecraft.entity.Entity; 4 | import net.minecraft.entity.LivingEntity; 5 | 6 | public class EntityHudUtil { 7 | public static String getLivingFlags(LivingEntity living) { 8 | String result = "|"; 9 | if(living.hurtTime==living.maxHurtTime-1) result += "Hurt|"; 10 | if(living.isFallFlying()) result += "Fly|"; 11 | if(living.isSleeping()) result += "Slp|"; 12 | if(living.isDead()) result += "Dead|"; 13 | return result; 14 | } 15 | 16 | public static String getGeneralFlags(Entity entity) { 17 | String result = "|"; 18 | if(entity.isGlowing()) result += "Gl|"; 19 | if(entity.isInvulnerable()) result += "Inv|"; 20 | if(entity.isCollidable()) result += "Col"; 21 | if(entity.hasNoGravity()) result += "NG|"; 22 | if(entity.horizontalCollision) result += "HC|"; 23 | if(entity.verticalCollision) result += "VC|"; 24 | if(entity.isWet()) result += "Wet|"; 25 | if(entity.isSubmergedInWater()) result += "Sbm|"; 26 | if(entity.isSprinting()) result += "Sp|"; 27 | if(entity.isSneaking()) result += "Sn|"; 28 | if(entity.isDescending()) result += "De|"; 29 | if(entity.isSwimming()) result += "Sw|"; 30 | if(entity.isOnGround()) result += "Og|"; 31 | return result; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/rendering/hud/EntitySideBar.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.rendering.hud; 2 | 3 | import lovexyn0827.mess.MessMod; 4 | import lovexyn0827.mess.rendering.hud.data.HudDataStorage; 5 | import lovexyn0827.mess.rendering.hud.data.RemoteHudDataStorage; 6 | import net.minecraft.client.util.math.MatrixStack; 7 | 8 | public class EntitySideBar extends EntityHud { 9 | public EntitySideBar(ClientHudManager clientHudManager) { 10 | super(clientHudManager, HudType.SIDEBAR); 11 | this.shouldRender = true; 12 | } 13 | 14 | public void render() { 15 | if(this.getData().size() > 0) { 16 | this.render(new MatrixStack(), "Entity Sidebar"); 17 | } 18 | } 19 | 20 | @Override 21 | protected HudDataStorage createDataStorage(HudType type) { 22 | if(type != HudType.SIDEBAR) { 23 | throw new IllegalArgumentException(); 24 | } 25 | 26 | if (MessMod.isDedicatedEnv()) { 27 | return new RemoteHudDataStorage(); 28 | } else { 29 | return (HudDataStorage) MessMod.INSTANCE.getServerHudManager().sidebar; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/rendering/hud/HudManager.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.rendering.hud; 2 | 3 | public interface HudManager { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/rendering/hud/HudType.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.rendering.hud; 2 | 3 | public enum HudType { 4 | TARGET, 5 | SERVER_PLAYER, 6 | CLIENT_PLAYER, 7 | SIDEBAR; 8 | 9 | public boolean isPlayer() { 10 | return this == SERVER_PLAYER || this == CLIENT_PLAYER; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/rendering/hud/HudUtil.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.rendering.hud; 2 | 3 | import lovexyn0827.mess.options.OptionManager; 4 | 5 | public class HudUtil { 6 | public static boolean isLeftAligned() { 7 | return OptionManager.hudAlignMode.name().contains("LEFT"); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/rendering/hud/LookingAtEntityHud.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.rendering.hud; 2 | 3 | import lovexyn0827.mess.rendering.hud.data.BuiltinHudInfo; 4 | import net.minecraft.client.util.math.MatrixStack; 5 | 6 | public class LookingAtEntityHud extends EntityHud { 7 | public LookingAtEntityHud(ClientHudManager clientHudManager) { 8 | super(clientHudManager, HudType.TARGET); 9 | } 10 | 11 | public void render() { 12 | String entityInfo; 13 | if(this.getData().get(BuiltinHudInfo.ID) != null) { 14 | entityInfo = "("+getData().get(BuiltinHudInfo.ID) + "," + 15 | getData().get(BuiltinHudInfo.NAME) + "," + 16 | getData().get(BuiltinHudInfo.AGE) + ")"; 17 | } else { 18 | entityInfo = "[Null]"; 19 | } 20 | 21 | String describe = "Target" + entityInfo; 22 | if(this.shouldRender) this.render(new MatrixStack(), describe); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/rendering/hud/PlayerHud.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.rendering.hud; 2 | 3 | import net.minecraft.client.util.math.MatrixStack; 4 | import net.minecraft.entity.player.PlayerEntity; 5 | 6 | public class PlayerHud extends EntityHud{ 7 | private PlayerEntity player; 8 | private final boolean isServer; 9 | 10 | public PlayerHud(ClientHudManager clientHudManager, PlayerEntity player, boolean isServer) { 11 | super(clientHudManager, isServer ? HudType.SERVER_PLAYER : HudType.CLIENT_PLAYER); 12 | this.player = player; 13 | this.isServer = isServer; 14 | } 15 | 16 | public void render() { 17 | this.render(new MatrixStack(), (this.isServer ? "Server" : "Client") + "Player(" + this.player.getEntityId() + ")"); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/rendering/hud/ServerHudManager.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.rendering.hud; 2 | 3 | import java.util.List; 4 | 5 | import com.mojang.authlib.GameProfile; 6 | 7 | import lovexyn0827.mess.rendering.hud.data.HudDataSender; 8 | import lovexyn0827.mess.rendering.hud.data.SidebarDataSender; 9 | import lovexyn0827.mess.util.RaycastUtil; 10 | import net.minecraft.server.MinecraftServer; 11 | import net.minecraft.server.network.ServerPlayerEntity; 12 | 13 | public class ServerHudManager implements HudManager { 14 | public final HudDataSender lookingHud; 15 | public final HudDataSender playerHudC; 16 | public final HudDataSender playerHudS; 17 | public final SidebarDataSender sidebar; 18 | private GameProfile subscribedProfile; 19 | 20 | public ServerHudManager(MinecraftServer server) { 21 | lookingHud = HudDataSender.createHudDataSenderer(HudType.TARGET, server); 22 | playerHudC = HudDataSender.createHudDataSenderer(HudType.CLIENT_PLAYER, server); 23 | playerHudS = HudDataSender.createHudDataSenderer(HudType.SERVER_PLAYER, server); 24 | sidebar = SidebarDataSender.create(server); 25 | } 26 | 27 | public void setServerPlayerHudTarget(GameProfile gameProfile) { 28 | this.subscribedProfile = gameProfile; 29 | } 30 | 31 | public GameProfile getServerPlayerHudTarget() { 32 | return subscribedProfile; 33 | } 34 | 35 | public void tick(MinecraftServer server) { 36 | List players = server.getPlayerManager().getPlayerList(); 37 | GameProfile subscribed = this.getServerPlayerHudTarget(); 38 | if(!players.isEmpty() && subscribed == null) { 39 | this.setServerPlayerHudTarget(players.get(0).getGameProfile()); 40 | } 41 | 42 | if (this.getServerPlayerHudTarget() != null) { 43 | ServerPlayerEntity player = server.getPlayerManager().getPlayer(this.getServerPlayerHudTarget().getId()); 44 | if(player != null && this.lookingHud != null) { 45 | this.lookingHud.updateData(RaycastUtil.getTargetEntity(player)); 46 | } 47 | 48 | if(player != null && this.playerHudS != null) { 49 | this.playerHudS.updateData(player); 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/rendering/hud/data/DataType.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.rendering.hud.data; 2 | 3 | import com.google.common.collect.ImmutableMap; 4 | 5 | import net.minecraft.entity.EntityPose; 6 | 7 | public enum DataType { 8 | INTEGER{ 9 | @Override 10 | public String getStringOf(Object ob) { 11 | return ((Integer)ob).toString(); 12 | } 13 | }, 14 | FLOAT{ 15 | @Override 16 | public String getStringOf(Object ob) { 17 | return ((Float)ob).toString(); 18 | } 19 | }, 20 | DOUBLE{ 21 | @Override 22 | public String getStringOf(Object ob) { 23 | return ((Double)ob).toString(); 24 | } 25 | }, 26 | STRING{ 27 | @Override 28 | public String getStringOf(Object ob) { 29 | return (String) ob; 30 | } 31 | }, 32 | POSE{ 33 | @Override 34 | public String getStringOf(Object ob) { 35 | return POSE_NAMES.get(ob); 36 | } 37 | }; 38 | 39 | public abstract String getStringOf(Object ob); 40 | private static final ImmutableMap POSE_NAMES = new ImmutableMap.Builder() 41 | .put(EntityPose.CROUCHING, "crouching") 42 | .put(EntityPose.DYING, "dying") 43 | .put(EntityPose.FALL_FLYING, "fall_flying") 44 | .put(EntityPose.SLEEPING, "sleeping") 45 | .put(EntityPose.SPIN_ATTACK, "spin_attack") 46 | .put(EntityPose.STANDING, "standing") 47 | .put(EntityPose.SWIMMING, "swiming") 48 | .build(); 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/rendering/hud/data/HudDataSender.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.rendering.hud.data; 2 | 3 | import java.lang.reflect.Field; 4 | import java.util.Collection; 5 | import java.util.List; 6 | import java.util.stream.Collectors; 7 | 8 | import lovexyn0827.mess.MessMod; 9 | import lovexyn0827.mess.rendering.hud.HudType; 10 | import lovexyn0827.mess.util.ListenedField; 11 | import lovexyn0827.mess.util.Reflection; 12 | import lovexyn0827.mess.util.WrappedPath; 13 | import lovexyn0827.mess.util.access.AccessingPath; 14 | import net.minecraft.entity.Entity; 15 | import net.minecraft.server.MinecraftServer; 16 | 17 | /** 18 | * @author lovexyn0827 19 | * @date 2022/7/14 20 | */ 21 | public interface HudDataSender { 22 | void updateData(Entity entity); 23 | Collection getCustomLines(); 24 | 25 | default boolean hasDuplication(HudLine line) { 26 | return this.getCustomLines().stream().anyMatch((l0) -> { 27 | return l0.getName().equals(line.getName()) || l0.equals(line); 28 | }); 29 | } 30 | 31 | /** 32 | * @implNote Custom lines whose name is the same as the one of the names of in built-in lines and one of the other 33 | * custom lines should be rejected. 34 | */ 35 | default boolean addCustomLine(HudLine line) { 36 | if(this.hasDuplication(line)) { 37 | return false; 38 | } else { 39 | this.getCustomLines().add(line); 40 | return true; 41 | } 42 | } 43 | 44 | default boolean removeCustomLine(String name) { 45 | return this.getCustomLines().removeIf(((line) -> line.getName().equals(name))); 46 | } 47 | 48 | default boolean addField(Class cl, String field) { 49 | return this.addField(cl, field, field, AccessingPath.DUMMY); 50 | } 51 | 52 | default boolean addField(Class cl, String field, String name, AccessingPath path) { 53 | if ("-THIS-".equals(field)) { 54 | return this.addCustomLine(new WrappedPath(path, name)); 55 | } 56 | 57 | Field f = Reflection.getFieldFromNamed(cl, field); 58 | ListenedField lf = new ListenedField(f, path, name); 59 | return this.addCustomLine(lf); 60 | } 61 | 62 | default List getListenedFields() { 63 | return this.getCustomLines().stream() 64 | .map((l) -> (ListenedField) l) 65 | .collect(Collectors.toList()); 66 | } 67 | 68 | public static HudDataSender createHudDataSenderer(HudType type, MinecraftServer server) { 69 | if(MessMod.isDedicatedEnv()) { 70 | return new RemoteHudDataSender(server, type); 71 | } else { 72 | switch(type) { 73 | case TARGET : 74 | case SERVER_PLAYER : 75 | case CLIENT_PLAYER : 76 | return new LocalDefaultHudDataStorage(); 77 | default: 78 | throw new IllegalArgumentException(); 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/rendering/hud/data/HudDataStorage.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.rendering.hud.data; 2 | 3 | import java.util.Iterator; 4 | import java.util.Map.Entry; 5 | import java.util.function.BiConsumer; 6 | 7 | import lovexyn0827.mess.MessMod; 8 | import lovexyn0827.mess.rendering.hud.HudType; 9 | import lovexyn0827.mess.rendering.hud.ServerHudManager; 10 | import net.fabricmc.api.EnvType; 11 | import net.fabricmc.api.Environment; 12 | 13 | /** 14 | * A client-side cache of the data in HUDs 15 | * @author lovexyn0827 16 | * @date 2022/7/14 17 | */ 18 | @Environment(EnvType.CLIENT) 19 | public interface HudDataStorage { 20 | int size(); 21 | Object get(HudLine id); 22 | Iterator> iterator(); 23 | default void forEach(BiConsumer action) { 24 | synchronized (this) { 25 | this.iterator().forEachRemaining((entry) -> action.accept(entry.getKey().getName(), entry.getValue())); 26 | } 27 | } 28 | 29 | // FIXME: Client crashes when connecting to a server without MessMod 30 | static HudDataStorage create(HudType type) { 31 | if(MessMod.isDedicatedEnv()) { 32 | return new RemoteHudDataStorage(); 33 | } else { 34 | ServerHudManager shm = MessMod.INSTANCE.getServerHudManager(); 35 | switch(type) { 36 | case TARGET : 37 | return (HudDataStorage) shm.lookingHud; 38 | case SERVER_PLAYER : 39 | return (HudDataStorage) shm.playerHudS; 40 | case CLIENT_PLAYER : 41 | return (HudDataStorage) shm.playerHudC; 42 | case SIDEBAR : 43 | return (HudDataStorage) shm.sidebar; 44 | } 45 | 46 | throw new AssertionError(); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/rendering/hud/data/HudLine.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.rendering.hud.data; 2 | 3 | import java.util.Objects; 4 | 5 | import org.jetbrains.annotations.NotNull; 6 | import net.minecraft.entity.Entity; 7 | 8 | public interface HudLine { 9 | @NotNull 10 | String getFrom(Entity in); 11 | boolean canGetFrom(Entity entity); 12 | String getName(); 13 | 14 | /** 15 | * Used on remote clients, to represent a custom field. 16 | */ 17 | public static final class Unknown implements HudLine, Comparable { 18 | public final String name; 19 | 20 | Unknown(String name) { 21 | Objects.requireNonNull(name); 22 | this.name = name; 23 | } 24 | 25 | @Override 26 | public int hashCode() { 27 | return name.hashCode(); 28 | } 29 | 30 | @Override 31 | public boolean equals(Object obj) { 32 | if (obj == null) { 33 | return false; 34 | } else { 35 | if(obj.getClass() == Unknown.class) { 36 | Unknown other = (Unknown) obj; 37 | return this.name.equals(other.name); 38 | } else { 39 | return false; 40 | } 41 | } 42 | } 43 | 44 | @Override 45 | public @NotNull String getFrom(Entity in) { 46 | throw new UnsupportedOperationException(); 47 | } 48 | 49 | @Override 50 | public boolean canGetFrom(Entity entity) { 51 | return false; 52 | } 53 | 54 | @Override 55 | public String getName() { 56 | return this.name; 57 | } 58 | 59 | @Override 60 | public int compareTo(HudLine o) { 61 | if(o instanceof BuiltinHudInfo) { 62 | return 1; 63 | } else if(o instanceof Unknown) { 64 | return this.name.compareTo(((Unknown) o).name); 65 | } 66 | 67 | return 0; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/rendering/hud/data/LocalDataStorage.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.rendering.hud.data; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Iterator; 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.Map.Entry; 8 | import java.util.TreeMap; 9 | import java.util.function.BiConsumer; 10 | 11 | import net.fabricmc.api.EnvType; 12 | import net.fabricmc.api.Environment; 13 | import net.minecraft.entity.Entity; 14 | 15 | @Environment(EnvType.CLIENT) 16 | public abstract class LocalDataStorage implements HudDataSender, HudDataStorage { 17 | private Map data = new TreeMap<>(); 18 | private List lines = new ArrayList<>(); 19 | 20 | public LocalDataStorage() { 21 | for(HudLine l : BuiltinHudInfo.values()) { 22 | this.lines.add(l); 23 | } 24 | } 25 | 26 | @Override 27 | public synchronized void updateData(Entity entity) { 28 | this.data.clear(); 29 | if (entity == null) return; 30 | this.lines.forEach((f) -> { 31 | if(f.canGetFrom(entity)) { 32 | this.data.put(f, f.getFrom(entity)); 33 | } 34 | }); 35 | } 36 | 37 | @Override 38 | public List getCustomLines() { 39 | return this.lines; 40 | } 41 | 42 | @Override 43 | public synchronized void forEach(BiConsumer action) { 44 | this.data.forEach((l, d) -> { 45 | action.accept(l.getName(), d); 46 | }); 47 | } 48 | 49 | @Override 50 | @Deprecated 51 | public Iterator> iterator() { 52 | return this.data.entrySet().iterator(); 53 | } 54 | 55 | @Override 56 | public int size() { 57 | return this.data.size(); 58 | } 59 | 60 | @Override 61 | public synchronized Object get(HudLine id) { 62 | return this.data.get(id); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/rendering/hud/data/LocalDefaultHudDataStorage.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.rendering.hud.data; 2 | 3 | import net.fabricmc.api.EnvType; 4 | import net.fabricmc.api.Environment; 5 | 6 | @Environment(EnvType.CLIENT) 7 | public class LocalDefaultHudDataStorage extends LocalDataStorage { 8 | public LocalDefaultHudDataStorage() { 9 | for (HudLine l : BuiltinHudInfo.values()) { 10 | this.addCustomLine(l); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/rendering/hud/data/LocalSidebarDataStorage.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.rendering.hud.data; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Iterator; 5 | import java.util.List; 6 | import java.util.Map.Entry; 7 | 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | import lovexyn0827.mess.util.phase.TickingPhase; 11 | 12 | import java.util.TreeMap; 13 | 14 | import net.fabricmc.api.EnvType; 15 | import net.fabricmc.api.Environment; 16 | import net.minecraft.entity.Entity; 17 | import net.minecraft.world.World; 18 | 19 | @Environment(EnvType.CLIENT) 20 | public class LocalSidebarDataStorage implements SidebarDataSender, HudDataStorage { 21 | private TreeMap data = new TreeMap<>(); 22 | private List lines = new ArrayList<>(); 23 | 24 | public LocalSidebarDataStorage() { 25 | this.registerTickingEvents(); 26 | } 27 | 28 | @Override 29 | public void updateData(Entity entity) { 30 | throw new UnsupportedOperationException(); 31 | } 32 | 33 | @Override 34 | public List getCustomLines() { 35 | return this.lines; 36 | } 37 | 38 | @Override 39 | public int size() { 40 | return this.data.size(); 41 | } 42 | 43 | @Override 44 | public Object get(HudLine id) { 45 | return this.data.get(id); 46 | } 47 | 48 | @Override 49 | public Iterator> iterator() { 50 | return this.data.entrySet().iterator(); 51 | } 52 | 53 | @Override 54 | public synchronized void updateData(TickingPhase phase, @Nullable World world) { 55 | this.data.keySet().removeIf((l) -> !this.lines.contains(l)); 56 | this.lines.forEach((l) -> { 57 | if(l instanceof SidebarLine) { 58 | SidebarLine line = (SidebarLine) l; 59 | if(SidebarDataSender.shouldUpdate(line, phase, world)) { 60 | this.data.put(line, line.get()); 61 | } 62 | } else { 63 | throw new IllegalStateException("Only SidebarLines are permitted"); 64 | } 65 | }); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/rendering/hud/data/RemoteHudDataStorage.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.rendering.hud.data; 2 | 3 | import java.util.Iterator; 4 | import java.util.Map; 5 | import java.util.TreeMap; 6 | import java.util.Map.Entry; 7 | 8 | import net.minecraft.nbt.CompoundTag; 9 | import net.minecraft.nbt.Tag; 10 | 11 | public class RemoteHudDataStorage implements HudDataStorage { 12 | private Map cache = new TreeMap<>(); 13 | 14 | public synchronized void pushData(CompoundTag tag) { 15 | tag.getList("ToRemove", 8).forEach((item) -> this.cache.remove(generateHudLine(item.asString()))); 16 | tag.remove("ToRemove"); 17 | tag.getKeys().forEach((key) -> { 18 | Tag line = tag.get(key); 19 | cache.put(generateHudLine(key), line.asString()); 20 | }); 21 | } 22 | 23 | private static HudLine generateHudLine(String key) { 24 | HudLine lineObj = BuiltinHudInfo.BY_TITLE.get(key); 25 | if(lineObj == null) { 26 | lineObj = new HudLine.Unknown(key); 27 | } 28 | 29 | return lineObj; 30 | } 31 | 32 | @Override 33 | public synchronized int size() { 34 | return this.cache.size(); 35 | } 36 | 37 | @Override 38 | public synchronized Object get(HudLine id) { 39 | return this.cache.get(id); 40 | } 41 | 42 | @Override 43 | public synchronized Iterator> iterator() { 44 | return this.cache.entrySet().iterator(); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/rendering/hud/data/SidebarDataSender.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.rendering.hud.data; 2 | 3 | import java.lang.reflect.Field; 4 | 5 | import org.jetbrains.annotations.Nullable; 6 | 7 | import lovexyn0827.mess.MessMod; 8 | import lovexyn0827.mess.util.ListenedField; 9 | import lovexyn0827.mess.util.Reflection; 10 | import lovexyn0827.mess.util.TranslatableException; 11 | import lovexyn0827.mess.util.WrappedPath; 12 | import lovexyn0827.mess.util.access.AccessingPath; 13 | import lovexyn0827.mess.util.phase.ClientTickingPhase; 14 | import lovexyn0827.mess.util.phase.ServerTickingPhase; 15 | import lovexyn0827.mess.util.phase.TickingPhase; 16 | import net.minecraft.entity.Entity; 17 | import net.minecraft.server.MinecraftServer; 18 | import net.minecraft.server.world.ServerWorld; 19 | import net.minecraft.world.World; 20 | 21 | public interface SidebarDataSender extends HudDataSender { 22 | void updateData(TickingPhase phase, @Nullable World world); 23 | 24 | default void registerTickingEvents() { 25 | ServerTickingPhase.addEventToAll(this::updateData); 26 | ClientTickingPhase.addEventToAll(this::updateData); 27 | } 28 | 29 | static boolean shouldUpdate(SidebarLine line, TickingPhase phase, @Nullable World world) { 30 | World entityWorld = line.entity.world; 31 | return line.updatePhase == phase && line.canGet() && 32 | (entityWorld == world || phase.isNotInAnyWorld() || 33 | entityWorld instanceof ServerWorld && phase instanceof ClientTickingPhase || 34 | !(entityWorld instanceof ServerWorld) && phase instanceof ServerTickingPhase); 35 | } 36 | 37 | static SidebarDataSender create(MinecraftServer server) { 38 | if (MessMod.isDedicatedEnv()) { 39 | return new RemoteHudDataSender.Sidebar(server); 40 | } else { 41 | return new LocalSidebarDataStorage(); 42 | } 43 | } 44 | 45 | default boolean addLine(Entity e, String fieldName, String name, TickingPhase phase, AccessingPath path) { 46 | if ("-THIS-".equals(fieldName)) { 47 | return this.addCustomLine(new SidebarLine(new WrappedPath(path, name), e, phase)); 48 | } 49 | 50 | Field f = Reflection.getFieldFromNamed(e.getClass(), fieldName); 51 | if (f == null) { 52 | throw new TranslatableException("exp.nofield", fieldName, e.getClass().getSimpleName()); 53 | } 54 | 55 | return this.addCustomLine(new SidebarLine(new ListenedField(f, path, name), e, phase)); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/rendering/hud/data/SidebarLine.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.rendering.hud.data; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import lovexyn0827.mess.util.phase.TickingPhase; 6 | import net.minecraft.entity.Entity; 7 | 8 | public final class SidebarLine implements HudLine, Comparable { 9 | private final HudLine backend; 10 | public final Entity entity; 11 | public final TickingPhase updatePhase; 12 | 13 | public SidebarLine(HudLine backend, Entity e, TickingPhase updatePhase) { 14 | this.backend = backend; 15 | this.entity = e; 16 | this.updatePhase = updatePhase; 17 | } 18 | 19 | @Override 20 | public @NotNull String getFrom(Entity in) { 21 | if(in != this.entity) { 22 | throw new IllegalArgumentException(); 23 | } 24 | 25 | return this.backend.getFrom(in); 26 | } 27 | 28 | @Override 29 | public boolean canGetFrom(Entity entity) { 30 | return entity == this.entity && this.backend.canGetFrom(entity); 31 | } 32 | 33 | public Object get() { 34 | return this.backend.getFrom(this.entity); 35 | } 36 | 37 | @Override 38 | public String getName() { 39 | return this.backend.getName(); 40 | } 41 | 42 | @Override 43 | public int compareTo(HudLine o) { 44 | return this.getName().compareTo(o.getName()); 45 | } 46 | 47 | public boolean canGet() { 48 | return this.backend.canGetFrom(this.entity); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/CarpetUtil.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util; 2 | 3 | import java.lang.reflect.Field; 4 | import java.util.function.BooleanSupplier; 5 | 6 | import lovexyn0827.mess.MessMod; 7 | import net.fabricmc.loader.api.FabricLoader; 8 | import net.minecraft.util.Lazy; 9 | 10 | /** 11 | * @author lovexyn0827 12 | * Date: April 10, 2022 13 | */ 14 | public class CarpetUtil { 15 | // FIXME Not working with dedicated servers 16 | private static final Lazy IS_TICK_FROZEN = new Lazy<>(() -> { 17 | if(FabricLoader.getInstance().isModLoaded("carpet")) { 18 | try { 19 | Field f = Class.forName("carpet.helpers.TickSpeed").getField("process_entities"); 20 | return () -> { 21 | try { 22 | return !f.getBoolean(null); 23 | } catch (Exception e) { 24 | MessMod.LOGGER.error("An error occured in getting the process_entities, " 25 | + "but the carpet is installed, something may work wrongly later."); 26 | e.printStackTrace(); 27 | return false; 28 | } 29 | }; 30 | } catch (ClassNotFoundException | IllegalArgumentException | NoSuchFieldException | SecurityException e) { 31 | return () -> false; 32 | } 33 | } else { 34 | return () -> false; 35 | } 36 | }); 37 | 38 | public static boolean isTickFrozen() { 39 | return IS_TICK_FROZEN.get().getAsBoolean(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/FloatPredicate.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util; 2 | 3 | @FunctionalInterface 4 | public interface FloatPredicate { 5 | boolean test(float val); 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/JavaAgent.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.net.URL; 6 | import java.nio.file.Files; 7 | import java.nio.file.Path; 8 | import java.nio.file.Paths; 9 | import java.nio.file.StandardCopyOption; 10 | 11 | public final class JavaAgent { 12 | private final Path path; 13 | 14 | private JavaAgent(Path path) { 15 | this.path = path; 16 | } 17 | 18 | public static JavaAgent download(URL url) { 19 | try (InputStream in = url.openConnection().getInputStream()) { 20 | Path target = Paths.get(String.format("MessModAgent%d.jar", System.currentTimeMillis())); 21 | Files.copy(in, target, StandardCopyOption.REPLACE_EXISTING); 22 | return new JavaAgent(target); 23 | } catch (IOException e) { 24 | e.printStackTrace(); 25 | return null; 26 | } 27 | } 28 | 29 | public static JavaAgent load(Path path) { 30 | return new JavaAgent(path); 31 | } 32 | 33 | public boolean attach() { 34 | try { 35 | Class phClass = Class.forName("java.lang.ProcessHandle"); 36 | Object ph = phClass.getMethod("current").invoke(null); 37 | long pid = (long) phClass.getMethod("pid").invoke(ph); 38 | return this.attach(pid); 39 | } catch (Exception e) { 40 | e.printStackTrace(); 41 | return false; 42 | } 43 | } 44 | 45 | public boolean attach(long pid) { 46 | try { 47 | Class vmClass = Class.forName("com.sun.tools.attach.VirtualMachine"); 48 | Object vmInstance = vmClass.getMethod("attach", String.class).invoke(vmClass, Long.toString(pid)); 49 | vmClass.getMethod("loadAgent", String.class).invoke(vmInstance, this.path.toAbsolutePath().toString()); 50 | return true; 51 | } catch (Exception e) { 52 | e.printStackTrace(); 53 | return false; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/LockedException.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util; 2 | 3 | public final class LockedException extends RuntimeException { 4 | private static final long serialVersionUID = 202307200130L; 5 | } -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/ParameterizedTypeImpl.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util; 2 | 3 | import java.lang.reflect.ParameterizedType; 4 | import java.lang.reflect.Type; 5 | 6 | public class ParameterizedTypeImpl implements ParameterizedType { 7 | private final Type[] actualTypeArguments; 8 | private final Type rawType; 9 | 10 | public ParameterizedTypeImpl(Type rawType, Type ... actualTypeArguments) { 11 | this.actualTypeArguments = actualTypeArguments; 12 | this.rawType = rawType; 13 | } 14 | 15 | @Override 16 | public Type[] getActualTypeArguments() { 17 | return this.actualTypeArguments.clone(); 18 | } 19 | 20 | @Override 21 | public Type getRawType() { 22 | return this.rawType; 23 | } 24 | 25 | @Override 26 | public Type getOwnerType() { 27 | return null; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/RaycastUtil.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util; 2 | 3 | import java.util.Optional; 4 | 5 | import lovexyn0827.mess.fakes.ServerWorldInterface; 6 | import lovexyn0827.mess.options.OptionManager; 7 | import net.minecraft.entity.Entity; 8 | import net.minecraft.server.world.ServerWorld; 9 | import net.minecraft.util.math.Vec3d; 10 | import net.minecraft.world.EntityView; 11 | 12 | public final class RaycastUtil { 13 | public static Entity getTargetEntity(Entity player) { 14 | Vec3d pos = player.getPos().add(0,player.getStandingEyeHeight(),0); 15 | Vec3d direction = player.getRotationVector().multiply(10); 16 | Vec3d max = pos.add(direction); 17 | Entity target = null; 18 | double minDistance = 18; 19 | EntityView world = OptionManager.directChunkAccessForMessMod && player.world instanceof ServerWorld ? 20 | ((ServerWorldInterface) player.world).toNoChunkLoadingWorld() : player.world; 21 | for(Entity entity : world.getEntitiesByClass((Class) Entity.class, 22 | player.getBoundingBox().expand(10), 23 | (e) -> e != player)) { 24 | if(entity.getEntityId() == player.getEntityId()) { 25 | continue; 26 | } 27 | 28 | Optional result = entity.getBoundingBox().raycast(pos, max); 29 | if(result.isPresent()) { 30 | if(result.get().subtract(pos).length() < minDistance) { 31 | target = entity; 32 | max = result.get(); 33 | minDistance = result.get().subtract(pos).length(); 34 | } 35 | } 36 | } 37 | 38 | return target; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/ServerMicroTime.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util; 2 | 3 | import lovexyn0827.mess.MessMod; 4 | import lovexyn0827.mess.util.phase.ServerTickingPhase; 5 | 6 | public class ServerMicroTime { 7 | public final long gameTime; 8 | public final ServerTickingPhase phase; 9 | 10 | public ServerMicroTime(long gameTime, ServerTickingPhase phase) { 11 | this.gameTime = gameTime; 12 | this.phase = phase; 13 | } 14 | 15 | public static ServerMicroTime current() { 16 | return new ServerMicroTime(MessMod.INSTANCE.getGameTime(), ServerTickingPhase.current()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/TranslatableException.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util; 2 | 3 | import lovexyn0827.mess.util.i18n.I18N; 4 | 5 | @SuppressWarnings("serial") 6 | public class TranslatableException extends RuntimeException { 7 | 8 | /** 9 | * The message is translated by default. 10 | * @param msg 11 | */ 12 | public TranslatableException(String msg) { 13 | super(I18N.translate(msg)); 14 | } 15 | 16 | public TranslatableException(String msg, Object ... args) { 17 | super(String.format(I18N.translate(msg), args)); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/access/AccessingFailureException.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util.access; 2 | 3 | import lovexyn0827.mess.util.i18n.I18N; 4 | 5 | public class AccessingFailureException extends Exception { 6 | private static final long serialVersionUID = -4184399838031396060L; 7 | private final String shortenedMsg; 8 | public final FailureCause failureCause; 9 | final Object[] args; 10 | 11 | /** 12 | * Whether or not the node from which the exception arose is specified. 13 | */ 14 | private boolean raw; 15 | 16 | private AccessingFailureException(FailureCause failureCause, Node node, Throwable e, Object ... args) { 17 | super(I18N.translate(failureCause.translationKey, args) 18 | + '(' + "Node#" + (node == null ? '?' : node.ordinary) + ',' 19 | + (node == null ? '?' : node) + ')' , e); 20 | this.shortenedMsg = failureCause.name() + '@' + (node == null ? '?' : node.ordinary); 21 | this.failureCause = failureCause; 22 | this.args = args; 23 | this.raw = false; 24 | } 25 | 26 | static AccessingFailureException create(FailureCause failureCause, Node node) { 27 | return new AccessingFailureException(failureCause, node, null); 28 | } 29 | 30 | static AccessingFailureException create(InvalidLiteralException e, Node node) { 31 | return new AccessingFailureException(e.failureCause, node, e.getCause(), e.args); 32 | } 33 | 34 | static AccessingFailureException create(FailureCause failureCause, Node node, Throwable e) { 35 | return new AccessingFailureException(failureCause, node, e); 36 | } 37 | 38 | static AccessingFailureException createWithArgs(FailureCause failureCause, Node node, Throwable e, Object ... args) { 39 | return new AccessingFailureException(failureCause, node, e, args); 40 | } 41 | 42 | public String getShortenedMsg() { 43 | return this.shortenedMsg; 44 | } 45 | 46 | public boolean isRaw() { 47 | return this.raw; 48 | } 49 | 50 | public AccessingFailureException withNode(Node node) { 51 | return AccessingFailureException.createWithArgs(failureCause, node, this.getCause(), args); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/access/AccessingPath.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util.access; 2 | 3 | import java.lang.reflect.Type; 4 | import java.util.Collections; 5 | import java.util.List; 6 | 7 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 8 | 9 | import lovexyn0827.mess.options.EnumParser; 10 | 11 | /** 12 | * A sequence of {@link Node}, used to get some fields or elements from an object. 13 | * @author lovexyn0827 14 | * Date: April 22, 2022 15 | */ 16 | public interface AccessingPath { 17 | public static final AccessingPath DUMMY = new JavaAccessingPath(Collections.emptyList(), ""); 18 | 19 | Object access(Object start, Type inputType) throws AccessingFailureException; 20 | 21 | /** 22 | * Write a new value to the last node of the path. 23 | * @param value The string representation of the new value, in the form of literals. 24 | * @throws CommandSyntaxException 25 | */ 26 | void write(Object start, Type genericType, String valueStr) 27 | throws AccessingFailureException, CommandSyntaxException; 28 | Type getOutputType(); 29 | Class compile(List> nodeInputTypes, String name) throws CompilationException; 30 | String getOriginalStringRepresentation(); 31 | 32 | public static enum InitializationStrategy { 33 | LEGACY, 34 | STANDARD, 35 | STRICT; 36 | 37 | public static class Parser extends EnumParser { 38 | public Parser() { 39 | super(InitializationStrategy.class); 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/access/AccessingUtils.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util.access; 2 | 3 | @Deprecated 4 | public final class AccessingUtils { 5 | public static Object noop(Object o) { 6 | return o; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/access/ClassCastNode.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util.access; 2 | 3 | import java.lang.reflect.Type; 4 | import java.util.Objects; 5 | 6 | import org.objectweb.asm.Opcodes; 7 | import org.objectweb.asm.tree.InsnList; 8 | import org.objectweb.asm.tree.TypeInsnNode; 9 | 10 | import lovexyn0827.mess.MessMod; 11 | import lovexyn0827.mess.util.TranslatableException; 12 | 13 | public class ClassCastNode extends Node { 14 | private final Class castTo; 15 | 16 | public ClassCastNode(String className) { 17 | try { 18 | String runtimtClassName = MessMod.INSTANCE.getMapping().srgClass(className.replace('/', '.')); 19 | this.castTo = Class.forName(runtimtClassName); 20 | } catch (ClassNotFoundException e) { 21 | TranslatableException e1 = new TranslatableException("exp.noclass", className); 22 | e1.initCause(e); 23 | throw e1; 24 | } 25 | } 26 | 27 | @Override 28 | Object access(Object previous) throws AccessingFailureException { 29 | try { 30 | return this.castTo.cast(previous); 31 | } catch (ClassCastException e) { 32 | throw AccessingFailureException.createWithArgs(FailureCause.CAST, this, e, 33 | previous.getClass().getCanonicalName(), this.castTo.getCanonicalName()); 34 | } 35 | } 36 | 37 | @Override 38 | protected Type resolveOutputType(Type lastOutType) throws AccessingFailureException, InvalidLiteralException { 39 | return this.castTo; 40 | } 41 | 42 | @Override 43 | public int hashCode() { 44 | return Objects.hash(this.castTo); 45 | } 46 | 47 | @Override 48 | public String toString() { 49 | return '(' + this.castTo.getCanonicalName().replace('.', '/') + ')'; 50 | } 51 | 52 | @Override 53 | public boolean equals(Object obj) { 54 | if (this == obj) { 55 | return true; 56 | } 57 | 58 | if (obj == null) { 59 | return false; 60 | } 61 | 62 | if (getClass() != obj.getClass()) { 63 | return false; 64 | } 65 | 66 | ClassCastNode other = (ClassCastNode) obj; 67 | return Objects.equals(this.castTo, other.castTo); 68 | } 69 | 70 | @Override 71 | NodeCompiler getCompiler() { 72 | this.ensureInitialized(); 73 | return (ctx) -> { 74 | InsnList insns = new InsnList(); 75 | insns.add(new TypeInsnNode(Opcodes.CHECKCAST, org.objectweb.asm.Type.getInternalName(this.castTo))); 76 | ctx.endNode(this.castTo); 77 | return insns; 78 | }; 79 | } 80 | 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/access/CompilationException.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util.access; 2 | 3 | import lovexyn0827.mess.util.i18n.I18N; 4 | 5 | public class CompilationException extends Exception { 6 | public CompilationException(String key, Object ... args) { 7 | super(I18N.translate(key, args)); 8 | } 9 | 10 | public CompilationException(FailureCause cause, Object ... args) { 11 | super(I18N.translate(cause.translationKey, args)); 12 | } 13 | 14 | private static final long serialVersionUID = 202306280958L; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/access/FailureCause.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util.access; 2 | 3 | public enum FailureCause { 4 | /** 5 | * Field %s couldn't be found in %s 6 | * Arguments: name of the field, name of the class 7 | */ 8 | NO_FIELD("exp.nofield"), 9 | 10 | /** 11 | * Method %s couldn't be found in %s 12 | */ 13 | NO_METHOD("exp.nomethod"), 14 | 15 | /** 16 | * The value associated with the given key is not found! 17 | */ 18 | NO_KEY("exp.nokey"), 19 | 20 | /** 21 | * Out of bound! 22 | */ 23 | OUT_OF_BOUND("exp.outbound"), 24 | 25 | /** 26 | * A NullPointerException was thrown, possibly because the output of the last node is null. 27 | */ 28 | NULL("exp.null"), 29 | 30 | /** 31 | * Exception in executing method %s: %s 32 | */ 33 | INVOKE_FAIL("exp.failexec"), 34 | 35 | /** 36 | * Properity %s couldn't be gotten from the last node 37 | */ 38 | INV_LAST("exp.invalidlast"), 39 | 40 | /** 41 | * The declaring class of %s couldn't be known 42 | */ 43 | UNCERTAIN_CLASS("exp.unboundedclass"), 44 | 45 | /** 46 | * "Class %s is not found 47 | */ 48 | NO_CLASS("exp.noclass"), 49 | 50 | /** 51 | * "The result of the previous node of %s is not a Map! 52 | */ 53 | NOT_MAP("exp.notmap"), 54 | 55 | /** 56 | * Argument %s is illegal for %s 57 | */ 58 | BAD_ARG("exp.badarg"), 59 | 60 | /** 61 | * Multiple targets were found 62 | */ 63 | MULTI_TARGET("exp.multitarget"), 64 | 65 | /** 66 | * Use # to separate class name and field name, and use / to separate package names, like \"java/lang/FLOAT#MAX_VALUE\" 67 | */ 68 | INV_STATIC("exp.staticl.format"), 69 | 70 | /** 71 | * %s couldn't be casted to %s. 72 | */ 73 | CAST("exp.cast"), 74 | 75 | /** 76 | * Unexpected exception: %s 77 | */ 78 | ERROR("exp.unexc"), 79 | 80 | /** 81 | * Writting is not available. 82 | */ 83 | NOT_WRITTABLE("exp.nowrite"), 84 | 85 | /** 86 | * %s couldn't be set to %s 87 | */ 88 | INV_LAST_W("exp.invalidlastw"); 89 | 90 | public final String translationKey; 91 | 92 | FailureCause(String translationKey) { 93 | this.translationKey = translationKey; 94 | } 95 | } -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/access/InvalidLiteralException.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util.access; 2 | 3 | import lovexyn0827.mess.util.i18n.I18N; 4 | 5 | public class InvalidLiteralException extends Exception { 6 | private static final long serialVersionUID = -4184399838031396061L; 7 | private final String shortenedMsg; 8 | public final FailureCause failureCause; 9 | final Object[] args; 10 | 11 | /** 12 | * Whether or not the node from which the exception arose is specified. 13 | */ 14 | private boolean raw; 15 | 16 | private InvalidLiteralException(FailureCause failureCause, Literal literal, Throwable e, Object ... args) { 17 | super(I18N.translate(failureCause.translationKey, args) 18 | + '(' + "Node#" + '?' + ',' + literal.toString() + ')' , e); 19 | this.shortenedMsg = failureCause.name() + '@' + '?'; 20 | this.failureCause = failureCause; 21 | this.args = args; 22 | this.raw = false; 23 | } 24 | 25 | static InvalidLiteralException create(FailureCause failureCause, Literal literal) { 26 | return new InvalidLiteralException(failureCause, literal, null); 27 | } 28 | 29 | static InvalidLiteralException create(FailureCause failureCause, Literal literal, Throwable e) { 30 | return new InvalidLiteralException(failureCause, literal, e); 31 | } 32 | 33 | static InvalidLiteralException createWithArgs(FailureCause failureCause, Literal literal, Throwable e, Object ... args) { 34 | return new InvalidLiteralException(failureCause, literal, e, args); 35 | } 36 | 37 | public String getShortenedMsg() { 38 | return this.shortenedMsg; 39 | } 40 | 41 | public boolean isRaw() { 42 | return this.raw; 43 | } 44 | 45 | public AccessingFailureException withNode(Node node) { 46 | return AccessingFailureException.createWithArgs(failureCause, node, this.getCause(), args); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/access/LiteralNode.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util.access; 2 | 3 | import java.lang.reflect.Type; 4 | import org.objectweb.asm.Opcodes; 5 | import org.objectweb.asm.tree.InsnList; 6 | import org.objectweb.asm.tree.InsnNode; 7 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 8 | 9 | import lovexyn0827.mess.util.ArgumentListTokenizer; 10 | import lovexyn0827.mess.util.Reflection; 11 | 12 | public class LiteralNode extends Node { 13 | private Literal literal; 14 | 15 | public LiteralNode(String nodeStr) throws CommandSyntaxException { 16 | this.literal = Literal.parse(new ArgumentListTokenizer(nodeStr).next()); 17 | } 18 | 19 | @Override 20 | Object access(Object previous) throws AccessingFailureException { 21 | try { 22 | return this.literal.get(this.outputType); 23 | } catch (InvalidLiteralException e) { 24 | throw AccessingFailureException.create(e, this); 25 | } 26 | } 27 | 28 | @Override 29 | protected Type resolveOutputType(Type lastOutType) throws AccessingFailureException, InvalidLiteralException { 30 | Object ob = this.literal.get(null); 31 | return ob == null ? Object.class : ob.getClass(); 32 | } 33 | 34 | @Override 35 | void initialize(Type lastOutType) throws AccessingFailureException { 36 | try { 37 | this.literal.get(null); 38 | } catch (InvalidLiteralException e) { 39 | throw AccessingFailureException.create(e, this); 40 | } 41 | 42 | super.initialize(lastOutType); 43 | } 44 | 45 | @Override 46 | void uninitialize() { 47 | this.literal = this.literal.recreate(); 48 | } 49 | 50 | @Override 51 | boolean allowsPrimitiveTypes() { 52 | return true; 53 | } 54 | 55 | @Override 56 | NodeCompiler getCompiler() { 57 | return (ctx) -> { 58 | InsnList insns = new InsnList(); 59 | Type lastOut = ctx.getLastOutputType(); 60 | insns.add(new InsnNode(lastOut == double.class || lastOut == long.class ? Opcodes.POP2 : Opcodes.POP)); 61 | BytecodeHelper.appendConstantLoader(ctx, insns, this.literal, 62 | Reflection.getRawType(this.outputType)); 63 | ctx.endNode(this.outputType); 64 | return insns; 65 | }; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/access/NodeCompiler.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util.access; 2 | 3 | import org.objectweb.asm.tree.InsnList; 4 | 5 | interface NodeCompiler { 6 | /** 7 | * Generate a sequence of bytecode performing the operation of a node.
8 | * The element at the top of the operand stack is the output of the last node and should be the output of this node 9 | * after execution. 10 | * Using variables is not permitted. 11 | * @param ctx Context 12 | * @return 13 | */ 14 | InsnList compile(CompilationContext ctx) throws CompilationException; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/access/PathClassLoader.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util.access; 2 | 3 | import lovexyn0827.mess.MessMod; 4 | 5 | class PathClassLoader extends ClassLoader { 6 | public static final PathClassLoader INSTANCE = new PathClassLoader(); 7 | 8 | private PathClassLoader() { 9 | super(MessMod.class.getClassLoader()); 10 | } 11 | 12 | public Class defineClass(String name, byte[] bytes) { 13 | return super.defineClass(name, bytes, 0, bytes.length); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/access/SizeNode.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util.access; 2 | 3 | import java.lang.reflect.Array; 4 | import java.lang.reflect.Type; 5 | import java.util.Collection; 6 | import java.util.Map; 7 | 8 | import org.objectweb.asm.Opcodes; 9 | import org.objectweb.asm.tree.InsnList; 10 | import org.objectweb.asm.tree.InsnNode; 11 | import org.objectweb.asm.tree.MethodInsnNode; 12 | import org.objectweb.asm.tree.TypeInsnNode; 13 | 14 | public class SizeNode extends Node { 15 | @Override 16 | boolean canFollow(Node n) { 17 | Type t = n.outputType; 18 | return t instanceof Class && (((Class) t).isArray() || Collection.class.isAssignableFrom((Class) t)); 19 | } 20 | 21 | @Override 22 | Object access(Object previous) throws AccessingFailureException { 23 | if(previous.getClass().isArray()) { 24 | return Array.getLength(previous); 25 | } else if(previous instanceof Collection) { 26 | Collection c = (Collection) previous; 27 | return c.size(); 28 | } else if(previous instanceof CharSequence) { 29 | return ((CharSequence) previous).length(); 30 | } else if(previous instanceof Map) { 31 | Map m = (Map) previous; 32 | return m.size(); 33 | } else { 34 | throw AccessingFailureException.createWithArgs(FailureCause.INV_LAST, this, null, this); 35 | } 36 | } 37 | 38 | @Override 39 | protected Type resolveOutputType(Type lastOutType) { 40 | return int.class; 41 | } 42 | 43 | @Override 44 | NodeCompiler getCompiler() { 45 | return (ctx) -> { 46 | InsnList insns = new InsnList(); 47 | Class clazz = ctx.getLastOutputClass(); 48 | if(clazz.isArray()) { 49 | insns.add(new InsnNode(Opcodes.ARRAYLENGTH)); 50 | } else if(Collection.class.isAssignableFrom(clazz)) { 51 | insns.add(new TypeInsnNode(Opcodes.CHECKCAST, "java/util/Collection")); 52 | insns.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE, "java/util/Collection", 53 | "size", "()I")); 54 | } else if(CharSequence.class.isAssignableFrom(clazz)) { 55 | insns.add(new TypeInsnNode(Opcodes.CHECKCAST, "java/lang/CharSequence")); 56 | insns.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE, "java/lang/CharSequence", 57 | "length", "()I")); 58 | } else if(Map.class.isAssignableFrom(clazz)) { 59 | insns.add(new TypeInsnNode(Opcodes.CHECKCAST, "java/util/Map")); 60 | insns.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE, "java/util/Map", 61 | "size", "()I")); 62 | } else { 63 | throw new CompilationException(FailureCause.INV_LAST, this); 64 | } 65 | 66 | ctx.endNode(int.class); 67 | return insns; 68 | }; 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/blame/BlamingMode.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util.blame; 2 | 3 | import lovexyn0827.mess.options.EnumParser; 4 | 5 | public enum BlamingMode { 6 | DISABLED, 7 | SIMPLE_TRACE, 8 | DEOBFUSCATED_TRACE, 9 | ANALYZED; 10 | 11 | public static class Parser extends EnumParser { 12 | public Parser() { 13 | super(BlamingMode.class); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/blame/Cause.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util.blame; 2 | 3 | public interface Cause { 4 | String toString(); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/blame/Confidence.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util.blame; 2 | 3 | import lovexyn0827.mess.options.EnumParser; 4 | 5 | public enum Confidence implements Comparable { 6 | IMPOSSIBLE, 7 | /** 8 | * Nearly impossible, but unable to prove. 9 | */ 10 | UNLIKELY, 11 | POSSIBLE, 12 | PROBABLE, 13 | DEFINITE; 14 | 15 | public boolean isAtLeast(Confidence other) { 16 | return this.ordinal() >= other.ordinal(); 17 | } 18 | 19 | public static class Parser extends EnumParser { 20 | public Parser() { 21 | super(Confidence.class); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/blame/StackTraceCause.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util.blame; 2 | 3 | public class StackTraceCause implements Cause { 4 | private StackTrace trace; 5 | 6 | public StackTraceCause(StackTrace stackTrace, boolean map) { 7 | this.trace = map ? stackTrace.mapToNamed() : stackTrace; 8 | } 9 | 10 | @Override 11 | public String toString() { 12 | return this.trace.toString('|'); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/deobfuscating/DummyMapping.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util.deobfuscating; 2 | 3 | class DummyMapping implements Mapping { 4 | 5 | @Override 6 | public String namedClass(String srg) { 7 | return srg; 8 | } 9 | 10 | @Override 11 | public String namedField(String srg) { 12 | return srg; 13 | } 14 | 15 | public String srgClass( String named) { 16 | return named; 17 | } 18 | 19 | @Override 20 | public String srgField(String clazz, String named) { 21 | return named; 22 | } 23 | 24 | @Override 25 | public boolean isClassMapped(Class clazz) { 26 | return false; 27 | } 28 | 29 | @Override 30 | public String namedMethod(String srg, String desc) { 31 | return srg; 32 | } 33 | 34 | @Override 35 | public String srgMethod(String clazz, String named, String desc) { 36 | return named; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/deobfuscating/MethodInfo.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util.deobfuscating; 2 | 3 | public class MethodInfo { 4 | public final String srgName; 5 | public final String name; 6 | 7 | /** 8 | * If class names are contained, their srg names are used 9 | */ 10 | public final String descriptor; 11 | 12 | public MethodInfo(String srgName, String name, String descriptor) { 13 | this.srgName = srgName; 14 | this.name = name; 15 | this.descriptor = descriptor; 16 | 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/i18n/I18N.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util.i18n; 2 | 3 | import com.google.common.collect.ImmutableSet; 4 | 5 | import lovexyn0827.mess.MessMod; 6 | import net.minecraft.client.MinecraftClient; 7 | import net.minecraft.util.crash.CrashException; 8 | import net.minecraft.util.crash.CrashReport; 9 | 10 | /** 11 | * Translation. 12 | * @author lovexyn0827 13 | * Date: April 10, 2022 14 | */ 15 | public class I18N { 16 | /** 17 | * Remember to add the name of the added language to make it present in command suggestions 18 | */ 19 | public static final ImmutableSet SUPPORTED_LANGUAGES = ImmutableSet.builder().add("zh_cn", "en_us").build(); 20 | public static final Language EN_US; 21 | private static Language currentLanguage; 22 | 23 | public static String translate(String translationKey) { 24 | return currentLanguage.translate(translationKey); 25 | } 26 | 27 | public static String translate(String translationKey, Object ... args) { 28 | return String.format(translate(translationKey), args); 29 | } 30 | 31 | public static boolean canUseLanguage(String name, boolean forceLoad) { 32 | if(name == null || "-FOLLOW_SYSTEM_SETTINGS-".equals(name)) { 33 | return true; 34 | } 35 | 36 | if(SUPPORTED_LANGUAGES.contains(name)) { 37 | try { 38 | return forceLoad || new Language(name).vaildate(); 39 | } catch (Exception e) { 40 | return false; 41 | } 42 | } else { 43 | return false; 44 | } 45 | } 46 | 47 | @SuppressWarnings("resource") 48 | public static boolean setLanguage(String name, boolean forceLoad) { 49 | if(name == null || "-FOLLOW_SYSTEM_SETTINGS-".equals(name)) { 50 | forceLoad = true; 51 | if (!MessMod.isDedicatedEnv() && MinecraftClient.getInstance().options != null) { 52 | String sysLang = MinecraftClient.getInstance().options.language; 53 | if (I18N.SUPPORTED_LANGUAGES.contains(sysLang)) { 54 | name = sysLang; 55 | } else { 56 | name = "en_us"; 57 | } 58 | } else { 59 | name = "en_us"; 60 | } 61 | } 62 | 63 | try { 64 | Language lang = new Language(name); 65 | if(forceLoad || lang.vaildate()) { 66 | currentLanguage = lang; 67 | return true; 68 | } else { 69 | return false; 70 | } 71 | } catch (Exception e) { 72 | e.printStackTrace(); 73 | return false; 74 | } 75 | } 76 | 77 | public static Language getCurrentLanguage() { 78 | return currentLanguage; 79 | } 80 | 81 | static { 82 | try { 83 | EN_US = new Language("en_us"); 84 | currentLanguage = EN_US; 85 | } catch (Exception e) { 86 | throw new CrashException(new CrashReport("Couldn't load the default translation.", e)); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/phase/ClientTickingPhase.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util.phase; 2 | 3 | import java.util.List; 4 | 5 | import org.jetbrains.annotations.Nullable; 6 | 7 | import com.google.common.collect.Lists; 8 | import net.minecraft.world.World; 9 | 10 | public enum ClientTickingPhase implements TickingPhase { 11 | CLIENT_TICK_START, 12 | CLIENT_TICK_END; 13 | 14 | private final List events = Lists.newArrayList(); 15 | 16 | @Override 17 | public void begin(@Nullable World world) { 18 | this.triggerEvents(world); 19 | } 20 | 21 | protected synchronized void triggerEvents(@Nullable World world) { 22 | this.events.forEach((e) -> e.trigger(this, world)); 23 | } 24 | 25 | @Override 26 | public synchronized void addEvent(TickingPhase.Event event) { 27 | this.events.add(event); 28 | } 29 | 30 | @Override 31 | public synchronized void removeEvent(TickingPhase.Event event) { 32 | this.events.remove(event); 33 | } 34 | 35 | @Override 36 | public boolean isNotInAnyWorld() { 37 | return true; 38 | } 39 | 40 | public static void addEventToAll(TickingPhase.Event event) { 41 | for(ClientTickingPhase phase : values()) { 42 | phase.addEvent(event); 43 | } 44 | } 45 | 46 | public static void removeAllEvents() { 47 | for(ClientTickingPhase phase : values()) { 48 | phase.events.clear(); 49 | } 50 | } 51 | 52 | public static void removeEventFromAll(TickingPhase.Event event) { 53 | for(ClientTickingPhase phase : values()) { 54 | phase.removeEvent(event); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/phase/ServerTickingPhase.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util.phase; 2 | 3 | import java.util.List; 4 | 5 | import org.jetbrains.annotations.Nullable; 6 | 7 | import com.google.common.collect.Lists; 8 | 9 | import net.minecraft.world.World; 10 | 11 | public enum ServerTickingPhase implements TickingPhase { 12 | WEATHER_CYCLE(false), 13 | CHUNK(false), 14 | SCHEDULED_TICK(false), 15 | VILLAGE(false), 16 | BLOCK_EVENT(false), 17 | ENTITY(false), 18 | TILE_ENTITY(false), 19 | DIM_REST(false), 20 | TICKED_ALL_WORLDS(true), 21 | SERVER_TASKS(true), 22 | REST(true); 23 | 24 | private static ServerTickingPhase current; 25 | private final List events = Lists.newArrayList(); 26 | public final boolean notInAnyWorld; 27 | 28 | private ServerTickingPhase(boolean notInAnyWorld) { 29 | this.notInAnyWorld = notInAnyWorld; 30 | } 31 | 32 | @Override 33 | public void begin(@Nullable World world) { 34 | current = this; 35 | this.triggerEvents(world); 36 | } 37 | 38 | protected synchronized void triggerEvents(@Nullable World world) { 39 | this.events.forEach((e) -> e.trigger(this, world)); 40 | } 41 | 42 | @Override 43 | public synchronized void addEvent(TickingPhase.Event event) { 44 | this.events.add(event); 45 | } 46 | 47 | @Override 48 | public synchronized void removeEvent(TickingPhase.Event event) { 49 | this.events.remove(event); 50 | } 51 | 52 | @Override 53 | public boolean isNotInAnyWorld() { 54 | return this.notInAnyWorld; 55 | } 56 | 57 | public static void addEventToAll(TickingPhase.Event event) { 58 | for(ServerTickingPhase phase : values()) { 59 | phase.addEvent(event); 60 | } 61 | } 62 | 63 | public static void initialize() { 64 | current = null; 65 | for(ServerTickingPhase phase : values()) { 66 | phase.events.clear(); 67 | } 68 | } 69 | 70 | @Nullable 71 | public static ServerTickingPhase current() { 72 | return current; 73 | } 74 | 75 | public static void removeEventFromAll(TickingPhase.Event event) { 76 | for(ServerTickingPhase phase : values()) { 77 | phase.removeEvent(event); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/phase/TickingPhase.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util.phase; 2 | 3 | import org.jetbrains.annotations.Nullable; 4 | 5 | import com.mojang.brigadier.builder.RequiredArgumentBuilder; 6 | 7 | import net.minecraft.server.command.CommandManager; 8 | import net.minecraft.server.command.ServerCommandSource; 9 | import net.minecraft.world.World; 10 | 11 | public interface TickingPhase { 12 | public void begin(@Nullable World world); 13 | public void addEvent(Event event); 14 | public void removeEvent(Event event); 15 | public boolean isNotInAnyWorld(); 16 | 17 | public static RequiredArgumentBuilder commandArg() { 18 | return CommandManager.argument("whereToUpdate", TickingPhaseArgumentType.phaseArg()); 19 | } 20 | 21 | public interface Event { 22 | void trigger(TickingPhase phase, @Nullable World world); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/lovexyn0827/mess/util/phase/TickingPhaseArgumentType.java: -------------------------------------------------------------------------------- 1 | package lovexyn0827.mess.util.phase; 2 | 3 | import java.util.concurrent.CompletableFuture; 4 | 5 | import com.mojang.brigadier.StringReader; 6 | import com.mojang.brigadier.arguments.ArgumentType; 7 | import com.mojang.brigadier.context.CommandContext; 8 | import com.mojang.brigadier.exceptions.CommandSyntaxException; 9 | import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; 10 | import com.mojang.brigadier.suggestion.Suggestions; 11 | import com.mojang.brigadier.suggestion.SuggestionsBuilder; 12 | 13 | import lovexyn0827.mess.MessMod; 14 | import lovexyn0827.mess.util.i18n.I18N; 15 | import net.minecraft.command.argument.ArgumentTypes; 16 | import net.minecraft.command.argument.serialize.ConstantArgumentSerializer; 17 | import net.minecraft.server.command.ServerCommandSource; 18 | 19 | public class TickingPhaseArgumentType implements ArgumentType { 20 | // TODO Use CommandException more. 21 | private static final DynamicCommandExceptionType UNKNOWN_PHASE = new DynamicCommandExceptionType((key) -> { 22 | return () -> I18N.translate("exp.unknownphase", key); 23 | }); 24 | 25 | @Override 26 | public TickingPhase parse(StringReader reader) throws CommandSyntaxException { 27 | String name = reader.readUnquotedString(); 28 | for(ServerTickingPhase p : ServerTickingPhase.values()) { 29 | if(p.name().equals(name)) { 30 | return p; 31 | } 32 | } 33 | 34 | if(!MessMod.isDedicatedEnv()) { 35 | for(ClientTickingPhase p : ClientTickingPhase.values()) { 36 | if(p.name().equals(name)) { 37 | return p; 38 | } 39 | } 40 | } 41 | 42 | throw UNKNOWN_PHASE.create(name); 43 | } 44 | 45 | @Override 46 | public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) { 47 | for(ServerTickingPhase phase : ServerTickingPhase.values()) { 48 | if (phase.name().contains(builder.getRemaining())) { 49 | builder.suggest(phase.name()); 50 | } 51 | } 52 | 53 | if(!MessMod.isDedicatedEnv()) { 54 | for(ClientTickingPhase phase : ClientTickingPhase.values()) { 55 | if (phase.name().contains(builder.getRemaining())) { 56 | builder.suggest(phase.name()); 57 | } 58 | } 59 | } 60 | 61 | return builder.buildFuture(); 62 | } 63 | 64 | public static TickingPhaseArgumentType phaseArg() { 65 | return new TickingPhaseArgumentType(); 66 | } 67 | 68 | public static TickingPhase getPhase(CommandContext ct, String argName) { 69 | return ct.getArgument(argName, TickingPhase.class); 70 | } 71 | 72 | public static void registerArgumentType() { 73 | ArgumentTypes.register("mess_phase", TickingPhaseArgumentType.class, 74 | new ConstantArgumentSerializer(TickingPhaseArgumentType::phaseArg)); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/resources/assets/MessMod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lovexyn0827/MessMod/a1c2d0b4164cef52e73161b924416879041e1b07/src/main/resources/assets/MessMod.png -------------------------------------------------------------------------------- /src/main/resources/assets/lang/zh_cn.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lovexyn0827/MessMod/a1c2d0b4164cef52e73161b924416879041e1b07/src/main/resources/assets/lang/zh_cn.json -------------------------------------------------------------------------------- /src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "messmod", 4 | "version": "${version}", 5 | 6 | "name": "MessMod", 7 | "description": "A minecraft mod that contains many features ranging from world manipulation and information providing to bug fixes and so on, allowing you to take more control of the game, see more information, and do some work easier.", 8 | "icon": "assets/MessMod.png", 9 | "license": "CC-0", 10 | "authors": [ 11 | "lovexyn0827" 12 | ], 13 | "contact": { 14 | "homepage": "https://github.com/lovexyn0827/MessMod" 15 | }, 16 | 17 | "environment": "*", 18 | "entrypoints": { 19 | "main": [ 20 | "lovexyn0827.mess.MessMod::INSTANCE" 21 | ] 22 | }, 23 | "mixins": [ 24 | "messmod.mixins.json" 25 | ], 26 | 27 | "accessWidener" : "messmod.accesswidener", 28 | "depends": { 29 | "fabricloader": ">=0.7.4", 30 | "minecraft": "1.16.x" 31 | }, 32 | 33 | "recommends": { 34 | }, 35 | 36 | "conflicts": { 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/resources/messmod.accesswidener: -------------------------------------------------------------------------------- 1 | accessWidener v1 named 2 | 3 | accessible class net/minecraft/network/NetworkState$PacketHandler 4 | accessible class net/minecraft/server/world/ChunkTicketManager$NearbyChunkTicketUpdater 5 | accessible class net/minecraft/server/world/ServerChunkManager$MainThreadExecutor 6 | accessible class net/minecraft/server/world/ThreadedAnvilChunkStorage$TicketManager --------------------------------------------------------------------------------